android installation android-5.0-lollipop android-install-apk installation-path

¿Cómo instalar/actualizar/eliminar APK utilizando la clase "PackageInstaller" en Android L?



installation android-5.0-lollipop (7)

El método de instalación que proporcionó @amalBit no funcionó para mí. Es extraño ya que esta es la forma en que se implementa en la muestra de Google .

Esta answer me ayudó a encontrar una solución. Tuve que cambiar algunas partes del código. Aquí está mi implementación:

public static void installPackage(Context context, InputStream inputStream) throws IOException { PackageInstaller packageInstaller = context.getPackageManager().getPackageInstaller(); int sessionId = packageInstaller.createSession(new PackageInstaller .SessionParams(PackageInstaller.SessionParams.MODE_FULL_INSTALL)); PackageInstaller.Session session = packageInstaller.openSession(sessionId); long sizeBytes = 0; OutputStream out = null; out = session.openWrite("my_app_session", 0, sizeBytes); int total = 0; byte[] buffer = new byte[65536]; int c; while ((c = inputStream.read(buffer)) != -1) { total += c; out.write(buffer, 0, c); } session.fsync(out); inputStream.close(); out.close(); // fake intent IntentSender statusReceiver = null; Intent intent = new Intent(context, SomeActivity.class); PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 1337111117, intent, PendingIntent.FLAG_UPDATE_CURRENT); session.commit(pendingIntent.getIntentSender()); session.close(); }

Este método se puede llamar así:

InputStream inputStream = getActivity().getAssets().open("my_awesome_app.apk"); InstallationHelper.installPackage(getActivity(), inputStream);

Por favor verifique la clasificación a continuación y dame la sugerencia de cómo usarlos https://developer.android.com/reference/android/content/pm/PackageInstaller.html https://developer.android.com/reference/android/content/pm/PackageInstaller.Session.html

Por favor, dame un ejemplo para instalar / actualizar / eliminar la aplicación. ¿Es posible que la nueva aplicación se instale en el propietario del perfil del dispositivo?


En Android Api-21 a continuación se encuentra un fragmento de código a través del cual podemos instalar apk en silencio.

private void runInstallWrite() throws IOException, RemoteException { long sizeBytes = -1; String opt; while ((opt = nextOption()) != null) { if (opt.equals("-S")) { sizeBytes = Long.parseLong(nextOptionData()); } else { throw new IllegalArgumentException("Unknown option: " + opt); } } final int sessionId = Integer.parseInt(nextArg()); final String splitName = nextArg(); String path = nextArg(); if ("-".equals(path)) { path = null; } else if (path != null) { final File file = new File(path); if (file.isFile()) { sizeBytes = file.length(); } } final SessionInfo info = mInstaller.getSessionInfo(sessionId); PackageInstaller.Session session = null; InputStream in = null; OutputStream out = null; try { session = new PackageInstaller.Session(mInstaller.openSession(sessionId)); if (path != null) { in = new FileInputStream(path); } else { in = new SizedInputStream(System.in, sizeBytes); } out = session.openWrite(splitName, 0, sizeBytes); int total = 0; byte[] buffer = new byte[65536]; int c; while ((c = in.read(buffer)) != -1) { total += c; out.write(buffer, 0, c); if (info.sizeBytes > 0) { final float fraction = ((float) c / (float) info.sizeBytes); session.addProgress(fraction); } } session.fsync(out); System.out.println("Success: streamed " + total + " bytes"); } finally { IoUtils.closeQuietly(out); IoUtils.closeQuietly(in); IoUtils.closeQuietly(session); } }

El código anterior se ha tomado de Framework here

¿Puedo usar este código con device_owner o usuario normal en LoLiipop?

Respuesta - No, ya que hay apis que han sido @hide tag en marcos de android, aunque PackageManager.Session se introdujo en API 21 pero no podemos usar el nuevo PAckageManager.Session () ya que @hide en API 21.

Si aún desea utilizar este código a través de framework.jar, debe compilar el código fuente de Lolippop y extraer el archivo jar desde out /..../ framework.jar y llamar a apis arriba.


Es posible sin los permisos del sistema de Android M en adelante .

if ((mPm.checkUidPermission(android.Manifest.permission.INSTALL_PACKAGES, installerUid) == PackageManager.PERMISSION_GRANTED) || (installerUid == Process.ROOT_UID) || mIsInstallerDeviceOwner) { mPermissionsAccepted = true; } else { mPermissionsAccepted = false; }

Instalación y desinstalación silenciosa de aplicaciones por el propietario del dispositivo:

Un propietario de dispositivo ahora puede instalar y desinstalar aplicaciones de forma silenciosa utilizando las API PackageInstaller, independientemente de Google Play for Work.

Más en este enlace.

Esto es posible desde Android 6.0 en adelante.

  • Haz de tu aplicación el propietario del dispositivo.

Una vez que su aplicación obtenga el permiso del propietario del dispositivo, podemos instalar, desinstalar y actualizar de forma silenciosa sin la intervención del usuario.

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(); session.commit(createIntentSender(context, sessionId)); return true; } private static IntentSender createIntentSender(Context context, int sessionId) { PendingIntent pendingIntent = PendingIntent.getBroadcast( context, sessionId, new Intent(ACTION_INSTALL_COMPLETE), 0); return pendingIntent.getIntentSender(); }

Desinstalar

String appPackage = "com.your.app.package"; Intent intent = new Intent(getActivity(), getActivity().getClass()); PendingIntent sender = PendingIntent.getActivity(getActivity(), 0, intent, 0); PackageInstaller mPackageInstaller = getActivity().getPackageManager().getPackageInstaller(); mPackageInstaller.uninstall(appPackage, sender.getIntentSender());

