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 .