我正在制作一个 APK 安装应用程序,我经历了很多。特别是版本控制。 为此,我查阅了一些帖子和 StackOverFlow。但是所有的帖子现在让我更加困惑。那么,正确的方法是什么?
首先,请检查我下面关于为每个版本安装的代码。让我们谈谈什么是正确的方法。
KitKat(API 19)、Lollipop(API 21)、MashMellow(API 23)
fun installApkBelowNougat(apkFile: File) {
val apkUri = Uri.fromFile(apkFile)
val intent = Intent(Intent.ACTION_VIEW).apply {
setDataAndType(apkUri, "application/vnd.android.package-archive")
flags = Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_NEW_TASK
}
}
在这种情况下,所有解决方案都是相同的,我们必须使用
Uri.fromFile(file)
来获得 Uri
.
牛轧糖(API 24)
fun installApkInNougat(apkFile: File) {
val apkUri = FileProvider.getUriForFile(applicationContext, applicationContext.packageName + ".fileProvider", apkFile)
val intent = Intent(Intent.ACTION_VIEW).apply {
setDataAndType(apkUri, "application/vnd.android.package-archive")
flags = Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_NEW_TASK
addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
}
}
在这种情况下,我们不能再使用
Uri.fromFile(file)
了。所以代替它,我们必须使用 FileProvider
因为牛轧糖。我们还必须像这样在 AndroidManifest.xml 中编写<proivder/>
...
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.fileProvider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/filepath" />
</provider>
...
有人说我们不需要用
setDataAndType()
。相反,他们只是在 Android7(牛轧糖)中使用setData()
。
哪一个是正确的方法?两个都好吗?我们需要设置一个标志Intent.FLAG_GRANT_READ_URI_PERMISSION
。 setDataAndType()
或两者之一here 时找到。 奥利奥(API 26)、派(API 28)、Q(API 29)、R(API 30)
fun installApkMoreThanO(apkFile: File) {
f (!this.packageManager.canRequestPackageInstalls()) {
val unknownIntent = Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES).setData(
Uri.parse(String.format("package:%s", this.packageName))
)
resultLauncher.launch(unknownIntent)
} else {
val apkUri = FileProvider.getUriForFile(applicationContext, applicationContext.packageName + ".fileProvider", apkFile)
val intent = Intent(Intent.ACTION_VIEW, apkUri).apply {
putExtra(Intent.EXTRA_NOT_UNKNOWN_SOURCE, true)
setDataAndType(apkUri, "application/vnd.android.package-archive")
flags = Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_NEW_TASK
addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
}
startActivity(intent)
finish()
}
}
在这种情况下,从奥利奥,我们必须添加此权限
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
以安装APK文件。
如果不这样做,该应用程序将在没有任何迹象的情况下崩溃。我们必须使用Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES
,因为自Android8(Oreo)以来授予权限的方式已经改变。在奥利奥之前,我们可以一次授予所有应用程序的权限。但自从奥利奥以来,我们必须单独授予每个应用程序的权限。
我们可以使用
registerActivitResult
作为许可的结果。意思是如果你至今没有允许过app的权限,你必须允许权限,允许后系统返回Activity.RESULT_OK,或者Activity.RESULT_CANCELED。然后你可以做你想做的事。
S(API 31)
fun installApkMoreThanR(apkFile: File) {
val apkUri = FileProvider.getUriForFile(applicationContext, applicationContext.packageName + ".fileProvider", apkFile)
val intent = Intent(Intent.ACTION_VIEW, apkUri).apply {
putExtra(Intent.EXTRA_NOT_UNKNOWN_SOURCE, false)
setDataAndType(apkUri, "application/vnd.android.package-archive")
flags = Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_NEW_TASK
addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
}
}
在这种情况下,看起来我回到了有点旧的方式,但它确实有效而且很好。 和Android 8~10的方式一样。我不使用
Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES)
的原因是即使我们授予该应用程序的权限,我们也只能接收RESULT_CANCELED
。它总是在 Android12 中返回Activity.RESULT_CANCELED
。我不知道为什么。有人说我们必须使用 PackageInstaller
API,因为 ACTION_VIEW
和 ACTION_INSTALL_PACKAGE
在 Android 10 中已被弃用。但我测试了它,ACTION_VIEW
没有被弃用。
但是哪种方式更好?我们必须使用 PackageInstaller
API 从 Android 10 开始?