J'essaye d'installer silencieusement apk dans le système. Mon application se trouve dans / system / app et a obtenu l'autorisation "android.permission.INSTALL_PACKAGES"
Cependant, je ne trouve nulle part comment utiliser cette autorisation. J'ai essayé de copier des fichiers dans / data / app et je n'ai pas réussi. J'ai aussi essayé d'utiliser ce code
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(
Uri.parse("file:///sdcard/app.apk"),
"application/vnd.android.package-archive");
startActivity(intent);
Mais ce code ouvre la boîte de dialogue d'installation standard. Comment puis-je installer l'application silencieusement sans root avec accord android.permission.INSTALL_PACKAGES
?
PS J'écris une application qui installera de nombreux apks du dossier dans le système au premier démarrage (remplace l'assistant d'installation). J'en ai besoin pour alléger le firmware.
Si vous pensez que j'écris un virus: Tous les programmes sont installés dans / data / app. L'autorisation Install_packages ne peut être accordée qu'aux programmes de niveau système situés dans / system / app ou signés avec la clé système. Le virus ne peut donc pas y arriver.
Comme dit http://www.mail-archive.com/[email protected]/msg06281.html, les applications PEUVENT être installées silencieusement si elles ont l'autorisation install_packages. De plus, vous n'avez pas besoin de l'autorisation Install_packages pour installer les packages de manière non silencieuse. Plus http://www.androidzoom.com/android_applications/tools/silent-installer_wgqi.html
la source
Réponses:
Votre premier pari est de regarder dans PackageInstaller natif d' Android . Je recommanderais de modifier cette application comme vous le souhaitez ou d'extraire simplement les fonctionnalités requises.
Plus précisément, si vous examinez PackageInstallerActivity et sa méthode
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(); } }
Ensuite, vous remarquerez que le programme d'installation réel se trouve dans la classe InstallAppProgress . En inspectant cette classe, vous découvrirez que
initView
c'est la fonction principale du programme d'installation, et la dernière chose qu'elle fait est d'appelerPackageManager
lainstallPackage
fonction de:public void initView() { ... pm.installPackage(mPackageURI, observer, installFlags, installerPackageName); }
L'étape suivante consiste à inspecter PackageManager , qui est une classe abstraite. Vous y trouverez la
installPackage(...)
fonction. La mauvaise nouvelle est qu'il est marqué @hide. Cela signifie qu'il n'est pas directement disponible (vous ne pourrez pas compiler avec l'appel à cette méthode)./** * @hide * .... */ public abstract void installPackage(Uri packageURI, IPackageInstallObserver observer, int flags,String installerPackageName);
Mais vous pourrez accéder à ces méthodes par réflexion.
Si vous êtes intéressé par la manière dont
PackageManager
lainstallPackage
fonction de est implémentée, jetez un œil à PackageManagerService .Sommaire
Vous aurez besoin d'obtenir l'objet du gestionnaire de paquets via
Context
'sgetPackageManager()
. Ensuite, vous appellerez lainstallPackage
fonction par réflexion.la source
LogCat
les journaux relatifs aux autorisations.J'ai vérifié comment ADB installe les applications.
- Il copie l'APK dans / data / local / tmp
- il exécute 'shell: pm install /data/local/tmp/app.apk'
J'ai essayé de reproduire ce comportement en faisant: (sur PC, en utilisant un câble USB)
adb push app.apk /sdcard/app.apk
adb shell
$ pm install /sdcard/app.apk
Cela fonctionne. L'application est installée.
J'ai créé une application (nommée AppInstall) qui devrait installer l'autre application.
(installé normalement, périphérique non rooté) Oui
:
Runtime.getRuntime().exec("pm install /sdcard/app.apk").waitFor();
Mais cela donne l'erreur:
java.lang.SecurityException: Neither user 10019 nor current process has android.permission.INSTALL_PACKAGES.
il semble que l'erreur soit générée par pm, pas par AppInstall.
Parce que SecurityException n'est pas intercepté par AppInstall et que l'application ne plante pas.
J'ai essayé la même chose sur un appareil enraciné (même application et AppInstall) et cela a fonctionné comme un charme.
(Également normalement installé, pas dans / system ou quoi que ce soit)
AppInstall n'a même pas demandé l'autorisation root.
Mais c'est parce que le shell est toujours
#
au lieu de$
sur cet appareil.Btw, vous avez besoin de root pour installer une application dans / system, n'est-ce pas?
J'ai essayé adb remount sur le périphérique non rooté et j'ai obtenu:
remount failed: Operation not permitted.
C'est pourquoi je n'ai pas pu essayer le truc / system sur le périphérique non rooté.
Conclusion: vous devriez utiliser un appareil enraciné
J'espère que cela aide :)
la source
su
)J'ai récemment mis en œuvre l'installation sans le consentement de l'utilisateur - c'était une application de kiosque pour le niveau d'API 21+ où j'avais un contrôle total sur l'environnement.
Les exigences de base sont
La méthode suivante lit et installe l'APK à partir d'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; }
Le code suivant appelle l'installation
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(); }
pour que tout fonctionne, vous avez désespérément besoin d'une
INSTALL_PACKAGES
autorisation, sinon le code ci-dessus échouera silencieusement<uses-permission android:name="android.permission.INSTALL_PACKAGES" />
pour obtenir cette autorisation, vous devez installer votre APK en tant qu'application système qui REQUIERT root (cependant APRÈS avoir installé votre application de mise à jour, il semble fonctionner SANS root)
Pour l'installer en tant qu'application système, j'ai créé un APK signé et l'ai poussé avec
adb push updater.apk /sdcard/updater.apk
puis déplacé vers
system/priv-app
- ce qui nécessite le remontage de FS (c'est pourquoi la racine est requise)adb shell su mount -o rw,remount /system mv /sdcard/updater.apk /system/priv-app chmod 644 /system/priv-app/updater.apk
pour une raison quelconque, cela ne fonctionnait pas avec la version de débogage simple, mais logcat affiche des informations utiles si votre application
priv-app
n'est pas récupérée pour une raison quelconque.la source
Vous devez définir
<uses-permission android:name="android.permission.INSTALL_PACKAGES" />
dans votre manifeste, alors si vous êtes dans la partition système (/ system / app) ou si votre application est signée par le fabricant, vous allez avoir l'autorisation INSTALL_PACKAGES.
Ma suggestion est de créer un petit projet android avec un niveau de compatibilité 1.5 utilisé pour appeler installPackages via réflexion et d'exporter un fichier jar avec des méthodes pour installer des packages et pour appeler les méthodes réelles. Ensuite, en important le fichier jar dans votre projet, vous serez prêt à installer des packages.
la source
J'ai essayé sur Android 4.2.2 rooté et cette méthode fonctionne pour moi:
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(); } } }
la source
Je n'avais aucune idée de comment faire cela, car personne n'a répondu à ce moment-là, et je n'ai trouvé aucune documentation sur cette autorisation. J'ai donc trouvé ma propre solution. C'est pire que le vôtre, mais c'est quand même une solution.
J'ai installé busybox, qui a défini l'autorisation 777 sur / data / app (je me fiche de la sécurité). Ensuite, il suffit d'exécuter "busybox install" depuis l'application. Cela fonctionne, mais a une grosse fuite de sécurité. Si vous définissez les autorisations 777, aucune racine n'est requise.
la source
Process install; install = Runtime.getRuntime().exec("/system/bin/busybox install " + myAPK.getAbsolutePath()); int iSuccess = install.waitFor();
Vous pouvez utiliser l'API masquée
android.content.pm.IPackageInstallObserver
par réflexion: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(); } } }
Importez
android.content.pm.IPackageInstallObserver
dans votre projet. Votre application doit être système. Vous devez activer l'autorisationandroid.permission.INSTALL_PACKAGES
dans votre fichier manifeste.la source
Vous pouvez simplement utiliser la commande adb install pour installer / mettre à jour l'APK en silence. Un exemple de code est ci-dessous
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(); } } }
la source
Prérequis:
Votre APK doit être signé par le système comme indiqué précédemment. Une façon d'y parvenir consiste à créer vous-même l'image AOSP et à ajouter le code source dans la construction.
Code:
Une fois installé en tant qu'application système, vous pouvez utiliser les méthodes du gestionnaire de packages pour installer et désinstaller un APK comme suit:
Installer:
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; } }
Désinstaller:
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; } }
Pour avoir un rappel une fois que votre APK est installé / désinstallé, vous pouvez utiliser ceci:
/** * 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); }
===> Testé sur Android 8.1 et a bien fonctionné.
la source
J'ai créé une application de test pour les installations silencieuses, en utilisant la méthode PackageManager.installPackage.
J'obtiens la méthode installPackage par réflexion et j'ai créé l'interface android.content.pm.IPackageInstallObserver dans mon dossier src (car il est caché dans le package android.content.pm).
Lorsque j'exécute installPackage, j'ai SecurityException avec une indication de chaîne, que mon application n'a pas de android.permission.INSTALL_PACKAGES, mais qu'il est défini dans AndroidManifest.xml.
Donc, je pense qu'il n'est pas possible d'utiliser cette méthode.
PS. J'ai testé sur Android SDK 2.3 et 4.0. Peut-être que cela fonctionnera avec les versions antérieures.
la source
Essayez ceci
LD_LIBRARY_PATH=/vendor/lib:/system/lib
avant l'installation de pm. Ça marche bien.la source
Une application tierce ne peut pas installer une application Android lentement. Cependant, une application tierce peut demander au système d'exploitation Android d'installer une application.
Vous devez donc définir ceci:
Intent intent = new Intent(Intent.ACTION_VIEW); intent.setDataAndType(Uri.parse("file:///sdcard/app.apk", "application/vnd.android.package-archive"); startActivity(intent);
Vous pouvez également essayer de l'installer en tant qu'application système pour accorder l'autorisation et ignorer cette définition. (Racine requise)
Vous pouvez exécuter la commande suivante sur votre application tierce pour installer une application sur l'appareil enraciné.
Le code est:
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(); } } }
J'espère que cette réponse vous sera utile.
la source
Il est possible de faire une installation silencieuse sur Android 6 et supérieur. En utilisant la fonction fournie dans la réponse de Boris Treukhov, ignorez tout le reste du message, la racine n'est pas non plus requise.
Installez votre application en tant qu'administrateur de l'appareil, vous pouvez avoir le mode kiosque complet avec une installation silencieuse des mises à jour en arrière-plan.
la source
J'ai vérifié toutes les réponses, la conclusion semble être que vous devez d'abord avoir un accès root à l'appareil pour le faire fonctionner.
Mais j'ai trouvé ces articles très utiles. Depuis que je fabrique des appareils "appartenant à l'entreprise".
Comment mettre à jour l'application Android en silence sans interaction de l'utilisateur
Propriétaire d'appareil Android - Application minimale
Voici la documentation de Google sur les "appareils gérés"
Appareil entièrement géré
la source
vous pouvez l'utiliser dans un terminal ou un shell
adb shell install -g MyApp.apk
voir plus dans develope google
la source
! / 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
Cela fonctionne pour moi. Je lance ceci sur ubuntu 12.04, sur le terminal shell.
la source