Недавно я выполнял установку без согласия пользователя - это было приложение-киоск для API уровня 21+, где я полностью контролировал среду.
Основные требования
- API уровень 21+
- root-доступ для установки программы обновления в качестве системного привилегированного приложения.
Следующий метод читает и устанавливает 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
- что требует перемонтирования 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
по какой-то причине не поднято.