Я пытаюсь тихо установить 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);
Но этот код открывает стандартный диалог установки. Как я могу установить приложение без использования root с предоставленным 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
этот класс, вы обнаружите, что initView
является основной установкой, и последнее, что он делает, это вызвать функцию installPackage
:
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);
Но вы сможете получить доступ к этим методам посредством отражения.
Если вас интересует, как installPackage
функция installPackage
, взгляните на PackageManagerService .
Вам нужно будет получить объект менеджера пакетов через getPackageManager()
Context
. Затем вы вызываете функцию installPackage
через отражение.
Я проверил, как ADB устанавливает приложения.
– Он копирует APK в / data / local / tmp
– он запускает оболочку: 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.
Поскольку SecurityException не улавливается AppInstall, и приложение не сбой.
Я пробовал то же самое на корневом устройстве (такое же приложение и AppInstall), и он работал как шарм.
(Также обычно устанавливается, а не в / система или что-то еще)
AppInstall даже не попросил разрешения root.
Но это потому, что оболочка всегда #
вместо $
на этом устройстве.
Кстати, вам нужно root для установки приложения в / system, правильно?
Я попробовал adb remount на неуправляемом устройстве и получил:
remount failed: Operation not permitted.
Вот почему я не мог попробовать / system на не-корневом устройстве.
Вывод: вы должны использовать укорененное устройство
Надеюсь это поможет 🙂
Вы должны определить
<uses-permission android:name="android.permission.INSTALL_PACKAGES" />
В вашем манифесте, тогда, если вы находитесь в системном разделе (/ system / app) или у вас есть приложение, подписанное производителем, у вас будет разрешение INSTALL_PACKAGES.
Мое предложение состоит в том, чтобы создать небольшой проект андроида с 1,5 уровня совместимости, используемый для вызова installPackages через отражение и для экспорта банку с помощью методов для установки пакетов и вызова реальных методов. Затем, импортируя банку в свой проект, вы будете готовы к установке пакетов.
Я понятия не имел, как это сделать, потому что никто не отвечал в то время, и я не нашел документацию об этом разрешении. Поэтому я нашел свое решение. Это хуже, чем ваше, но это решение в любом случае.
Я установил busybox, который установил разрешение 777 / data / app (я не забочусь о безопасности). Затем просто выполните «busybox install» из приложения. Это работает, но имеет большую утечку безопасности. Если вы устанавливаете разрешения 777, root не требуется.
Вот очень хороший пост на эту тему. Это мне очень помогло.
Вы можете просто использовать команду 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(); } } }
Я пробовал на корневом 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(); } } }
Вы можете использовать скрытый 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
в вашем файле манифеста.
Я недавно внедрял установку без согласия пользователя – это приложение для киоска для уровня 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 (однако ПОСЛЕ того, как вы установили приложение для обновления, оно, похоже, работает WITHOUT root)
Для установки в качестве системного приложения я создал подписанный APK и нажал его
adb push updater.apk /sdcard/updater.apk
А затем переместил его в system/priv-app
– для чего требуется перезагрузка FS (поэтому необходим корень)
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
то причине ваше приложение в priv-app
не подхвачено.
Я сделал тестовое приложение для бесшумной установки, используя метод 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
до pm install. Это работает хорошо.
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, на терминале оболочки.