我的应用程序具有自动更新功能,可以下载APK,下载完成后会打开一个Intent.VIEW_ACTION来打开应用程序并让用户安装下载的apk
Uri uri = Uri.parse("file://" + destination);
Intent install = new Intent(Intent.ACTION_VIEW);
install.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
install.setDataAndType(uri,
manager.getMimeTypeForDownloadedFile(downloadId));
activity.startActivity(install);
这适用于所有设备< 24
现在使用Android 24显然我们不再允许使用file:///启动意图,并且经过一些谷歌搜索后,建议使用A文件提供程序
新代码:
Intent install = new Intent(Intent.ACTION_VIEW);
install.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
install.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
Uri apkUri = FileProvider.getUriForFile(AutoUpdate.this,
BuildConfig.APPLICATION_ID + ".provider", file);
install.setDataAndType(apkUri,
manager.getMimeTypeForDownloadedFile(downloadId));
activity.startActivity(install);
现在activity.startActivity(安装);抛出错误
找不到活动来处理Intent {act = android.intent.action.VIEW DAT =含量://com.xxxx.xx.provider/MyFolder/Download/MyApkFile.apk typ = application / vnd.android.package-archive flg = 0x4000000}
有什么方法可以在Android 7(24)中打开APK查看器吗?
答案 0 :(得分:114)
经过大量尝试后,我能够通过为Nougat之下的任何东西创建不同的Intent来解决这个问题,因为在Nougat导致错误之前使用FileProvider创建Android版本的安装意图:
ActivityNotFoundException: No Activity found to handle Intent { act=android.intent.action.INSTALL_PACKAGE dat=content://XXX.apk flg=0x1 }
在Android上使用普通的Uri时,Nougat会产生以下错误:
FileUriExposedException: file:///XXX.apk exposed beyond app through Intent.getData()
我的解决方案适用于模拟器上的Android N和运行Android M.的手机
File toInstall = new File(appDirectory, appName + ".apk");
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
Uri apkUri = FileProvider.getUriForFile(activity, BuildConfig.APPLICATION_ID + ".provider", toInstall);
Intent intent = new Intent(Intent.ACTION_INSTALL_PACKAGE);
intent.setData(apkUri);
intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
activity.startActivity(intent)
} else {
Uri apkUri = Uri.fromFile(toInstall);
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(apkUri, "application/vnd.android.package-archive");
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
activity.startActivity(intent);
}
更新Android Nougat 7.1:
您还需要在清单中添加权限REQUEST_INSTALL_PACKAGES。它可以从Api Level 23(Android 6.0 Marshmallow)获得,并且需要25级(Android 7.1 Nougat)。
<强>更新强>
如果您尝试安装的文件位于外部存储上,请记住请求读取和写入外部存储的权限。并为Android Nougat及以上版本设置正确的FileProvider。
首先检查您是否具有写入权限,如果之前未调用canReadWriteExternal()
,则请致电requestPermission()
:
private static final int REQUEST_WRITE_PERMISSION = 786;
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
if (requestCode == REQUEST_WRITE_PERMISSION && grantResults[0] == PackageManager.PERMISSION_GRANTED)
Toast.makeText(this, "Permission granted", Toast.LENGTH_LONG).show();
}
private void requestPermission() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
requestPermissions(new String[]{ Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_WRITE_PERMISSION);
}
private boolean canReadWriteExternal() {
return Build.VERSION.SDK_INT < Build.VERSION_CODES.M ||
ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED;
}
以下是外部存储上的“下载”文件夹的文件提供程序示例。的的AndroidManifest.xml 强>:
<application ... >
...
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="${applicationId}.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/filepaths" />
</provider>
</application>
<强>资源/ XML / filepaths.xml 强>:
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path name="external_download" path="Download"/>
</paths>
如果在安装.apk时出现类似&#34之类的错误;解析包时会出现问题。&#34;可能是您没有要求读/写权限,或者您尝试安装的文件不存在或已损坏。
答案 1 :(得分:5)
这可能是问题,你有
intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
你的例子中的应该是
install.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
as install是意图的名称。
答案 2 :(得分:5)
我在调用开始活动时遇到了这个问题。暂停当前活动后,它突然回来并调用了onResume。好像什么都没发生。我的问题是清单中的此权限:
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
几乎没有人提到。所以记住这一点。 在sdk> = 24中,您需要使用provider,因为它需要以file:///开头的意图 在sdk 24以下,您应以content:///开头的uri 这就是为什么我们需要sdk 24及更高版本的文件提供程序。我不认为我需要为此编写任何代码,因为@just_user编写了正确的答案。
答案 3 :(得分:1)
您应注意,对于<24的API,您需要使用:
setDataAndType(Uri.fromFile(apkFile), "application/vnd.android.package-archive")
而不是分别设置数据和类型:
data = Uri.fromFile(apkFile)
type = "application/vnd.android.package-archive"
否则,您将获得ActivityNotFoundException