Ionic 6/Capacitor应用已加存储权限仍无法保存文件问题咨询
排查修复步骤
- 先补全运行时权限申请逻辑
你只在AndroidManifest.xml声明了存储权限,但Android 6.0(API 23)以上版本,存储属于危险权限,必须在操作触发时动态向用户申请,只写Manifest不会自动授权,调用写入接口会直接失败。
注意Android 13(API 33)及以上版本已经废弃WRITE_EXTERNAL_STORAGE权限,不需要申请,系统默认允许应用访问公共媒体和文档目录,你加的android:requestLegacyExternalStorage="true"仅对Android 10生效,Android 11+会自动忽略这个配置。
改造后的写入方法参考:
import { Filesystem, Directory, Encoding } from '@capacitor/filesystem'; import { Permissions } from '@capacitor/permissions'; import { Device } from '@capacitor/device'; writeSecretFile = async () => { // 先判断系统版本,低版本才申请存储权限 const info = await Device.getInfo(); if (Number(info.androidSDKVersion) < 33) { const perm = await Permissions.requestPermissions({ permissions: ['storage'] }); if (perm.storage !== 'granted') { console.log('未获得存储权限,终止操作'); return; } } try { // 先递归创建父目录,避免父目录不存在报错 await Filesystem.mkdir({ path: 'secrets', directory: Directory.Documents, recursive: true }); // 执行写入 const writeRes = await Filesystem.writeFile({ path: 'secrets/text.txt', data: "This is a test", directory: Directory.Documents, encoding: Encoding.UTF8, }); console.log('写入成功,文件URI:', writeRes.uri); // 写完立刻读,验证文件是否真的写入成功 const readRes = await Filesystem.readFile({ path: 'secrets/text.txt', directory: Directory.Documents, encoding: Encoding.UTF8 }); console.log('读取校验内容:', readRes.data); } catch (err) { console.error('文件操作报错:', err); } };
- 不要手动翻目录找文件,先确认文件是否真的没写入
不同厂商ROM对公共Documents目录的映射逻辑不一样,部分系统自带文件管理器会默认隐藏非媒体类文件,或者把目录放在Android/data/你的应用包名/files/Documents路径下,不要靠手动翻目录判断是否写入成功。
写入成功后接口会返回文件的URI地址,你可以直接用这个URI定位文件,或者通过上面代码里的写入后立刻读取的逻辑校验:如果能读到写入的内容,说明文件已经写成功,只是你找错了位置。 - 检查基础配置是否同步到位
- 确认
@capacitor/filesystem插件版本和你项目使用的Capacitor主版本一致,大版本不兼容会导致API调用无响应。 - 每次修改
AndroidManifest.xml、安装新的Capacitor插件后,必须执行npx cap sync android同步配置到原生工程,再重新打包安装,否则修改的配置不会生效。 - 检查
android/app/src/main/res/xml/file_paths.xml配置,确保已经添加Documents目录的映射,配置参考:
- 确认
<?xml version="1.0" encoding="utf-8"?> <paths xmlns:android="http://schemas.android.com/apk/res/android"> <external-files-path name="my_docs" path="Documents/" /> <external-path name="public_docs" path="Documents/" /> </paths>
- 必须加错误捕获
你现在的代码没有try/catch包裹异步操作,接口调用失败的报错会被Promise吞掉,你看不到具体错误原因——不管是权限不足、路径不存在还是系统限制,报错信息里都会写得很清楚,加上捕获之后看log就能直接定位问题,不用盲目试错。
内容的提问来源于stack exchange,提问作者deszok
相关产品推荐
相关产品推荐

