Android无法从Assets文件夹安装APK问题求助
你的问题主要出在Android 7.0+的文件访问限制和Android 8.0+的未知应用安装权限要求这两个核心点上,结合你的代码与Gradle配置,我给你一步步的解决方案:
1. 配置FileProvider(解决API24+的Uri访问问题)
从Android 7.0(API24)开始,直接使用file://格式的Uri会触发FileUriExposedException,而且你的APK存储在应用内部私有目录,系统安装器无法直接访问该目录的文件,必须通过FileProvider来共享文件。
步骤1:在AndroidManifest.xml中添加FileProvider声明
打开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/file_paths" /> </provider>
${applicationId}会自动替换成你Gradle里的com.mypackage.music,确保authorities唯一即可。
步骤2:创建FileProvider路径配置文件
在res目录下新建xml文件夹,然后创建file_paths.xml文件,内容如下:
<?xml version="1.0" encoding="utf-8"?> <paths xmlns:android="http://schemas.android.com/apk/res/android"> <!-- 对应你用openFileOutput存储的files目录 --> <files-path name="tmp_apks" path="." /> </paths>
这个配置告诉FileProvider可以共享应用内部files目录下的所有文件。
2. 添加安装权限并处理Android 8.0+的权限请求
从Android 8.0(API26)开始,安装未知来源的APK需要用户手动授予权限,需完成以下操作:
步骤1:在AndroidManifest.xml添加权限
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
步骤2:修改安装Intent的代码
替换你原来的调用代码,先检查权限,再用FileProvider生成可访问的Uri并授予临时权限:
// 处理Android 8.0+的未知应用安装权限 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { if (!getPackageManager().canRequestPackageInstalls()) { // 跳转到权限设置页面 startActivityForResult(new Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES, Uri.parse("package:" + getPackageName())), 100); return; } } File apkFile = prepareApk("myapk.apk"); // 用FileProvider生成可被安装器访问的Uri Uri apkUri = FileProvider.getUriForFile(this, getPackageName() + ".fileprovider", apkFile); Intent intent = new Intent(Intent.ACTION_INSTALL_PACKAGE); intent.setData(apkUri); // 给安装器应用授予临时读取权限 intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); startActivity(intent);
3. 验证APK文件是否正确写入
可以在prepareApk函数末尾添加日志,确认文件是否成功写入:
File apkFile = getFileStreamPath("tmp.apk"); Log.i("InstallApk", "APK文件路径:" + apkFile.getAbsolutePath() + ",大小:" + apkFile.length()); return apkFile;
如果日志显示的文件大小和Assets里的APK大小不一致,说明文件写入有问题:检查Assets里的文件名是否和你传入的"myapk.apk"完全一致(注意大小写),或者排查读取/写入过程的异常。
额外检查点
- 避免Assets中的APK被压缩:在Gradle中添加配置,防止APK被压缩导致无法安装:
android { ... aaptOptions { noCompress 'apk' } } - 测试时确保设备允许安装未知来源应用:Android 8.0以下在系统设置中开启,8.0+通过代码跳转的权限页面开启。
按照这些步骤修改后,就能正常触发APK安装流程了。
内容的提问来源于stack exchange,提问作者BekaKK

