广东建设监理协会网站,上海加强旅游住宿业与商业场所,简洁物流网站模板,贵阳手机银行app在 RK 平台 Android 7 项目中#xff0c;因为客户需要支持 APK 静默安装/卸载#xff0c;只能从 Framework 层下手做一套完整方案。 网上常见做法基本都是直接调用 pm 命令。实测下来#xff1a; pm install #xff1a;基本没有问题#xff0c;可以绕过“未知来源”提示…在 RK 平台Android 7项目中因为客户需要支持APK 静默安装/卸载只能从 Framework 层下手做一套完整方案。网上常见做法基本都是直接调用pm命令。实测下来pm install基本没有问题可以绕过“未知来源”提示完成安装pm uninstall在应用内调用时会抛异常最终还是回到系统源代码从 Framework 层分析调用链并做了小改动实现了可用的静默安装 / 卸载能力。先看系统自带的卸载行为从桌面拖动应用到“卸载”区域本质上最终会调用PackageManager.deletePackage来完成卸载frameworks/base/core/java/android/content/pm/PackageManager.java/** * Attempts to delete a package. Since this may take a little while, the * result will be posted back to the given observer. A deletion will fail if * the calling context lacks the * {link android.Manifest.permission#DELETE_PACKAGES} permission, if the * named package cannot be found, or if the named package is a system * package. * * param packageName The name of the package to delete * param observer An observer callback to get notified when the package * deletion is complete. * {link android.content.pm.IPackageDeleteObserver#packageDeleted} * will be called when that happens. observer may be null to * indicate that no callback is desired. * hide */SuppressWarnings(HiddenAbstractMethod)RequiresPermission(Manifest.permission.DELETE_PACKAGES)UnsupportedAppUsagepublicabstractvoiddeletePackage(NonNullStringpackageName,NullableIPackageDeleteObserverobserver,DeleteFlagsintflags);不过deletePackage是hide的隐藏 API虽然可以通过引入framework.jar反射调用但工程侵入性较大、维护成本也高因此还是优先选择基于pm命令的方式来做静默卸载。原理pm命令最终是落到 Framework 层的PackageInstallerService这个类来执行的。相关源码文件位置如下frameworks/base/services/core/java/com/android/server/pm/PackageInstallerService.javaOverridepublicvoiduninstall(VersionedPackageversionedPackage,StringcallerPackageName,intflags,IntentSenderstatusReceiver,intuserId){finalComputersnapshotmPm.snapshotComputer();finalintcallingUidBinder.getCallingUid();snapshot.enforceCrossUserPermission(callingUid,userId,true,true,uninstall);// Create by yeruilai 2025-11-01 20:46:06 Enable silent loading for System users// if ((callingUid ! Process.SHELL_UID) (callingUid ! Process.ROOT_UID)) {if((callingUid!Process.SHELL_UID)(callingUid!Process.ROOT_UID)(callingUid!Process.SYSTEM_UID)){mAppOps.checkPackage(callingUid,callerPackageName);}// Check whether the caller is device owner or affiliated profile owner, in which case we do// it silently.DevicePolicyManagerInternaldpmiLocalServices.getService(DevicePolicyManagerInternal.class);finalbooleancanSilentlyInstallPackagedpmi!nulldpmi.canSilentlyInstallPackage(callerPackageName,callingUid);uninstall相关逻辑默认只允许ROOT_UID与SHELL_UID这两个用户执行所以通过ADB shell执行pm uninstall可以正常卸载shell 权限在普通应用里直接执行pm uninstall就会因权限校验失败而抛异常如果业务 APK 本身是系统应用Manifest 中指定android.uid.system那么只需要在对应逻辑里把SYSTEM_UID也加入白名单即可允许系统应用通过pm uninstall执行卸载。如果希望普通应用也能调用pm uninstall那就更“简单粗暴”——把下面这行校验直接注释掉即可mAppOps.checkPackage(callingUid,callerPackageName);但这等于完全放开了调用方校验风险较大仅建议在强可控的定制系统或调试环境里使用不推荐在量产环境这样修改。封装实现静默安装 / 卸载工具类下面是对静默安装 / 卸载做的一层简单封装方便在业务代码中统一调用与回调处理。1. 安装 / 卸载回调接口publicinterfaceApkInstallListener{voidonSuccess(StringpackageName);voidonFail(Exceptione);}2. 静默安装方法基于pm installpublicsynchronizedstaticvoidinstallApk(Contextcontext,StringapkPath,ApkInstallListenerinstallListener){try{PackageInfoinfogetApkInfo(context,apkPath);String[]args{pm,install,-i,info.packageName,--user,0,-r,apkPath};ProcessBuilderprocessBuildernewProcessBuilder(args);Processprocessnull;BufferedReadersuccessResultnull;BufferedReadererrorResultnull;StringBuildersuccessMsgnewStringBuilder();StringBuildererrorMsgnewStringBuilder();try{processprocessBuilder.start();successResultnewBufferedReader(newInputStreamReader(process.getInputStream()));errorResultnewBufferedReader(newInputStreamReader(process.getErrorStream()));Stringline;while((linesuccessResult.readLine())!null){successMsg.append(line);}while((lineerrorResult.readLine())!null){errorMsg.append(line);}Log.i(TAG,install success_msg successMsg);Log.i(TAG,install error_msg errorMsg);if(successMsg.toString().contains(Success)){if(installListener!null){installListener.onSuccess(info.packageName);}}else{if(installListener!null){installListener.onFail(newRuntimeException(errorMsg.toString()));}}}catch(Exceptione){Log.i(TAG,install fail ,e);if(installListener!null){installListener.onFail(e);}}finally{try{if(successResult!null){successResult.close();}}catch(IOExceptionignored){}try{if(errorResult!null){errorResult.close();}}catch(IOExceptionignored){}try{if(process!null){process.destroy();}}catch(Exceptionignored){}}}catch(Exceptione){if(installListener!null){installListener.onFail(e);}}}3. 获取 APK 信息的工具方法/** * 获取 apk 包的信息版本号名称图标等 * * param absPath apk 包的绝对路径 * param context Context */privatestaticPackageInfogetApkInfo(Contextcontext,StringabsPath){PackageInfopkgInfonull;try{PackageManagerpmcontext.getPackageManager();pkgInfopm.getPackageArchiveInfo(absPath,PackageManager.GET_ACTIVITIES);if(pkgInfo!null){ApplicationInfoappInfopkgInfo.applicationInfo;// 必须加这两句否则 icon 获取不到 apk 自身的图标appInfo.sourceDirabsPath;appInfo.publicSourceDirabsPath;StringappNamepm.getApplicationLabel(appInfo).toString();StringpackageNameappInfo.packageName;StringversionpkgInfo.versionName;StringpkgInfoStrString.format(PackageName:%s, Version:%s, AppName:%s,packageName,version,appName);Log.i(YTUtils,String.format(PkgInfo: %s,pkgInfoStr));}}catch(Exceptione){Log.e(YTUtils,apk 文件信息读取失败: absPath,e);}returnpkgInfo;}4. 静默卸载方法基于pm uninstallpublicsynchronizedstaticvoiduninstallApk(Contextcontext,StringpackageName,ApkInstallListenerinstallListener){try{String[]args{pm,uninstall,-k,--user,0,packageName};ProcessBuilderprocessBuildernewProcessBuilder(args);Processprocessnull;BufferedReadersuccessResultnull;BufferedReadererrorResultnull;StringBuildersuccessMsgnewStringBuilder();StringBuildererrorMsgnewStringBuilder();try{processprocessBuilder.start();successResultnewBufferedReader(newInputStreamReader(process.getInputStream()));errorResultnewBufferedReader(newInputStreamReader(process.getErrorStream()));Stringline;while((linesuccessResult.readLine())!null){successMsg.append(line);}while((lineerrorResult.readLine())!null){errorMsg.append(line);}Log.i(TAG,uninstall success_msg successMsg);Log.i(TAG,uninstall error_msg errorMsg);if(successMsg.toString().contains(Success)){if(installListener!null){installListener.onSuccess(packageName);}}else{if(installListener!null){installListener.onFail(newRuntimeException(errorMsg.toString()));}}}catch(Exceptione){Log.i(TAG,uninstall fail ,e);if(installListener!null){installListener.onFail(e);}}finally{try{if(successResult!null){successResult.close();}}catch(IOExceptionignored){}try{if(errorResult!null){errorResult.close();}}catch(IOExceptionignored){}try{if(process!null){process.destroy();}}catch(Exceptionignored){}}}catch(Exceptione){if(installListener!null){installListener.onFail(e);}}}以上就是在Android 7上通过少量 Framework 修改配合pm命令实现静默安装 / 卸载的整体思路与代码封装。