Android Uri写入权限遭拒:java.lang.SecurityException异常如何处理?
解决Android修改Exif时的SecurityException权限问题
嘿,我帮你分析下这个问题——你遇到的java.lang.SecurityException其实不是因为没加对权限,而是两个关键误区导致的:MANAGE_DOCUMENTS权限的特殊限制,还有你调用grantUriPermission()的方式完全错了。
先搞清楚核心问题
MANAGE_DOCUMENTS权限没用:这个权限是系统级权限,只有系统预装的文件管理器或者特定系统应用才能申请到,普通APP就算在Manifest里声明了,系统也不会授予,所以这个权限可以直接删掉,它解决不了你的问题。grantUriPermission()用错了:你传的第一个参数是getApplicationContext().getPackageCodePath(),这是你APK的本地路径,但这个方法需要的是目标应用的包名。而且grantUriPermission()是用来给其他APP授权访问Uri的,不是给自己APP用的!给自己APP授权应该用takePersistableUriPermission()来获取持久访问权限。
正确的解决方案步骤
1. 确保你是通过SAF获取的Uri
如果你的AddArray里的Uri是自己构造的file://类型,在Android 10+是绝对无法直接写入的,必须通过**Storage Access Framework(SAF)**让用户选择文件,这样拿到的content://类型Uri才支持持久权限。
2. 在获取Uri时先拿到持久权限
当用户通过SAF选择文件后,你需要立即调用takePersistableUriPermission()保存权限,这样后续才能随时访问这个文件:
// 假设你在ActivityResultCallback中拿到用户选择的Uri @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == YOUR_PICK_FILE_REQUEST_CODE && resultCode == RESULT_OK) { Uri selectedUri = data.getData(); // 申请持久的读写权限 int flags = Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION; getContentResolver().takePersistableUriPermission(selectedUri, flags); // 把这个Uri保存到你的AddArray里 } }
3. 修正你的Exif修改代码
去掉错误的grantUriPermission()调用,直接用已获取的持久权限操作文件:
Uri targetUri = (Uri) AddArray[i]; ParcelFileDescriptor parcelFileDescriptor = null; try { // 先检查是否有持久写入权限(可选,但能避免异常) boolean hasWritePermission = getContentResolver().getPersistedUriPermissions().stream() .anyMatch(perm -> perm.getUri().equals(targetUri) && (perm.getFlags() & Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0); if (!hasWritePermission) { Toast.makeText(getApplicationContext(), "缺少文件写入权限,请重新选择文件", Toast.LENGTH_SHORT).show(); return; } // 打开文件写入流 parcelFileDescriptor = getContentResolver().openFileDescriptor(targetUri, "w"); if (parcelFileDescriptor == null) { Toast.makeText(getApplicationContext(), "无法打开文件", Toast.LENGTH_SHORT).show(); return; } FileDescriptor fileDescriptor = parcelFileDescriptor.getFileDescriptor(); ExifInterface ei = new ExifInterface(fileDescriptor); // 设置GPS信息 ei.setAttribute(TAG_GPS_LATITUDE, "33/1,35/1,4091/100"); ei.setAttribute(TAG_GPS_LATITUDE_REF, "N"); ei.setAttribute(TAG_GPS_LONGITUDE, "73/1,1/1,4390/100"); ei.setAttribute(TAG_GPS_LONGITUDE_REF, "E"); ei.saveAttributes(); Toast.makeText(getApplicationContext(), "GPS信息修改成功", Toast.LENGTH_SHORT).show(); } catch (Exception e) { Toast.makeText(getApplicationContext(), "修改失败:" + e.getMessage(), Toast.LENGTH_SHORT).show(); e.printStackTrace(); } finally { // 务必关闭流,避免资源泄漏 if (parcelFileDescriptor != null) { try { parcelFileDescriptor.close(); } catch (IOException e) { e.printStackTrace(); } } }
4. 额外优化建议
如果是处理媒体库中的图片,也可以考虑用MediaStore API直接修改Exif,不需要依赖SAF Uri:
ContentValues values = new ContentValues(); // 直接设置GPS相关的Exif字段 values.put(MediaStore.Images.Media.GPS_LATITUDE, 33.354091); values.put(MediaStore.Images.Media.GPS_LATITUDE_REF, "N"); values.put(MediaStore.Images.Media.GPS_LONGITUDE, 73.014390); values.put(MediaStore.Images.Media.GPS_LONGITUDE_REF, "E"); // 更新媒体库中的文件 getContentResolver().update(targetMediaUri, values, null, null);
这样处理更简洁,而且不需要额外申请持久权限,适合批量修改媒体文件的场景。
内容的提问来源于stack exchange,提问作者Abdullah Mufti
相关产品推荐
相关产品推荐

