You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Android 7+外接存储写入异常,是否需切换至SAF替代file://?

解决Android 7+可移除外部存储写入问题:是否该切换到SAF?

绝对是,切换到Storage Access Framework (SAF)就是解决你当前问题的正确思路,尤其是结合你的应用需要支持自定义保存位置、甚至允许新建文件夹的需求来看,SAF几乎是完美匹配的方案。下面我给你拆解下原因和实操要点:

为啥Context.getExternalFilesDirs(null)[1]会变成只读?

  • 在Android 7(API 24)到Android 9(API 28)这段区间,虽然理论上应用拿了WRITE_EXTERNAL_STORAGE权限就能访问可移除存储,但不少设备厂商对SD卡上的应用私有目录(就是你用getExternalFilesDirs(null)[1]拿到的路径)做了写入限制,导致实际使用中出现只读的情况。
  • 到了Android 10(API 29)及以上的Scoped Storage机制,更是直接收紧了规则:就算是应用自己的私有目录,在可移除存储上也不允许直接用File API写入,必须通过SAF或者MediaStore来操作。

为什么SAF适合你的场景?

SAF刚好戳中你的核心需求:

  • 自定义保存位置完全支持:通过ACTION_OPEN_DOCUMENT_TREE这个Intent,你可以让用户自由选择任何目录——不管是内部存储、可移除SD卡,甚至还能让用户在选择过程中新建文件夹。拿到用户选择的目录的文档URI后,就能对这个目录进行操作。
  • 权限持久化:用户授权后,你可以调用ContentResolver.takePersistableUriPermission()把权限存下来,下次用户打开应用不用再反复授权,体验会顺畅很多。
  • 跨版本兼容省心:SAF从Android 4.4就有了,在Android 7+上运行稳定,能避开不同版本存储权限的各种坑,不用再为不同系统版本写一堆适配逻辑。

切换到SAF的核心步骤

  • 启动目录选择器:用ACTION_OPEN_DOCUMENT_TREE Intent唤起系统的目录选择界面,用户选好后在onActivityResult(或者用Activity Result API)里拿到返回的Uri
  • 保存权限:拿到Uri后,调用takePersistableUriPermission()把访问权限持久化,避免下次启动应用失效。
  • DocumentFile操作文件:通过DocumentFile.fromTreeUri()获取目录的DocumentFile实例,之后创建子文件夹、写入音频文件都靠它——比如用ContentResolver.openOutputStream()获取输出流来写录音文件。

额外提醒

  • 如果你的应用还要兼容Android 10以下的设备,可以做个分支逻辑:内部存储和应用私有外部存储继续用File API,只有当用户选择可移除存储上的自定义位置时,才切换到SAF。
  • 记得多测几个不同品牌的设备,有些厂商对SAF的实现会有小差异,提前适配能避免踩坑。

内容的提问来源于stack exchange,提问作者Alexandru Circus

火山引擎 最新活动