我最近一直在未经用户同意的情况下实施安装 - 这是一个 API 级别 21+ 的信息亭应用程序,我可以完全控制环境。
基本要求是
- API 级别 21+
- root 访问权限以将更新程序安装为系统特权应用程序。
以下方法从 InputStream 读取并安装 APK:
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(这就是需要 root 的原因)
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