Пытаюсь незаметно установить apk в систему. Мое приложение находится в / system / app, и ему успешно предоставлено разрешение "android.permission.INSTALL_PACKAGES"
Однако я нигде не могу найти, как использовать это разрешение. Я пытался скопировать файлы в / data / app, но безуспешно. Также я пробовал использовать этот код
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(
Uri.parse("file:///sdcard/app.apk"),
"application/vnd.android.package-archive");
startActivity(intent);
Но этот код открывает стандартный диалог установки. Как я могу установить приложение в автоматическом режиме без рута с предоставленным доступом android.permission.INSTALL_PACKAGES
?
PS Я пишу приложение, которое при первом запуске установит множество apks из папки в систему (замените Мастер установки). Мне это нужно для облегчения прошивки.
Если вы думаете, что я пишу вирус: все программы устанавливаются в / data / app. Разрешение Install_packages может быть предоставлено только программам системного уровня, расположенным в / system / app или подписанным системным ключом. Так что вирус не может попасть туда.
Как сказано, http://www.mail-archive.com/android-porting@googlegroups.com/msg06281.html приложения МОГУТ устанавливаться без вывода сообщений, если у них есть разрешение install_packages. Более того, вам не нужно разрешение Install_packages для установки пакетов не в автоматическом режиме. Плюс http://www.androidzoom.com/android_applications/tools/silent-installer_wgqi.html
источник
Ответы:
Ваша первая ставка - изучить собственный PackageInstaller для Android . Я бы порекомендовал изменить это приложение так, как вам нравится, или просто извлечь необходимые функции.
В частности, если вы посмотрите на PackageInstallerActivity и его метод
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(); } }
Затем вы заметите, что фактический установщик находится в классе InstallAppProgress . Проверка этого класса вы обнаружите , что
initView
является основной функцией инсталлятора, и последнее , что он делает вызовPackageManager
«sinstallPackage
функции:public void initView() { ... pm.installPackage(mPackageURI, observer, installFlags, installerPackageName); }
Следующим шагом является проверка PackageManager , который является абстрактным классом. Вы найдете
installPackage(...)
там функцию. Плохая новость в том, что он отмечен @hide. Это означает, что он недоступен напрямую (вы не сможете выполнить компиляцию с вызовом этого метода)./** * @hide * .... */ public abstract void installPackage(Uri packageURI, IPackageInstallObserver observer, int flags,String installerPackageName);
Но вы сможете получить доступ к этим методам через отражение.
Если вы заинтересованы в том, как
PackageManager
«SinstallPackage
реализована функция, посмотрите на PackageManagerService .Резюме
Вам нужно будет получить объект диспетчера пакетов с помощью
Context
файлаgetPackageManager()
. Затем вы вызоветеinstallPackage
функцию через отражение.источник
LogCat
Журналы, связанные с разрешениями.Я проверил, как ADB устанавливает приложения.
- Он копирует APK в / data / local / tmp
- запускает shell: pm install /data/local/tmp/app.apk
Я попытался воспроизвести это поведение, выполнив: (на ПК, используя USB-кабель)
adb push app.apk /sdcard/app.apk
adb shell
$ pm install /sdcard/app.apk
Это работает. Приложение установлено.
Я создал приложение (названное AppInstall), которое должно установить другое приложение.
(устанавливается нормально, устройство без рута) Да
:
Runtime.getRuntime().exec("pm install /sdcard/app.apk").waitFor();
Но это дает ошибку:
java.lang.SecurityException: Neither user 10019 nor current process has android.permission.INSTALL_PACKAGES.
Кажется, что ошибка выдается pm, а не AppInstall.
Поскольку AppInstall не перехватывает SecurityException, и приложение не аварийно завершает работу.
Я пробовал то же самое на рутированном устройстве (то же приложение и AppInstall), и это сработало как шарм.
(Также обычно устанавливается, не в / system или в чем-то еще)
AppInstall даже не запрашивал права root.
Но это потому, что оболочка всегда находится
#
вместо$
этого устройства.Кстати, вам нужен рут для установки приложения в / system, правильно?
Я попробовал adb remount на некорневом устройстве и получил:
remount failed: Operation not permitted.
Вот почему я не смог попробовать / system на некорневом устройстве.
Вывод: вы должны использовать рутированное устройство.
Надеюсь, это поможет :)
источник
su
)Недавно я реализовал установку без согласия пользователя - это было киоск-приложение для уровня API 21+, где у меня был полный контроль над средой.
Основные требования:
Следующий метод считывает и устанавливает APK из 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; }
Следующий код вызывает установку
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(); }
для того, чтобы все это работало, вам отчаянно нужно
INSTALL_PACKAGES
разрешение, иначе приведенный выше код не сработает.<uses-permission android:name="android.permission.INSTALL_PACKAGES" />
чтобы получить это разрешение, вы должны установить свой APK как системное приложение, которое ТРЕБУЕТ root (однако ПОСЛЕ того, как вы установили приложение для обновления, оно, похоже, работает БЕЗ root)
Чтобы установить как системное приложение, я создал подписанный APK и отправил его с помощью
adb push updater.apk /sdcard/updater.apk
а затем переместил его в
system/priv-app
- что требует перемонтирования ФС (вот почему требуется рут)adb shell su mount -o rw,remount /system mv /sdcard/updater.apk /system/priv-app chmod 644 /system/priv-app/updater.apk
по какой-то причине он не работал с простой версией отладки, но logcat показывает полезную информацию, если ваше приложение
priv-app
по какой-то причине не подхватывается.источник
Вы должны определить
<uses-permission android:name="android.permission.INSTALL_PACKAGES" />
в вашем манифесте, то, если вы находитесь в системном разделе (/ system / app) или у вас есть приложение, подписанное производителем, у вас будет разрешение INSTALL_PACKAGES.
Мое предложение - создать небольшой проект Android с уровнем совместимости 1.5, который используется для вызова installPackages через отражение и для экспорта банки с методами установки пакетов и вызова настоящих методов. Затем, импортировав jar в свой проект, вы будете готовы к установке пакетов.
источник
Я пробовал рутированный Android 4.2.2, и этот метод работает для меня:
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(); } } }
источник
Я понятия не имел, как это сделать, потому что тогда никто не ответил, и я не нашел документации об этом разрешении. Итак, я нашел собственное решение. Хуже твоего, но все равно это выход.
Я установил busybox, который установил разрешение 777 для / data / app (я не забочусь о безопасности). Затем просто выполнил «установку busybox» из приложения. Это работает, но имеет большую утечку безопасности. Если вы установите права доступа 777, рут не требуется.
источник
Process install; install = Runtime.getRuntime().exec("/system/bin/busybox install " + myAPK.getAbsolutePath()); int iSuccess = install.waitFor();
Вы можете использовать скрытый API
android.content.pm.IPackageInstallObserver
путем отражения: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(); } } }
Импортируйте
android.content.pm.IPackageInstallObserver
в свой проект. Ваше приложение должно быть системным. Вы должны активировать разрешениеandroid.permission.INSTALL_PACKAGES
в своем файле манифеста.источник
Вы можете просто использовать команду adb install для автоматической установки / обновления APK. Пример кода ниже
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(); } } }
источник
Предпосылка:
Ваш APK должен быть подписан системой, как правильно указывалось ранее. Один из способов добиться этого - самостоятельно создать образ AOSP и добавить исходный код в сборку.
Код:
После установки в качестве системного приложения вы можете использовать методы диспетчера пакетов для установки и удаления APK следующим образом:
Установить:
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; } }
Удалить:
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; } }
Чтобы получить обратный вызов после установки / удаления APK, вы можете использовать это:
/** * 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); }
===> Проверено на Android 8.1, работает хорошо.
источник
Я сделал тестовое приложение для автоматической установки, используя метод PackageManager.installPackage.
Я получаю метод installPackage через отражение и создал интерфейс android.content.pm.IPackageInstallObserver в моей папке src (потому что он скрыт в пакете android.content.pm).
Когда я запускаю installPackage, я получил SecurityException со строковым указанием, что в моем приложении нет android.permission.INSTALL_PACKAGES, но он определен в AndroidManifest.xml.
Так что, думаю, использовать этот метод невозможно.
PS. Я тестировал Android SDK 2.3 и 4.0. Возможно, он будет работать с более ранними версиями.
источник
Попробуйте это
LD_LIBRARY_PATH=/vendor/lib:/system/lib
перед установкой вечера. Это работает хорошо.источник
Стороннее приложение не может установить приложение для Android незаметно. Однако стороннее приложение может попросить ОС Android установить приложение.
Итак, вы должны определить это:
Intent intent = new Intent(Intent.ACTION_VIEW); intent.setDataAndType(Uri.parse("file:///sdcard/app.apk", "application/vnd.android.package-archive"); startActivity(intent);
Вы также можете попробовать установить его как системное приложение, чтобы предоставить разрешение и игнорировать это определение. (Требуется рут)
Вы можете запустить следующую команду в своем стороннем приложении, чтобы установить приложение на рутированное устройство.
Код такой:
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(); } } }
Надеюсь, этот ответ будет вам полезен.
источник
Возможна автоматическая установка на Android 6 и выше. Используя функцию, предоставленную в ответе Бориса Треухова, игнорируйте все остальное в сообщении, рут также не требуется.
Установите приложение как администратор устройства, вы можете использовать полный режим киоска с автоматической установкой обновлений в фоновом режиме.
источник
Я проверил все ответы и пришел к выводу, что сначала у вас должен быть root-доступ к устройству, чтобы оно работало.
Но потом я нашел эти статьи очень полезными. С тех пор, как делаю "фирменные" устройства.
Как обновить приложение для Android в автоматическом режиме без взаимодействия с пользователем
Владелец устройства Android - минимальное приложение
Вот документация Google об "управляемом устройстве"
Полностью управляемое устройство
источник
вы можете использовать это в терминале или оболочке
adb shell install -g MyApp.apk
увидеть больше в разработке google
источник
! / 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
У меня это работает. Я запускаю это на ubuntu 12.04 на терминале оболочки.
источник