Android 11下原生应用跨卸载/重装保留文件的存储路径问题
问题描述
我维护一款带有轻量Android层的原生应用,此前依赖存储在/sdcard的数据文件,但Android 11开始强制执行作用域存储,/sdcard要么不可用要么被限定为应用专属。于是我将文件迁移到.,即应用的files/目录下。
然而,若用户卸载后重装应用(可能作为类升级操作),files/目录会被清除,数据文件也随之丢失。getExternalStorageDirectory和getExternalStoragePublicDirectory在API 29中已废弃,后者原本符合我的需求。
那么,针对Android 11,我应将文件存放在何处才能在卸载后保留?且该路径需支持通过JNI在原生代码中访问。getExternalFilesDir说明中提到这些文件会在应用卸载时被删除,因此不适用。Intent和MediaStore也不适用,因为这是原生应用。
测试情况
getStorageDirectory对应/storage,由root拥有,不确定能否写入;getDataDirectory对应/data,由系统拥有,甚至无法列出内容,存在com.my.app/0这类子目录结构,会被删除;- 已废弃的
getExternalStorageDirectory对应/storage/emulated/0(即/sdcard),若保持使用<uses-sdk android:minSdkVersion="14" android:targetSdkVersion="21" />,它或许是候选方案。我推测其内容不会被删除,但不确定/sdcard是否可访问,不过假设getExternalStorageDirectory即使指向同一位置仍可访问。 - 测试设备是Android 10(API 29),使用
getExternalStorageDirectory一切正常,也许是因为目标SDK版本较低? - 尝试通过JNI调用
getExternalStoragePublicDirectory时传入Environment.DIRECTORY_DOCUMENTS,但未成功,且该API已被标记为废弃。
解决方案
1. 合规长期方案:申请MANAGE_EXTERNAL_STORAGE权限(Android 11+)
在Android 11及以上版本,要访问卸载后不会被删除的公共存储路径(比如公共文档目录),需要申请全文件访问权限:
- 在
AndroidManifest.xml中添加权限声明:<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" android:minSdkVersion="30" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="29" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="29" /> - 代码中引导用户开启权限:通过Intent跳转至系统权限设置页,让用户手动开启“所有文件访问权限”。
- 拿到权限后,通过Android层获取公共存储的合法路径(比如公共文档目录),再将路径通过JNI传递给原生代码,原生即可直接读写该路径下的文件,卸载后数据会保留。
2. 兼容过渡方案:降低targetSdkVersion至29以下
如果暂时不想适配新权限机制,可以把targetSdkVersion设为29或更低,此时在Android 11设备上仍能使用已废弃的getExternalStorageDirectory()获取/storage/emulated/0路径,正常读写公共存储区域,卸载后数据也不会丢失。但这是过渡方案,后续Google可能限制低targetSdk应用上架,不建议长期使用。
3. 关键注意事项
- 不要硬编码存储路径(比如
/storage/emulated/0),不同设备路径可能有差异,必须通过Android系统API获取路径后传给JNI; - 若使用MANAGE_EXTERNAL_STORAGE权限,上架Google Play需符合政策,仅当应用确实需要全文件访问(比如文件管理器类)才会获批,普通应用建议优先评估其他方案。
内容的提问来源于stack exchange,提问作者vesperto
相关产品推荐
相关产品推荐

