studio - se ha utilizado com google android packageinstaller
Instalar/desinstalar APKs programáticamente(PackageManager vs Intents) (9)
De acuerdo con el código fuente de Froyo, se consulta la clave adicional Intent.EXTRA_INSTALLER_PACKAGE_NAME para obtener el nombre del paquete del instalador en PackageInstallerActivity.
Mi aplicación instala otras aplicaciones y necesita hacer un seguimiento de las aplicaciones que ha instalado. Por supuesto, esto podría lograrse simplemente manteniendo una lista de aplicaciones instaladas. ¡Pero esto no debería ser necesario! Debería ser responsabilidad del PackageManager mantener la relación installedBy (a, b). De hecho, de acuerdo con la API es:
public abstract String getInstallerPackageName (String packageName) - Recupere el nombre del paquete de la aplicación que instaló un paquete. Esto identifica de qué mercado proviene el paquete.
El enfoque actual
Instalar APK usando Intento
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(apkUri, "application/vnd.android.package-archive");
startActivity(intent);
Desinstalar APK usando Intent:
Intent intent = new Intent(Intent.ACTION_DELETE, Uri.fromParts("package",
getPackageManager().getPackageArchiveInfo(apkUri.getPath(), 0).packageName,null));
startActivity(intent);
Esto obviamente no es el camino, por ejemplo, Android Market instala / desinstala paquetes. Usan una versión más rica de PackageManager. Esto puede verse descargando el código fuente de Android desde el repositorio Android Git. A continuación se muestran los dos métodos ocultos que corresponden al enfoque de Intención. Lamentablemente, no están disponibles para desarrolladores externos. ¿Pero quizás estarán en el futuro?
El mejor enfoque
Instalar APK usando el PackageManager
/**
* @hide
*
* Install a package. Since this may take a little while, the result will
* be posted back to the given observer. An installation will fail if the calling context
* lacks the {@link android.Manifest.permission#INSTALL_PACKAGES} permission, if the
* package named in the package file''s manifest is already installed, or if there''s no space
* available on the device.
*
* @param packageURI The location of the package file to install. This can be a ''file:'' or a
* ''content:'' URI.
* @param observer An observer callback to get notified when the package installation is
* complete. {@link IPackageInstallObserver#packageInstalled(String, int)} will be
* called when that happens. observer may be null to indicate that no callback is desired.
* @param flags - possible values: {@link #INSTALL_FORWARD_LOCK},
* {@link #INSTALL_REPLACE_EXISTING}, {@link #INSTALL_ALLOW_TEST}.
* @param installerPackageName Optional package name of the application that is performing the
* installation. This identifies which market the package came from.
*/
public abstract void installPackage(
Uri packageURI, IPackageInstallObserver observer, int flags,
String installerPackageName);
Desinstalar APK usando el PackageManager
/**
* Attempts to delete a package. Since this may take a little while, the result will
* be posted back to the given observer. A deletion will fail if the calling context
* lacks the {@link android.Manifest.permission#DELETE_PACKAGES} permission, if the
* named package cannot be found, or if the named package is a "system package".
* (TODO: include pointer to documentation on "system packages")
*
* @param packageName The name of the package to delete
* @param observer An observer callback to get notified when the package deletion is
* complete. {@link android.content.pm.IPackageDeleteObserver#packageDeleted(boolean)} will be
* called when that happens. observer may be null to indicate that no callback is desired.
* @param flags - possible values: {@link #DONT_DELETE_DATA}
*
* @hide
*/
public abstract void deletePackage(
String packageName, IPackageDeleteObserver observer, int flags);
Diferencias
Al usar intents, el administrador local del paquete no conoce la aplicación de la que se originó la instalación. Específicamente, getInstallerPackageName (...) devuelve null.
El método oculto installPackage (...) toma el nombre del paquete del instalador como parámetro, y es muy posible que establezca este valor.
Pregunta
¿Es posible especificar el nombre del instalador del paquete usando intents? (¿Tal vez el nombre del paquete instalador se puede agregar como un extra al intento de instalación?)
Sugerencia: si desea descargar el código fuente de Android, puede seguir los pasos que se describen a continuación: Descargar el Árbol de fuentes. Para extraer los archivos * .java y colocarlos en carpetas de acuerdo con la jerarquía del paquete, puede consultar esta secuencia de comandos ordenada: Ver Código fuente de Android en Eclipse .
El nivel 14 de la API introdujo dos nuevas acciones: ACTION_INSTALL_PACKAGE y ACTION_UNINSTALL_PACKAGE . Esas acciones le permiten pasar EXTRA_RETURN_RESULT boolean extra para obtener una notificación de resultados de ( EXTRA_RETURN_RESULT ) instalación.
Código de ejemplo para invocar el diálogo de desinstalación:
String app_pkg_name = "com.example.app";
int UNINSTALL_REQUEST_CODE = 1;
Intent intent = new Intent(Intent.ACTION_UNINSTALL_PACKAGE);
intent.setData(Uri.parse("package:" + app_pkg_name));
intent.putExtra(Intent.EXTRA_RETURN_RESULT, true);
startActivityForResult(intent, UNINSTALL_REQUEST_CODE);
Y reciba la notificación en su método Activity#onActivityResult :
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == UNINSTALL_REQUEST_CODE) {
if (resultCode == RESULT_OK) {
Log.d("TAG", "onActivityResult: user accepted the (un)install");
} else if (resultCode == RESULT_CANCELED) {
Log.d("TAG", "onActivityResult: user canceled the (un)install");
} else if (resultCode == RESULT_FIRST_USER) {
Log.d("TAG", "onActivityResult: failed to (un)install");
}
}
}
En un dispositivo rooteado, puede usar:
String pkg = context.getPackageName();
String shellCmd = "rm -r /data/app/" + pkg + "*.apk/n"
+ "rm -r /data/data/" + pkg + "/n"
// TODO remove data on the sd card
+ "sync/n"
+ "reboot/n";
Util.sudo(shellCmd);
Util.sudo()
se define aquí.
Esto no está disponible actualmente para aplicaciones de terceros. Tenga en cuenta que incluso el uso de la reflexión u otros trucos para acceder a installPackage () no ayudará, porque solo las aplicaciones del sistema pueden usarlo. (Esto se debe a que es el mecanismo de instalación de bajo nivel, una vez que el usuario ha aprobado los permisos, por lo que no es seguro que las aplicaciones normales tengan acceso).
Además, los argumentos de la función installPackage () a menudo han cambiado entre las versiones de la plataforma, por lo que todo lo que hagas intentando acceder a él fallará en varias otras versiones de la plataforma.
EDITAR:
También vale la pena señalar que este installerPackage fue agregado recientemente a la plataforma (2.2?) Y originalmente no se usó para rastrear quién instaló la aplicación, sino que la plataforma la utiliza para determinar quién lanzar al informar errores con la aplicación, para implementar Android Feedback. (Esta también fue una de las veces que cambiaron los argumentos del método API.) Durante al menos un largo tiempo después de que se introdujo, Market aún no lo usó para rastrear las aplicaciones que ha instalado (y es posible que todavía no lo use ), pero en su lugar solo usé esto para configurar la aplicación Android Feedback (que estaba separada de Market) como el "propietario" para que se encargue de los comentarios.
La única forma de acceder a esos métodos es a través de la reflexión. Puede obtener un control sobre un objeto PackageManager
llamando a getApplicationContext().getPackageManager()
y usando reflection acceda a estos métodos. Mira this tutorial.
Si está pasando el nombre del paquete como parámetro a cualquiera de sus funciones definidas por el usuario, utilice el siguiente código:
Intent intent=new Intent(Intent.ACTION_DELETE);
intent.setData(Uri.parse("package:"+packageName));
startActivity(intent);
Si está utilizando Kotlin, API 14+, y solo desea mostrar el cuadro de diálogo de desinstalación para su aplicación:
startActivity(Intent(Intent.ACTION_UNINSTALL_PACKAGE).apply {
data = Uri.parse("package:$packageName")
})
Puede cambiar packageName
a cualquier otro nombre de paquete si desea solicitarle al usuario que desinstale otra aplicación en el dispositivo
Si tiene el permiso del propietario del dispositivo (o del propietario del perfil, no lo he intentado), puede instalar / desinstalar silenciosamente paquetes utilizando la API del propietario del dispositivo.
para desinstalar:
public boolean uninstallPackage(Context context, String packageName) {
ComponentName name = new ComponentName(MyAppName, MyDeviceAdminReceiver.class.getCanonicalName());
PackageManager packageManger = context.getPackageManager();
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
PackageInstaller packageInstaller = packageManger.getPackageInstaller();
PackageInstaller.SessionParams params = new PackageInstaller.SessionParams(
PackageInstaller.SessionParams.MODE_FULL_INSTALL);
params.setAppPackageName(packageName);
int sessionId = 0;
try {
sessionId = packageInstaller.createSession(params);
} catch (IOException e) {
e.printStackTrace();
return false;
}
packageInstaller.uninstall(packageName, PendingIntent.getBroadcast(context, sessionId,
new Intent("android.intent.action.MAIN"), 0).getIntentSender());
return true;
}
System.err.println("old sdk");
return false;
}
e instalar paquete:
public boolean installPackage(Context context,
String packageName, String packagePath) {
ComponentName name = new ComponentName(MyAppName, MyDeviceAdminReceiver.class.getCanonicalName());
PackageManager packageManger = context.getPackageManager();
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
PackageInstaller packageInstaller = packageManger.getPackageInstaller();
PackageInstaller.SessionParams params = new PackageInstaller.SessionParams(
PackageInstaller.SessionParams.MODE_FULL_INSTALL);
params.setAppPackageName(packageName);
try {
int sessionId = packageInstaller.createSession(params);
PackageInstaller.Session session = packageInstaller.openSession(sessionId);
OutputStream out = session.openWrite(packageName + ".apk", 0, -1);
readTo(packagePath, out); //read the apk content and write it to out
session.fsync(out);
out.close();
System.out.println("installing...");
session.commit(PendingIntent.getBroadcast(context, sessionId,
new Intent("android.intent.action.MAIN"), 0).getIntentSender());
System.out.println("install request sent");
return true;
} catch (IOException e) {
e.printStackTrace();
return false;
}
}
System.err.println("old sdk");
return false;
}
[Desinstalar]
Qué tal si:
Intent intent = new Intent(Intent.ACTION_DELETE);
intent.setData(Uri.parse("package:com.example.mypackage"));
startActivity(intent);
para la desinstalación Parece más fácil ...