Meu aplicativo instala outros aplicativos e precisa acompanhar quais aplicativos foram instalados. Obviamente, isso pode ser alcançado simplesmente mantendo uma lista de aplicativos instalados. Mas isso não deve ser necessário! Deve ser responsabilidade do PackageManager manter o relacionamento installedBy (a, b). De fato, de acordo com a API, é:
resumo público String getInstallerPackageName (String packageName) - Recupere o nome do pacote do aplicativo que instalou um pacote. Isso identifica de qual mercado o pacote veio.
A abordagem atual
Instale o APK usando Intent
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);
Obviamente, não é esse o caminho, por exemplo, o Android Market instala / desinstala pacotes. Eles usam uma versão mais rica do PackageManager. Isso pode ser visto baixando o código-fonte do Android no repositório do Android Git. Abaixo estão os dois métodos ocultos que correspondem à abordagem Intent. Infelizmente, eles não estão disponíveis para desenvolvedores externos. Mas talvez eles estejam no futuro?
A melhor abordagem
Instalando o APK usando o 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);
Desinstalando o APK usando o 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);
Diferenças
Ao usar intenções, o gerenciador de pacotes local não toma conhecimento de qual aplicativo a instalação se originou. Especificamente, getInstallerPackageName (...) retorna nulo.
O método oculto installPackage (...) usa o nome do pacote do instalador como parâmetro e provavelmente é capaz de definir esse valor.
Questão
É possível especificar o nome do instalador do pacote usando intenções? (Talvez o nome do pacote do instalador possa ser adicionado como um extra à intenção da instalação?)
Dica: Se você deseja fazer o download do código-fonte do Android, siga as etapas descritas aqui: Download da árvore de origem. Para extrair os arquivos * .java e colocá-los em pastas de acordo com a hierarquia de pacotes, você pode conferir este script puro: Exibir código-fonte do Android no Eclipse .
Respostas:
No momento, isso não está disponível para aplicativos de terceiros. Observe que mesmo o uso de reflexão ou outros truques para acessar o installPackage () não ajudará, porque apenas os aplicativos do sistema podem usá-lo. (Isso ocorre porque é o mecanismo de instalação de baixo nível, após as permissões terem sido aprovadas pelo usuário, portanto, não é seguro que aplicativos regulares tenham acesso.)
Além disso, os argumentos da função installPackage () geralmente mudam entre as liberações da plataforma; portanto, qualquer coisa que você tentar acessar, falhará em várias outras versões da plataforma.
EDITAR:
Além disso, vale ressaltar que este installerPackage foi adicionado recentemente à plataforma (2.2?) E não foi originalmente usado para rastrear quem instalou o aplicativo - ele é usado pela plataforma para determinar quem iniciar ao relatar erros com o aplicativo, para implementar o Feedback do Android. (Essa também foi uma das vezes em que os argumentos do método API foram alterados.) Por pelo menos um longo tempo após a introdução, o Market ainda não o utilizava para rastrear os aplicativos instalados (e pode muito bem ainda não usá-lo). ), mas apenas usou isso para definir o aplicativo Android Feedback (separado do Market) como o "proprietário" para cuidar dos comentários.
fonte
O Android P + requer esta permissão no AndroidManifest.xml
Então:
desinstalar. Parece mais fácil ...
fonte
onDestroy()
método?O nível 14 da API introduziu duas novas ações: ACTION_INSTALL_PACKAGE e ACTION_UNINSTALL_PACKAGE . Essas ações permitem que você passe EXTRA_RETURN_RESULT boolean extra para obter uma notificação de resultado da (des) instalação.
Código de exemplo para chamar a caixa de diálogo de desinstalação:
E receba a notificação no seu método Activity # onActivityResult :
fonte
ACTION_INSTALL_PACKAGE
exigirá aREQUEST_INSTALL_PACKAGES
permissão no nível da assinatura . Da mesma forma, a partir da API 28 (Android P), a chamadaACTION_UNINSTALL_PACKAGE
exigirá aREQUEST_DELETE_PACKAGES
permissão não perigosa . Pelo menos de acordo com os documentos.Se você tiver permissão de proprietário do dispositivo (ou proprietário do perfil, não tentei), poderá instalar / desinstalar silenciosamente pacotes usando a API do proprietário do dispositivo.
para desinstalar:
e para instalar o pacote:
fonte
A única maneira de acessar esses métodos é através da reflexão. Você pode controlar um
PackageManager
objeto chamandogetApplicationContext().getPackageManager()
e usando o reflexo para acessar esses métodos. Verificação geral este tutorial.fonte
De acordo com o código fonte do Froyo, a chave extra Intent.EXTRA_INSTALLER_PACKAGE_NAME é consultada para obter o nome do pacote do instalador em PackageInstallerActivity.
fonte
Em um dispositivo raiz, você pode usar:
Util.sudo()
é definido aqui.fonte
Se você estiver passando o nome do pacote como parâmetro para qualquer função definida pelo usuário, use o código abaixo:
fonte
Se você estiver usando o Kotlin, API 14+, e apenas desejar mostrar a caixa de diálogo de desinstalação do seu aplicativo:
Você pode mudar
packageName
para qualquer outro nome de pacote se desejar solicitar ao usuário que desinstale outro aplicativo no dispositivofonte
Pré-requisito:
Seu APK precisa ser assinado pelo sistema, conforme indicado corretamente anteriormente. Uma maneira de conseguir isso é criar a imagem AOSP e adicionar o código-fonte na compilação.
Código:
Depois de instalado como um aplicativo do sistema, você pode usar os métodos do gerenciador de pacotes para instalar e desinstalar um APK da seguinte maneira:
Instalar:
Desinstalar:
Para receber um retorno de chamada assim que seu APK for instalado / desinstalado, você pode usar o seguinte:
fonte