在Android 10及以上版本中,由于安全限制的加强,静默安装系统应用程序的方法已经发生了变化。现在需要使用设备策略管理器来实现静默安装。下面是一个Kotlin示例代码,用于使用设备策略管理器来静默安装系统应用程序:
/**
* 安装系统应用程序
* @param context 应用程序上下文
* @param packageName 应用程序包名
*/
@RequiresApi(Build.VERSION_CODES.Q)
fun installSystemApp(context: Context, packageName: String) {
val devicePolicyManager = context.getSystemService(Context.DEVICE_POLICY_SERVICE) as DevicePolicyManager
val componentName = ComponentName(context, MyDeviceAdminReceiver::class.java)
if (devicePolicyManager.isAdminActive(componentName)) {
val installerPackageName = devicePolicyManager.getProfileOwnerAsUser(UserHandle.myUserId())?.packageName
if (installerPackageName != null) {
val packageInfo = getSystemPackageInfo(context.packageManager, packageName)
if (packageInfo != null) {
val apkFile = File(packageInfo.applicationInfo.publicSourceDir)
val packageInstaller = context.packageManager.packageInstaller
val sessionParams = PackageInstaller.SessionParams(PackageInstaller.SessionParams.MODE_FULL_INSTALL)
sessionParams.setAppPackageName(packageName)
val sessionId = packageInstaller.createSession(sessionParams)
val session = packageInstaller.openSession(sessionId)
val outputStream = session.openWrite(apkFile.name, 0, -1)
val inputStream = FileInputStream(apkFile)
val buffer = ByteArray(8192)
var length: Int
while (inputStream.read(buffer).also { length = it } > 0) {
outputStream.write(buffer, 0, length)
}
session.fsync(outputStream)
outputStream.close()
inputStream.close()
session.commit(PendingIntent.getBroadcast(context, sessionId, Intent("android.intent.action.INSTALL_COMPLETED"), 0).intentSender)
} else {
// 应用程序包名不正确或应用程序未安装
}
} else {
// 未获得设备所有者权限
}
} else {
// 未激活设备管理器
}
}
/**
* 获取系统应用程序信息
* @param packageManager 包管理器
* @param packageName 应用程序包名
* @return 应用程序信息
*/
fun getSystemPackageInfo(packageManager: PackageManager, packageName: String): PackageInfo? {
try {
val applicationInfo = packageManager.getApplicationInfo(packageName, PackageManager.GET_META_DATA)
if (applicationInfo != null && (applicationInfo.flags and ApplicationInfo.FLAG_SYSTEM) != 0) {
return packageManager.getPackageArchiveInfo(applicationInfo.publicSourceDir, PackageManager.GET_ACTIVITIES or PackageManager.GET_SERVICES)
}
} catch (e: PackageManager.NameNotFoundException) {
e.printStackTrace()
}
return null
}