Próbuję po cichu zainstalować apk w systemie. Moja aplikacja znajduje się w katalogu / system / app i pomyślnie przyznano uprawnienie „android.permission.INSTALL_PACKAGES”
Jednak nie mogę nigdzie znaleźć, jak korzystać z tego uprawnienia. Próbowałem skopiować pliki do / data / app i bezskutecznie. Próbowałem też użyć tego kodu
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(
Uri.parse("file:///sdcard/app.apk"),
"application/vnd.android.package-archive");
startActivity(intent);
Ale ten kod otwiera standardowe okno dialogowe instalacji. Jak mogę cicho zainstalować aplikację bez rootowania z przyznanym android.permission.INSTALL_PACKAGES
?
PS Piszę aplikację, która zainstaluje wiele apek z folderu w systemie przy pierwszym uruchomieniu (zastąpienie Kreatora instalacji). Potrzebuję go, aby oprogramowanie układowe było lżejsze.
Jeśli myślisz, że piszę wirusa: wszystkie programy są instalowane w / data / app. Uprawnienie Pakiety_instalacyjne można nadać tylko programom na poziomie systemu znajdującym się w / system / app lub podpisanym kluczem systemowym. Więc wirus nie może się tam dostać.
Jak powiedziano, aplikacje http://www.mail-archive.com/[email protected]/msg06281.html mogą być instalowane w trybie cichym, jeśli mają uprawnienia install_packages. Ponadto nie potrzebujesz uprawnień Install_packages, aby instalować pakiety po cichu. Plus http://www.androidzoom.com/android_applications/tools/silent-installer_wgqi.html
źródło
Odpowiedzi:
Pierwszym zakładem jest przyjrzenie się natywnemu narzędziu PackageInstaller na Androida . Poleciłbym zmodyfikować tę aplikację tak, jak lubisz, lub po prostu wyodrębnić wymaganą funkcjonalność.
W szczególności, jeśli spojrzysz na PackageInstallerActivity i jego metodę
onClickListener
:public void onClick(View v) { if(v == mOk) { // Start subactivity to actually install the application Intent newIntent = new Intent(); ... newIntent.setClass(this, InstallAppProgress.class); ... startActivity(newIntent); finish(); } else if(v == mCancel) { // Cancel and finish finish(); } }
Wtedy zauważysz, że rzeczywisty instalator znajduje się w klasie InstallAppProgress . Sprawdzenie tej klasy przekonasz się, że
initView
jest to funkcja rdzeń instalator, a ostateczna rzeczą robi to wywołaniePackageManager
jestinstallPackage
funkcją:public void initView() { ... pm.installPackage(mPackageURI, observer, installFlags, installerPackageName); }
Następnym krokiem jest sprawdzenie PackageManager , który jest klasą abstrakcyjną. Znajdziesz
installPackage(...)
tam funkcję. Zła wiadomość jest taka, że jest oznaczona @hide. Oznacza to, że nie jest bezpośrednio dostępny (nie będziesz w stanie skompilować się z wywołaniem tej metody)./** * @hide * .... */ public abstract void installPackage(Uri packageURI, IPackageInstallObserver observer, int flags,String installerPackageName);
Ale będziesz mógł uzyskać dostęp do tych metod poprzez refleksję.
Jeśli jesteś zainteresowany w jaki
PackageManager
„sinstallPackage
funkcja jest realizowana, przyjrzeć PackageManagerService .Podsumowanie
Będziesz musiał pobrać obiekt menedżera pakietów za pośrednictwem
Context
plikugetPackageManager()
. Następnie wywołaszinstallPackage
funkcję poprzez odbicie.źródło
LogCat
dzienniki związane z uprawnieniami.Sprawdziłem, jak ADB instaluje aplikacje.
- Kopiuje APK do / data / local / tmp
- uruchamia 'shell: pm install /data/local/tmp/app.apk'
Próbowałem odtworzyć to zachowanie, wykonując: (na komputerze, przy użyciu kabla USB)
adb push app.apk /sdcard/app.apk
adb shell
$ pm install /sdcard/app.apk
To działa. Aplikacja jest zainstalowana.
Zrobiłem aplikację (o nazwie AppInstall), która powinna zainstalować drugą aplikację.
(instalowane normalnie, nierootowane urządzenie)
Tak:
Runtime.getRuntime().exec("pm install /sdcard/app.apk").waitFor();
Ale to powoduje błąd:
java.lang.SecurityException: Neither user 10019 nor current process has android.permission.INSTALL_PACKAGES.
Wygląda na to, że błąd jest generowany przez pm, a nie przez AppInstall.
Ponieważ wyjątek SecurityException nie jest przechwytywany przez AppInstall, a aplikacja nie ulega awarii.
Wypróbowałem to samo na zrootowanym urządzeniu (ta sama aplikacja i AppInstall) i działało jak urok.
(Również normalnie zainstalowany, nie w / system ani nic)
AppInstall nawet nie zapytał o uprawnienia roota.
Ale to dlatego, że powłoka jest zawsze
#
zamiast tego$
na tym urządzeniu.Przy okazji, potrzebujesz roota, aby zainstalować aplikację w / systemie, prawda?
Próbowałem ponownie zamontować adb na nierootowanym urządzeniu i otrzymałem:
remount failed: Operation not permitted.
Dlatego nie mogłem wypróbować rzeczy / system na urządzeniu niezrootowanym.
Wniosek: powinieneś użyć zrootowanego urządzenia
Mam nadzieję, że to pomoże :)
źródło
su
)Od niedawna wdrażam instalację bez zgody użytkownika - była to aplikacja kioskowa dla API poziomu 21+, gdzie miałem pełną kontrolę nad środowiskiem.
Podstawowe wymagania to
Następująca metoda odczytuje i instaluje APK z InputStream:
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(); Intent intent = new Intent(context, MainActivity.class); intent.putExtra("info", "somedata"); // for extra data if needed.. Random generator = new Random(); PendingIntent i = PendingIntent.getActivity(context, generator.nextInt(), intent,PendingIntent.FLAG_UPDATE_CURRENT); session.commit(i.getIntentSender()); return true; }
Poniższy kod wywołuje instalację
try { InputStream is = getResources().openRawResource(R.raw.someapk_source); installPackage(MainActivity.this, is, "com.example.apk"); } catch (IOException e) { Toast.makeText(MainActivity.this, e.getMessage(), Toast.LENGTH_SHORT).show(); }
aby wszystko działało, rozpaczliwie potrzebujesz
INSTALL_PACKAGES
pozwolenia, w przeciwnym razie powyższy kod zawiedzie po cichu<uses-permission android:name="android.permission.INSTALL_PACKAGES" />
aby uzyskać to pozwolenie, musisz zainstalować swój APK jako aplikację systemową, która WYMAGA roota (jednak PO zainstalowaniu aplikacji aktualizującej wydaje się działać BEZ roota)
Aby zainstalować jako aplikację systemową, utworzyłem podpisany plik APK i wysłałem go za pomocą
adb push updater.apk /sdcard/updater.apk
a następnie przeniosłem go do
system/priv-app
- co wymaga ponownego zamontowania FS (dlatego wymagany jest root)adb shell su mount -o rw,remount /system mv /sdcard/updater.apk /system/priv-app chmod 644 /system/priv-app/updater.apk
z jakiegoś powodu nie działało z prostą wersją debugowania, ale logcat pokazuje przydatne informacje, jeśli twoja aplikacja
priv-app
nie została pobrana z jakiegoś powodu.źródło
Powinieneś zdefiniować
<uses-permission android:name="android.permission.INSTALL_PACKAGES" />
w swoim manifeście, jeśli jesteś na partycji systemowej (/ system / app) lub masz aplikację podpisaną przez producenta, będziesz mieć uprawnienie INSTALL_PACKAGES.
Moją sugestią jest stworzenie małego projektu na Androida z poziomem zgodności 1.5 używanym do wywoływania installPackages poprzez odbicie i do wyeksportowania jar z metodami instalowania pakietów i wywoływania prawdziwych metod. Następnie importując jar do swojego projektu, będziesz gotowy do instalacji pakietów.
źródło
Próbowałem na zrootowanym Androidzie 4.2.2 i ta metoda działa dla mnie:
private void installApk(String filename) { File file = new File(filename); if(file.exists()){ try { final String command = "pm install -r " + file.getAbsolutePath(); Process proc = Runtime.getRuntime().exec(new String[] { "su", "-c", command }); proc.waitFor(); } catch (Exception e) { e.printStackTrace(); } } }
źródło
Nie miałem pojęcia, jak to zrobić, bo wtedy nikt nie odpowiedział i nie znalazłem dokumentacji na temat tego zezwolenia. Znalazłem więc własne rozwiązanie. Gorzej niż twoje, ale to i tak jest rozwiązanie.
Zainstalowałem busybox, które ustawiało 777 uprawnienia do / data / app (nie obchodzi mnie bezpieczeństwo). Następnie uruchomiono „instalację busybox” z aplikacji. To działa, ale ma duży wyciek bezpieczeństwa. Jeśli ustawisz uprawnienia 777, nie jest wymagany root.
źródło
Process install; install = Runtime.getRuntime().exec("/system/bin/busybox install " + myAPK.getAbsolutePath()); int iSuccess = install.waitFor();
Możesz użyć ukrytego interfejsu API
android.content.pm.IPackageInstallObserver
przez odbicie:public class PackageManagement { public static final int INSTALL_REPLACE_EXISTING = 0x00000002; public static final int INSTALL_SUCCEEDED = 1; private static Method installPackageMethod; private static Method deletePackageMethod; static { try { installPackageMethod = PackageManager.class.getMethod("installPackage", Uri.class, IPackageInstallObserver.class, Integer.TYPE, String.class); } catch (NoSuchMethodException e) { e.printStackTrace(); } } public static void installPackage(PackageManager pm, Uri mPackageUri, IPackageInstallObserver observer, int installFlags, String installerPackageName) { try { installPackageMethod.invoke(pm, mPackageUri, observer, installFlags, installerPackageName); } catch (Exception e) { e.printStackTrace(); } } }
Importuj
android.content.pm.IPackageInstallObserver
do swojego projektu. Twoja aplikacja musi być systemowa. Musisz aktywować pozwolenieandroid.permission.INSTALL_PACKAGES
w swoim pliku manifestu.źródło
Możesz po prostu użyć polecenia instalacji adb, aby po cichu zainstalować / zaktualizować pakiet APK. Przykładowy kod znajduje się poniżej
public static void InstallAPK(String filename){ File file = new File(filename); if(file.exists()){ try { String command; filename = StringUtil.insertEscape(filename); command = "adb install -r " + filename; Process proc = Runtime.getRuntime().exec(new String[] { "su", "-c", command }); proc.waitFor(); } catch (Exception e) { e.printStackTrace(); } } }
źródło
Warunek wstępny:
Twój plik APK musi być podpisany przez system, jak prawidłowo wskazano wcześniej. Jednym ze sposobów osiągnięcia tego jest samodzielne zbudowanie obrazu AOSP i dodanie kodu źródłowego do kompilacji.
Kod:
Po zainstalowaniu jako aplikacji systemowej możesz użyć metod menedżera pakietów, aby zainstalować i odinstalować pakiet APK w następujący sposób:
Zainstalować:
public boolean install(final String apkPath, final Context context) { Log.d(TAG, "Installing apk at " + apkPath); try { final Uri apkUri = Uri.fromFile(new File(apkPath)); final String installerPackageName = "MyInstaller"; context.getPackageManager().installPackage(apkUri, installObserver, PackageManager.INSTALL_REPLACE_EXISTING, installerPackageName); return true; } catch (Exception e) { e.printStackTrace(); return false; } }
Odinstaluj:
public boolean uninstall(final String packageName, final Context context) { Log.d(TAG, "Uninstalling package " + packageName); try { context.getPackageManager().deletePackage(packageName, deleteObserver, PackageManager.DELETE_ALL_USERS); return true; } catch (Exception e) { e.printStackTrace(); return false; } }
Aby uzyskać oddzwonienie po zainstalowaniu / odinstalowaniu pakietu APK, możesz użyć tego:
/** * Callback after a package was installed be it success or failure. */ private class InstallObserver implements IPackageInstallObserver { @Override public void packageInstalled(String packageName, int returnCode) throws RemoteException { if (packageName != null) { Log.d(TAG, "Successfully installed package " + packageName); callback.onAppInstalled(true, packageName); } else { Log.e(TAG, "Failed to install package."); callback.onAppInstalled(false, null); } } @Override public IBinder asBinder() { return null; } } /** * Callback after a package was deleted be it success or failure. */ private class DeleteObserver implements IPackageDeleteObserver { @Override public void packageDeleted(String packageName, int returnCode) throws RemoteException { if (packageName != null) { Log.d(TAG, "Successfully uninstalled package " + packageName); callback.onAppUninstalled(true, packageName); } else { Log.e(TAG, "Failed to uninstall package."); callback.onAppUninstalled(false, null); } } @Override public IBinder asBinder() { return null; } } /** * Callback to give the flow back to the calling class. */ public interface InstallerCallback { void onAppInstalled(final boolean success, final String packageName); void onAppUninstalled(final boolean success, final String packageName); }
===> Testowany na Androidzie 8.1 i działał dobrze.
źródło
Zrobiłem aplikację testową do cichych instalacji, używając metody PackageManager.installPackage.
Dostaję metodę installPackage poprzez odbicie i utworzyłem interfejs android.content.pm.IPackageInstallObserver w moim folderze src (ponieważ jest ukryty w pakiecie android.content.pm).
Kiedy uruchamiam installPackage, otrzymuję SecurityException ze wskazaniem ciągu, że moja aplikacja nie ma android.permission.INSTALL_PACKAGES, ale jest zdefiniowana w AndroidManifest.xml.
Więc myślę, że nie można użyć tej metody.
PS. Testowałem na Android SDK 2.3 i 4.0. Może zadziała z wcześniejszymi wersjami.
źródło
Spróbuj tego
LD_LIBRARY_PATH=/vendor/lib:/system/lib
przed godziną instalacji. To dobrze działa.źródło
Aplikacja innej firmy nie może szybko zainstalować aplikacji na Androida. Jednak aplikacja innej firmy może poprosić system operacyjny Android o zainstalowanie aplikacji.
Więc powinieneś to zdefiniować:
Intent intent = new Intent(Intent.ACTION_VIEW); intent.setDataAndType(Uri.parse("file:///sdcard/app.apk", "application/vnd.android.package-archive"); startActivity(intent);
Możesz także spróbować zainstalować go jako aplikację systemową, aby przyznać uprawnienia i zignorować to zdefiniowanie. (Wymagany root)
Możesz uruchomić następujące polecenie w aplikacji innej firmy, aby zainstalować aplikację na zrootowanym urządzeniu.
Kod to:
private void installApk(String filename) { File file = new File(filename); if(file.exists()){ try { final String command = "pm install -r " + file.getAbsolutePath(); Process proc = Runtime.getRuntime().exec(new String[] { "su", "-c", command }); proc.waitFor(); } catch (Exception e) { e.printStackTrace(); } } }
Mam nadzieję, że ta odpowiedź jest dla Ciebie pomocna.
źródło
Można przeprowadzić cichą instalację na Androidzie 6 i nowszych. Używając funkcji dostarczonej w odpowiedzi przez Borysa Treuchowa, zignoruj wszystko inne w poście, root również nie jest wymagany.
Zainstaluj aplikację jako administrator urządzenia, możesz mieć pełny tryb kiosku z cichą instalacją aktualizacji w tle.
źródło
Sprawdziłem wszystkie odpowiedzi, wniosek wydaje się być taki, że najpierw musisz mieć uprawnienia roota do urządzenia, aby działało.
Ale potem uznałem te artykuły za bardzo przydatne. Ponieważ tworzę urządzenia „należące do firmy”.
Jak cicho zaktualizować aplikację na Androida bez interakcji z użytkownikiem
Właściciel urządzenia z Androidem - minimalna aplikacja
Oto dokumentacja Google dotycząca „urządzenia zarządzanego”
W pełni zarządzane urządzenie
źródło
możesz użyć tego w terminalu lub powłoce
adb shell install -g MyApp.apk
zobacz więcej w develope google
źródło
! / bin / bash
f=/home/cox/myapp.apk #or $1 if input from terminal. #backup env var backup=$LD_LIBRARY_PATH LD_LIBRARY_PATH=/vendor/lib:/system/lib myTemp=/sdcard/temp.apk adb push $f $myTemp adb shell pm install -r $myTemp #restore env var LD_LIBRARY_PATH=$backup
To działa dla mnie. Uruchamiam to na Ubuntu 12.04, na terminalu powłoki.
źródło