Android 12程序化安装APK遭权限拒绝问题求助
Android 12 APK安装权限拒绝问题排查与解决
问题背景
使用Android Studio + Java开发应用,目标安装路径为/storage/emulated/0/Download/eduphone/eduphone.apk的安装包,但在Android 12系统上Logcat报错:Permission to access file: /storage/emulated/0/Download/eduphone/eduphone.apk is denied,尝试Stack Overflow方案无效。
用户提供的配置与代码
Manifest文件
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools"> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.READ_MEDIA_IMAGES" /> <uses-permission android:name="android.permission.READ_MEDIA_VIDEO" /> <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.READ_MEDIA_AUDIO" /> <uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES"/> <uses-permission android:name="com.termux.permission.RUN_COMMAND"/> <application android:allowBackup="true" android:dataExtractionRules="@xml/data_extraction_rules" android:fullBackupContent="@xml/backup_rules" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:exported="true" android:theme="@style/Theme.Test4" tools:targetApi="31"> <activity android:name="eu.eduphone.install.MainActivity" android:exported="true"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <provider android:name="androidx.core.content.FileProvider" android:authorities="${applicationId}.provider" android:exported="false" android:permission="android.permission.MANAGE_DOCUMENTS" android:grantUriPermissions="true"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/provider_paths"/> </provider> </application> <queries> <package android:name="com.termux" /> <package android:name="eu.edduphone" /> </queries> </manifest>
provider_paths.xml文件
<?xml version="1.0" encoding="utf-8"?> <paths xmlns:android="http://schemas.android.com/apk/res/android"> <external-path name="external_files" path="." /> </paths>
权限申请代码
public void getdroits () { if (ContextCompat.checkSelfPermission(this, READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(this, new String[]{READ_EXTERNAL_STORAGE}, 1); } if (ContextCompat.checkSelfPermission(this, WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(this, new String[]{WRITE_EXTERNAL_STORAGE}, 1); } if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { if(!getPackageManager().canRequestPackageInstalls()){ startActivityForResult(new Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES) .setData(Uri.parse(String.format("package:%s", getPackageName()))), 1); } } }
APK安装代码(传入路径:/sdcard/Download/eduphone/eduphone.apk)
private void instApp(String PATH){ Context context = getActivity().getBaseContext(); File file = new File(PATH); if(file.exists()) { Uri uri ; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { uri = FileProvider.getUriForFile(context, BuildConfig.APPLICATION_ID + ".provider", file); } else { uri = Uri.fromFile(file); } Intent intent = new Intent(Intent.ACTION_INSTALL_PACKAGE, uri); intent.setDataAndType(uri, "application/vnd.android.package-archive"); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); try { context.startActivity(intent); } catch (ActivityNotFoundException e) { e.printStackTrace(); Log.e("TAG", "Error in opening the file!"); } }else{ Toast.makeText(context,"APK "+PATH+" not found",Toast.LENGTH_LONG).show(); } }
解决方案
1. 移除FileProvider的多余权限配置
你的FileProvider配置中添加了android:permission="android.permission.MANAGE_DOCUMENTS",这会导致系统安装器访问该Provider时被额外权限拦截,直接删除此属性:
<provider android:name="androidx.core.content.FileProvider" android:authorities="${applicationId}.provider" android:exported="false" <!-- 移除该行 --> <!-- android:permission="android.permission.MANAGE_DOCUMENTS" --> android:grantUriPermissions="true"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/provider_paths"/> </provider>
2. 修正权限申请逻辑
Android 12中,READ_EXTERNAL_STORAGE属于危险权限,需合并请求避免弹窗叠加;同时Android 11+需适配MANAGE_EXTERNAL_STORAGE特殊权限:
public void getdroits() { List<String> permissions = new ArrayList<>(); // 合并读写权限请求 if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { permissions.add(Manifest.permission.READ_EXTERNAL_STORAGE); } if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { permissions.add(Manifest.permission.WRITE_EXTERNAL_STORAGE); } if (!permissions.isEmpty()) { ActivityCompat.requestPermissions(this, permissions.toArray(new String[0]), 1); } // 未知来源应用安装权限 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { if (!getPackageManager().canRequestPackageInstalls()) { startActivityForResult(new Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES) .setData(Uri.parse(String.format("package:%s", getPackageName()))), 2); } } // Android 11+ 全文件访问权限引导 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { if (!Environment.isExternalStorageManager()) { Intent intent = new Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION); intent.setData(Uri.parse("package:" + getPackageName())); startActivityForResult(intent, 3); } } }
3. 优化APK安装Intent配置
避免重复设置setDataAndType,并针对Android 12+添加持久权限标记:
private void instApp(String PATH) { Context context = getActivity().getBaseContext(); File file = new File(PATH); if (file.exists()) { Uri uri; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { uri = FileProvider.getUriForFile(context, BuildConfig.APPLICATION_ID + ".provider", file); } else { uri = Uri.fromFile(file); } Intent intent = new Intent(Intent.ACTION_INSTALL_PACKAGE); intent.setData(uri); intent.setType("application/vnd.android.package-archive"); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); // Android 12+ 添加持久权限 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { intent.addFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION); } try { context.startActivity(intent); } catch (ActivityNotFoundException e) { e.printStackTrace(); Log.e("TAG", "Error in opening the file!"); } } else { Toast.makeText(context, "APK " + PATH + " not found", Toast.LENGTH_LONG).show(); } }
4. 改用SAF获取文件Uri(Android 11+推荐)
直接访问公共目录易触发权限限制,使用存储访问框架让用户选择APK文件,彻底规避路径权限问题:
// 启动文件选择器 private void pickApkFile() { Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT); intent.addCategory(Intent.CATEGORY_OPENABLE); intent.setType("application/vnd.android.package-archive"); startActivityForResult(intent, 4); } // 处理选择结果 @Override protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == 4 && resultCode == RESULT_OK && data != null) { Uri apkUri = data.getData(); // 授予持久访问权限 getContentResolver().takePersistableUriPermission(apkUri, Intent.FLAG_GRANT_READ_URI_PERMISSION); // 执行安装 installApkWithUri(apkUri); } } // 通过Uri安装APK private void installApkWithUri(Uri uri) { Context context = getBaseContext(); Intent intent = new Intent(Intent.ACTION_INSTALL_PACKAGE); intent.setData(uri); intent.setType("application/vnd.android.package-archive"); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); try { context.startActivity(intent); } catch (ActivityNotFoundException e) { e.printStackTrace(); Log.e("TAG", "Error in opening the file!"); } }
内容的提问来源于stack exchange,提问作者Coilhac
相关产品推荐
相关产品推荐

