Android中Java.lang.SecurityException: Permission Denial权限问题求解
解决方案:Android Content URI 权限持久化问题
问题核心
你遇到的SecurityException是因为通过ACTION_OPEN_DOCUMENT获取的content:// URI仅拥有临时权限,当应用重启或会话结束后权限会失效,普通的READ_EXTERNAL_STORAGE权限无法覆盖这类URI的访问权限。
可行解决步骤
1. 持久化URI访问权限
在获取图片URI的环节(即你完成第一步“从设备查找图片并添加到程序”的代码中),添加持久化权限的代码,确保后续重启应用后仍能访问该URI:
// 适配传统ActivityResult方式 @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == YOUR_IMAGE_PICK_REQUEST_CODE && resultCode == RESULT_OK && data != null) { Uri imageUri = data.getData(); // 持久化读权限 getContentResolver().takePersistableUriPermission( imageUri, Intent.FLAG_GRANT_READ_URI_PERMISSION ); // 之后再将这个URI字符串保存到txt文件 } } // 适配AndroidX ActivityResultContracts方式 ActivityResultLauncher<Intent> pickImageLauncher = registerForActivityResult( new ActivityResultContracts.StartActivityForResult(), result -> { if (result.getResultCode() == Activity.RESULT_OK && result.getData() != null) { Uri imageUri = result.getData().getData(); getContentResolver().takePersistableUriPermission( imageUri, Intent.FLAG_GRANT_READ_URI_PERMISSION ); // 保存URI到txt文件 } } );
注意:必须使用ACTION_OPEN_DOCUMENT而非ACTION_GET_CONTENT来启动图片选择器,前者支持持久化权限,后者不支持。
2. 移除冗余权限
从AndroidManifest.xml中删除MANAGE_EXTERNAL_STORAGE权限,该权限用于全存储访问,不符合Scoped Storage规范,且会导致Google Play上架受阻,对你的场景完全无用:
<!-- 删除这一行 --> <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" tools:ignore="ScopedStorage"/>
Android 13+版本下,READ_EXTERNAL_STORAGE也可以移除,因为通过ACTION_OPEN_DOCUMENT获取的URI权限无需该权限。
3. 优化图片加载代码
添加异常捕获避免崩溃,同时简化加载逻辑:
if (str_adress != null && !str_adress.isEmpty()) { try { Uri uri = Uri.parse(str_adress); imgg.setImageURI(uri); } catch (SecurityException e) { // 权限失效时的处理:比如提示用户重新选择图片 Toast.makeText(getActivity(), "图片权限失效,请重新选择", Toast.LENGTH_SHORT).show(); e.printStackTrace(); } }
补充说明
content://类型的URI并非本地文件路径,不能直接用Drawable.createFromPath()加载,必须通过ContentResolver访问,setImageURI()内部会自动处理ContentResolver的调用。- 启动图片选择器时,需显式添加权限标记:
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT); intent.addCategory(Intent.CATEGORY_OPENABLE); intent.setType("image/*"); intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); pickImageLauncher.launch(intent);
内容的提问来源于stack exchange,提问作者PewPew01
相关产品推荐
相关产品推荐

