You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android API 30下使用SAF创建文件后分享报SecurityException权限错误如何解决

问题原因分析
  • 你拿到的SAF URI属于DocumentsProvider的内容URI,FLAG_GRANT_READ_URI_PERMISSION默认仅对应用自身包名下的ContentProvider(比如FileProvider)生效,跨包的DocumentsProvider URI需要主动申请临时权限授予
  • 调用SAF选择器拿到URI后,仅当前应用获得了读写权限,系统不会自动帮你把读取权限透传给第三方分享应用
  • 部分ROM的DocumentsProvider实现存在差异,即使是应用自身创建的文件,也不会默认对第三方应用开放读取权限
  • 额外说明:API 30并未废弃FileProvider,仅限制了FileProvider对外界公共存储目录的访问,应用私有目录/缓存目录的FileProvider分享逻辑完全可用
解决方案

方案1:手动授予URI临时权限(优先推荐)

构造分享意图时,除了添加FLAG标识,还需要主动给所有匹配到的分享目标应用授予临时读取权限:

// 替换yourMimeType为实际分享的文件类型,fileUri为SAF返回的文件URI
Intent shareIntent = new Intent(Intent.ACTION_SEND);
shareIntent.setType(yourMimeType);
shareIntent.putExtra(Intent.EXTRA_STREAM, fileUri);
shareIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);

// 遍历所有匹配到的分享应用,逐个授予权限
List<ResolveInfo> resInfoList = getPackageManager().queryIntentActivities(shareIntent, PackageManager.MATCH_DEFAULT_ONLY);
for (ResolveInfo resolveInfo : resInfoList) {
    String packageName = resolveInfo.activityInfo.packageName;
    grantUriPermission(packageName, fileUri, Intent.FLAG_GRANT_READ_URI_PERMISSION);
}

startActivity(Intent.createChooser(shareIntent, "分享文件"));

分享完成后可调用revokeUriPermission回收权限,避免权限泄露

方案2:写入公共媒体目录分享

如果分享的是图片、视频、音频这类公共媒体文件,可直接写入MediaStore公共目录,拿到MediaStore URI后即可直接分享,无需额外申请权限,适配逻辑更简单。

方案3:缓存中转分享

若上述方案不生效,可先将SAF路径下的文件读取拷贝到应用私有缓存目录,再用原有FileProvider方案实现分享,该逻辑在API 30+上完全兼容。

排查注意事项
  • 拿到SAF URI后需调用getContentResolver().takePersistableUriPermission(uri, Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION)持久化权限,避免应用重启后权限丢失
  • 全程使用URI操作文件,不要将SAF URI转换为本地绝对路径使用,不同ROM下路径规则不通用
  • 分享前可先调用getContentResolver().openInputStream(uri)测试自身是否有读取权限,排除文件写入失败的问题

内容的提问来源于stack exchange,提问作者donny.rewq

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.21 00:15:03