Git repo aquí .


Esto también funciona para mí, aunque el propietario de mi dispositivo restringe la instalación de aplicaciones y fuentes desconocidas por parte del usuario. Incluso si ejecuto este ejemplo como administrador de dispositivo, tengo la java.lang.SecurityException: User restriction prevents installing.

openSession está comprobando los permisos. Con esta simple modificación es posible restablecer las restricciones del usuario solo durante una llamada de método corto.

public static DevicePolicyManager getDpm(Context context) { return (DevicePolicyManager)context.getSystemService(Context.DEVICE_POLICY_SERVICE); } public static ComponentName getAdmin(Context context) { return new ComponentName(context, MyDevicePolicyReceiver.class); } public static void addMyRestrictions(Context context) { getDpm(context).addUserRestriction(getAdmin(context), UserManager.DISALLOW_INSTALL_APPS); getDpm(context).addUserRestriction(getAdmin(context), UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES); } public static void clearMyRestrictions(Context context) { getDpm(context).clearUserRestriction(getAdmin(context), UserManager.DISALLOW_INSTALL_APPS); getDpm(context).clearUserRestriction(getAdmin(context), UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES); } public static void installPackage(Context context, InputStream inputStream) throws IOException { PackageInstaller packageInstaller = context.getPackageManager().getPackageInstaller(); int sessionId = packageInstaller.createSession(new PackageInstaller .SessionParams(PackageInstaller.SessionParams.MODE_FULL_INSTALL)); //openSession checks for user restrictions clearMyRestrictions(context); PackageInstaller.Session session = packageInstaller.openSession(sessionId); addMyRestrictions(context); long sizeBytes = 0; OutputStream out = null; out = session.openWrite("my_app_session", 0, sizeBytes); int total = 0; byte[] buffer = new byte[65536]; int c; while ((c = inputStream.read(buffer)) != -1) { total += c; out.write(buffer, 0, c); } session.fsync(out); inputStream.close(); out.close(); // fake intent IntentSender statusReceiver = null; Intent intent = new Intent(context, SomeActivity.class); PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 1337111117, intent, PendingIntent.FLAG_UPDATE_CURRENT); session.commit(pendingIntent.getIntentSender()); session.close(); }

Por favor, tenga cuidado de manejo de excepciones.


INSTALAR:

Intent promptInstall = new Intent(Intent.ACTION_VIEW); promptInstall.setDataAndType(Uri.fromFile(new File(Environment .getExternalStorageDirectory() + "/download/" + APK_NAME)), "application/vnd.android.package-archive"); promptInstall.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); context.startActivity(promptInstall);

DESINSTALAR:

Intent intent = new Intent(Intent.ACTION_DELETE, Uri.fromParts("package", getPackageManager().getPackageArchiveInfo(apkUri.getPath(), 0).packageName,null)); startActivity(intent);


No puede instalar silenciosamente una aplicación de terceros en el usuario recién creado con PackageInstaller.Session.commit() sin "derechos" específicos.
O bien necesitas:

  • el permiso INSTALL_PACKAGES . Pero este permiso no está disponible para aplicaciones de terceros. Así que incluso con la aplicación de propietario de tu perfil, no tendrás este permiso específico.
  • Ejecuta el proceso como ROOT_UID . Lo que significa que tendrás que rootear el dispositivo.

Desde el código fuente de Android :

if ((mPm.checkUidPermission(android.Manifest.permission.INSTALL_PACKAGES, installerUid) == PackageManager.PERMISSION_GRANTED) || (installerUid == Process.ROOT_UID)) { mPermissionsAccepted = true; } else { mPermissionsAccepted = false; }

Si no tiene acceso de root y el permiso INSTALL_PACKAGES , se le pedirá un mensaje al usuario para que le pregunte si confirma los permisos. Esta confirmación se utiliza durante el process de confirmación de la sesión PackageInstaller''s . Obviamente, en este caso, esto no es transparente, ya que el usuario tendrá que confirmar manualmente la instalación de sus aplicaciones.


Simplemente borras tus restricciones

public static DevicePolicyManager getDpm(Context context) { return (DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE); } public static ComponentName getAdmin(Context context) { return new ComponentName(context, MyDevicePolicyReceiver.class); } public static void addMyRestrictions(Context context) { getDpm(context).addUserRestriction(getAdmin(context), UserManager.DISALLOW_INSTALL_APPS); getDpm(context).addUserRestriction(getAdmin(context), UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES); } public static void clearMyRestrictions(Context context) { getDpm(context).clearUserRestriction(getAdmin(context), UserManager.DISALLOW_INSTALL_APPS); getDpm(context).clearUserRestriction(getAdmin(context), UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES); } public static void installPackage(Context context, InputStream inputStream) throws IOException { PackageInstaller packageInstaller = context.getPackageManager().getPackageInstaller(); int sessionId = packageInstaller.createSession(new PackageInstaller .SessionParams(PackageInstaller.SessionParams.MODE_FULL_INSTALL)); //openSession checks for user restrictions clearMyRestrictions(context); PackageInstaller.Session session = packageInstaller.openSession(sessionId); long sizeBytes = 0; OutputStream out = null; out = session.openWrite("my_app_session", 0, sizeBytes); int total = 0; byte[] buffer = new byte[65536]; int c; while ((c = inputStream.read(buffer)) != -1) { total += c; out.write(buffer, 0, c); } session.fsync(out); inputStream.close(); out.close(); // fake intent IntentSender statusReceiver = null; Intent intent = new Intent(context, SomeActivity.class); PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 1337111117, intent, PendingIntent.FLAG_UPDATE_CURRENT); session.commit(pendingIntent.getIntentSender()); session.close(); }