android - 使用 INSTALL_PACKAGES 将 APK 安装为系统应用
问题描述
我开发了一个以系统权限运行的应用程序(它内置于 AOSP 的映像中)并具有 INSTALL_PACKAGES 权限。
我的目标是在后台静默安装 APK,无需用户交互。我在 stackoverflow 上阅读了不同的方法,但其中大多数要么已经过时,要么根本不起作用。
例如,如果我尝试使用 PackageManager(通过反射或通过在我的应用程序中作为 shell 命令运行),我会收到以下错误,这就是我目前卡住的地方。
11-20 19:06:10.999 4965 4965 D AndroidRuntime: >>>>>> START
com.android.internal.os.RuntimeInit uid 10039 <<<<<<
11-20 19:06:11.199 4965 4965 D AndroidRuntime: Calling main entry com.android.commands.pm.Pm
11-20 19:06:11.268 4965 4965 E Pm : Error
11-20 19:06:11.268 4965 4965 E Pm : java.lang.NullPointerException: Attempt to invoke virtual method 'void android.app.AppOpsManager.checkPackage(int, java.lang.String)' on a null object reference
11-20 19:06:11.268 4965 4965 E Pm : at android.os.Parcel.readException(Parcel.java:2010)
11-20 19:06:11.268 4965 4965 E Pm : at android.os.Parcel.readException(Parcel.java:1950)
11-20 19:06:11.268 4965 4965 E Pm : at android.content.pm.IPackageInstaller$Stub$Proxy.createSession(IPackageInstaller.java:254)
11-20 19:06:11.268 4965 4965 E Pm : at com.android.commands.pm.Pm.doCreateSession(Pm.java:607)
11-20 19:06:11.268 4965 4965 E Pm : at com.android.commands.pm.Pm.runInstall(Pm.java:431)
11-20 19:06:11.268 4965 4965 E Pm : at com.android.commands.pm.Pm.run(Pm.java:150)
11-20 19:06:11.268 4965 4965 E Pm : at com.android.commands.pm.Pm.main(Pm.java:107)
11-20 19:06:11.268 4965 4965 E Pm : at com.android.internal.os.RuntimeInit.nativeFinishInit(Native Method)
11-20 19:06:11.268 4965 4965 E Pm : at com.android.internal.os.RuntimeInit.main(RuntimeInit.java:285)
11-20 19:06:11.270 4965 4965 I app_process: System.exit called, status: 1
11-20 19:06:11.270 4965 4965 I AndroidRuntime: VM exiting with result code 1.
谁能告诉我为什么会发生此错误或其他解决方案或使用 INSTALL_PACKAGES 静默安装 APKS 的“现代”方式?
任何帮助表示赞赏。
编辑:
对于将其标记为空指针异常重复的人-您如何建立重复的连接?我专门询问其背后的原因,而不是关于 nullpointer 异常本身。您的重复建议毫无意义。
编辑2:
我尝试安装 APK 的代码(从 AOSP 源的包安装程序应用程序复制):
public boolean install(Context context) {
Log.d(TAG, "Start Installation");
String packageName = "com.spotify.music";
String apkPath = Environment.getExternalStorageDirectory().toString() + "/APKs/spotify.apk";
PackageInstaller.Session session;
int sessionId;
PackageInstaller.SessionParams params = new PackageInstaller.SessionParams(PackageInstaller.SessionParams.MODE_FULL_INSTALL);
params.setAppPackageName(packageName);
try {
sessionId = context.getPackageManager().getPackageInstaller().createSession(params);
session = context.getPackageManager().getPackageInstaller().openSession(sessionId);
} catch (IOException e) {
Log.w(TAG, "Error creating/opening the installing session", e);
return false;
}
try {
File file = new File(apkPath);
try (InputStream in = new FileInputStream(file)) {
long sizeBytes = file.length();
try (OutputStream out = session.openWrite("PackageInstaller", 0, sizeBytes)) {
byte[] buffer = new byte[1024 * 1024];
while (true) {
int numRead = in.read(buffer);
if (numRead == -1) {
session.fsync(out);
break;
}
out.write(buffer, 0, numRead);
if (sizeBytes > 0) {
float fraction = ((float) numRead / (float) sizeBytes);
Log.d(TAG, "Install progress: " + fraction);
}
}
}
}
Log.d(TAG, "Install finished");
session.commit(PendingIntent.getBroadcast(context, sessionId, new Intent("android.intent.action.MAIN"), 0).getIntentSender());
return true;
} catch (IOException | SecurityException e) {
Log.e(TAG, "Could not write package", e);
session.close();
return false;
}
}
解决方案
我们使用以下代码:
Uri apkUri = Uri.fromFile(apkFile);
IPackageInstallObserver observer = null;
String installerPackageName = "MyInstaller";
getPackageManager().installPackage(apkUri, observer, PackageManager.INSTALL_REPLACE_EXISTING, installerPackageName);
它已被弃用,但即使在 Android 8.1 上仍然有效。
推荐阅读
- python - 将数据帧写入 csv 时出错
- c# - 如何使用 jquery 设置 aspnet 下拉列表的选定值
- python - 累积和结转 - 用 pandas 向量化
- rest - 如何访问 Alexa 上本地托管的 REST API
- excel - Excel Web 加载项:如何检测功能区单击事件?
- sql-server - 用于更改现有数据库的 SQL Server 数据库项目
- visual-studio-code - VSCode 扩展不显示贡献
- python - PyCharm 在优化导入时将 os 视为第三方模块
- json - Elasticsearch js 批量索引类型错误
- swift - 如何将其保存到我的应用程序所在的位置