Moja aplikacja instaluje inne aplikacje i musi śledzić, jakie aplikacje zainstalowała. Oczywiście można to osiągnąć, po prostu zachowując listę zainstalowanych aplikacji. Ale to nie powinno być konieczne! Za utrzymanie relacji installedBy (a, b) powinien odpowiadać pakiet PackageManager. W rzeczywistości według API jest to:
public abstract String getInstallerPackageName (String nazwa_pakietu) - pobierz nazwę pakietu aplikacji, która zainstalowała pakiet. Pozwala to zidentyfikować rynek, z którego pochodzi pakiet.
Obecne podejście
Zainstaluj APK przy użyciu Intent
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(apkUri, "application/vnd.android.package-archive");
startActivity(intent);
Odinstaluj APK przy użyciu zamiaru:
Intent intent = new Intent(Intent.ACTION_DELETE, Uri.fromParts("package",
getPackageManager().getPackageArchiveInfo(apkUri.getPath(), 0).packageName,null));
startActivity(intent);
Oczywiście nie jest to sposób, w jaki np. Android Market instaluje / odinstalowuje pakiety. Używają bogatszej wersji PackageManager. Można to zobaczyć, pobierając kod źródłowy Androida z repozytorium Android Git. Poniżej znajdują się dwie ukryte metody, które odpowiadają podejściu Intent. Niestety nie są one dostępne dla zewnętrznych programistów. Ale może będą w przyszłości?
Lepsze podejście
Instalowanie APK przy użyciu 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);
Odinstalowywanie APK przy użyciu 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);
Różnice
Podczas używania intencji lokalny menedżer pakietów nie jest informowany, z której aplikacji pochodzi instalacja. W szczególności getInstallerPackageName (...) zwraca null.
Ukryta metoda installPackage (...) przyjmuje nazwę pakietu instalatora jako parametr i najprawdopodobniej jest w stanie ustawić tę wartość.
Pytanie
Czy można określić nazwę instalatora pakietu za pomocą intencji? (Może nazwę pakietu instalatora można dodać jako dodatek do zamiaru instalacji?)
Wskazówka: jeśli chcesz pobrać kod źródłowy Androida, możesz wykonać kroki opisane tutaj: Pobieranie drzewa źródłowego. Aby wyodrębnić pliki * .java i umieścić je w folderach zgodnie z hierarchią pakietów, możesz sprawdzić ten zgrabny skrypt: Wyświetl kod źródłowy Androida w Eclipse .