Instalar aplicaciones en silencio, con el permiso INSTALL_PACKAGES concedido
Estoy tratando de instalar silenciosamente apk en el sistema. Mi aplicación se encuentra en / system / app y se ha concedido permiso correctamente "android.permission.INSTALL_PACKAGES"
Sin embargo, no puedo encontrar en ningún lugar cómo utilizar este permiso. Traté de copiar archivos a / data / app y no tuvo éxito. También he intentado usar este código
- Cordova no instala realmente la aplicación en el dispositivo Android
- Dispositivos Fastboot para Android que no devuelven el dispositivo
- Android APK instala varios iconos / actividades?
- Anular el registro del cliente android desde el servidor de empuje unificado aerogear
- ¿Por qué falla Adb con el error ?
Intent intent = new Intent(Intent.ACTION_VIEW); intent.setDataAndType( Uri.parse("file:///sdcard/app.apk"), "application/vnd.android.package-archive"); startActivity(intent);
Pero este código abre diálogo de instalación estándar. ¿Cómo puedo instalar la aplicación en silencio sin root con android.permission.INSTALL_PACKAGES
concedido?
PS Estoy escribiendo una aplicación que instalará muchos apks de la carpeta en el sistema en el primer inicio (reemplace el asistente de configuración). Lo necesito para hacer el firmware más ligero.
Si piensa que estoy escribiendo un virus: Todos los programas están instalados en / data / app. Permiso Los paquetes_instalación sólo se pueden conceder a los programas de nivel de sistema ubicados en / system / app o firmados con la clave del sistema. Así que el virus no puede llegar allí.
Como se ha dicho http://www.mail-archive.com/[email protected]/msg06281.html las aplicaciones PUEDEN ser instaladas en silencio si tienen permiso de install_packages. Además, no necesita el permiso Install_packages para instalar los paquetes de forma silenciosa. Más http://www.androidzoom.com/android_applications/tools/silent-installer_wgqi.html
- Error de instalación de ADB con INSTALL_FAILED_TEST_ONLY
- Instalar MonoDevelop / Xamarin studio 4.0.8 Gtk # versión 2.12.16
- Fallo del protocolo adb utilizando install and push
- Error de Android: No se pudo instalar * .apk en el dispositivo *: timeout
- La tarea "instalar" de plugin de Gradle Maven no funciona con el proyecto de la biblioteca de Android
- Obtener la lista de aplicaciones de Android instaladas
- Instalar la aplicación de forma programática desde la fuente de Android
- Problema de instalación de Android SDK
Su primera apuesta es mirar en PackageInstaller nativo de Android. Yo recomendaría modificar la aplicación de la forma que desee, o simplemente extraer la funcionalidad necesaria.
Específicamente, si observa PackageInstallerActivity y su método onClickListener
:
public void onClick(View v) { if(v == mOk) { // Start subactivity to actually install the application Intent newIntent = new Intent(); ... newIntent.setClass(this, InstallAppProgress.class); ... startActivity(newIntent); finish(); } else if(v == mCancel) { // Cancel and finish finish(); } }
Entonces notará que el instalador real se encuentra en la clase InstallAppProgress . Inspeccionando esa clase encontrarás que initView
es la función de instalador central, y lo último que hace es llamar a la función installPackage
PackageManager
:
public void initView() { ... pm.installPackage(mPackageURI, observer, installFlags, installerPackageName); }
El siguiente paso es inspeccionar PackageManager , que es clase abstracta. Encontrarás installPackage(...)
allí. La mala noticia es que está marcada con @hide. Esto significa que no está disponible directamente (no podrá compilar con la llamada a este método).
/** * @hide * .... */ public abstract void installPackage(Uri packageURI, IPackageInstallObserver observer, int flags,String installerPackageName);
Pero podrá acceder a estos métodos a través de la reflexión.
Si está interesado en cómo se implementa la función installPackage
PackageManager
, eche un vistazo a PackageManagerService .
Resumen
Tendrá que obtener el objeto del gestor de paquetes a través de getPackageManager()
Context
. A continuación, llamará a la función installPackage
mediante la reflexión.
He comprobado cómo ADB instala aplicaciones.
– Copia el APK a / data / local / tmp
– ejecuta 'shell: pm install /data/local/tmp/app.apk'
He intentado replicar este comportamiento haciendo: (en pc, usando el usb-cable)
adb push app.apk /sdcard/app.apk
adb shell
$ pm install /sdcard/app.apk
Esto funciona. La aplicación está instalada.
Hice una aplicación (llamada AppInstall) que debería instalar la otra aplicación.
(Instalado normalmente, dispositivo no enraizado)
Lo hace:
Runtime.getRuntime().exec("pm install /sdcard/app.apk").waitFor();
Pero esto da el error:
java.lang.SecurityException: Neither user 10019 nor current process has android.permission.INSTALL_PACKAGES.
Parece que el error es lanzado por pm, no por AppInstall.
Debido a que la excepción de seguridad no se captura por AppInstall y la aplicación no se bloquea.
He intentado lo mismo en un dispositivo con raíz (la misma aplicación y AppInstall) y funcionó como un encanto.
(También se instala normalmente, no en / system o nada)
AppInstall ni siquiera pidió permiso de root.
Pero eso es porque el shell siempre es #
lugar de $
en ese dispositivo.
Por cierto, necesita root para instalar una aplicación en / system, correcto?
He intentado remontar adb en el dispositivo no arraigado y tiene:
remount failed: Operation not permitted.
Por eso no pude probar la cosa / system en el dispositivo no enraizado.
Conclusión: debe utilizar un dispositivo enraizado
Espero que esto ayude 🙂
Debe definir
<uses-permission android:name="android.permission.INSTALL_PACKAGES" />
En su manifiesto, entonces si si está en la partición del sistema (/ system / app) o tiene su aplicación firmada por el fabricante, va a tener el permiso de INSTALL_PACKAGES.
Mi sugerencia es crear un pequeño proyecto androide con nivel de compatibilidad 1.5 utilizado para llamar a installPackages a través de la reflexión y para exportar un jar con métodos para instalar paquetes y llamar a los métodos reales. Luego, al importar el frasco en su proyecto, estará listo para instalar paquetes.
No tenía ni idea de cómo hacer esto, porque nadie respondió a esa hora, y no encontré documentación sobre este permiso. Así que encontré mi propia solución. Es worser que el suyo, pero esto es una solución de todos modos.
He instalado busybox, que establece 777 permiso para / data / app (no me importa la seguridad). A continuación, acaba de ejecutar "busybox install" de la aplicación. Esto funciona, pero tiene una gran fuga de seguridad. Si establece permisos 777, no se necesita root.
Aquí hay un post muy agradable sobre este tema. Me ayudó mucho.
Simplemente puede usar el comando adb install para instalar / actualizar APK en silencio. El código de ejemplo está por debajo
public static void InstallAPK(String filename){ File file = new File(filename); if(file.exists()){ try { String command; filename = StringUtil.insertEscape(filename); command = "adb install -r " + filename; Process proc = Runtime.getRuntime().exec(new String[] { "su", "-c", command }); proc.waitFor(); } catch (Exception e) { e.printStackTrace(); } } }
He probado en arraigada Android 4.2.2 y este método funciona para mí:
private void installApk(String filename) { File file = new File(filename); if(file.exists()){ try { final String command = "pm install -r " + file.getAbsolutePath(); Process proc = Runtime.getRuntime().exec(new String[] { "su", "-c", command }); proc.waitFor(); } catch (Exception e) { e.printStackTrace(); } } }
Puede usar la API oculta android.content.pm.IPackageInstallObserver
por reflexión:
public class PackageManagement { public static final int INSTALL_REPLACE_EXISTING = 0x00000002; public static final int INSTALL_SUCCEEDED = 1; private static Method installPackageMethod; private static Method deletePackageMethod; static { try { installPackageMethod = PackageManager.class.getMethod("installPackage", Uri.class, IPackageInstallObserver.class, Integer.TYPE, String.class); } catch (NoSuchMethodException e) { e.printStackTrace(); } } public static void installPackage(PackageManager pm, Uri mPackageUri, IPackageInstallObserver observer, int installFlags, String installerPackageName) { try { installPackageMethod.invoke(pm, mPackageUri, observer, installFlags, installerPackageName); } catch (Exception e) { e.printStackTrace(); } } }
Importe android.content.pm.IPackageInstallObserver
en su proyecto. Su aplicación debe ser el sistema. Debe activar el permiso android.permission.INSTALL_PACKAGES
en el archivo de manifiesto.
He estado implementando la instalación sin el consentimiento del usuario recientemente – era una aplicación de kiosco para el nivel de la API 21 + donde tenía control total sobre el medio ambiente.
Los requisitos básicos son:
- Nivel de API 21+
- Root para instalar el actualizador como una aplicación privilegiada del sistema.
El siguiente método lee e instala APK de InputStream:
public static boolean installPackage(Context context, InputStream in, String packageName) throws IOException { PackageInstaller packageInstaller = context.getPackageManager().getPackageInstaller(); PackageInstaller.SessionParams params = new PackageInstaller.SessionParams( PackageInstaller.SessionParams.MODE_FULL_INSTALL); params.setAppPackageName(packageName); // set params int sessionId = packageInstaller.createSession(params); PackageInstaller.Session session = packageInstaller.openSession(sessionId); OutputStream out = session.openWrite("COSU", 0, -1); byte[] buffer = new byte[65536]; int c; while ((c = in.read(buffer)) != -1) { out.write(buffer, 0, c); } session.fsync(out); in.close(); out.close(); Intent intent = new Intent(context, MainActivity.class); intent.putExtra("info", "somedata"); // for extra data if needed.. Random generator = new Random(); PendingIntent i = PendingIntent.getActivity(context, generator.nextInt(), intent,PendingIntent.FLAG_UPDATE_CURRENT); session.commit(i.getIntentSender()); return true; }
El código siguiente llama a la instalación
try { InputStream is = getResources().openRawResource(R.raw.someapk_source); installPackage(MainActivity.this, is, "com.example.apk"); } catch (IOException e) { Toast.makeText(MainActivity.this, e.getMessage(), Toast.LENGTH_SHORT).show(); }
Para que todo funcione necesitas desesperadamente permiso de INSTALL_PACKAGES
, o el código anterior fallará silenciosamente
<uses-permission android:name="android.permission.INSTALL_PACKAGES" />
Para obtener este permiso debe instalar su APK como aplicación del sistema que REQUIERE root (sin embargo, después de haber instalado su aplicación de actualización que parecen trabajar sin raíz)
Para instalar como aplicación del sistema, creé un APK firmado y lo empujé con
adb push updater.apk /sdcard/updater.apk
Y luego se trasladó a system/priv-app
– que requiere volver a montar FS (es por eso que la raíz es necesario)
adb shell su mount -o rw,remount /system mv /sdcard/updater.apk /system/priv-app chmod 644 /system/priv-app/updater.apk
Por alguna razón no funcionó con la versión de depuración simple, pero logcat muestra información útil si su aplicación en priv-app
no es recogido por alguna razón.
Hice una aplicación de prueba para instalaciones silenciosas, utilizando el método PackageManager.installPackage.
Consigo el método del installPackage con la reflexión, e hice la interfaz de android.content.pm.IPackageInstallObserver en mi carpeta del src (porque está ocultada en el paquete de android.content.pm).
Cuando ejecuto installPackage, tengo SecurityException con indicación de cadena, que mi aplicación no tiene android.permission.INSTALL_PACKAGES, pero se definió en AndroidManifest.xml.
Por lo tanto, creo, no es posible utilizar este método.
PD. He probado en Android SDK 2.3 y 4.0. Tal vez funcionará con las versiones anteriores.
Intente esto LD_LIBRARY_PATH=/vendor/lib:/system/lib
antes de pm install. Funciona bien.
! / Bin / bash
f=/home/cox/myapp.apk #or $1 if input from terminal. #backup env var backup=$LD_LIBRARY_PATH LD_LIBRARY_PATH=/vendor/lib:/system/lib myTemp=/sdcard/temp.apk adb push $f $myTemp adb shell pm install -r $myTemp #restore env var LD_LIBRARY_PATH=$backup
Esto funciona para mí. Funciono esto en ubuntu 12.04, en terminal de la cáscara.