适配API24+的Android永久应用数据存储目录方案咨询
适配API24+的SAF存储方案:统一Documents目录下应用文件夹实现
核心需求
应用因Google Play合规要求被迫接入SAF(存储访问框架),需兼容minSdkVersion24,目标是让用户选择卸载后不被删除的共享存储文件夹,且该文件夹需位于Documents目录下,方便跨设备文件互传。
现存问题
- Documents目录并非所有设备原生存在
- API变更导致原应用专属目录不可用
- Documents目录绝对路径随设备挂载方式变化,硬编码不可靠
当前分版本实现
API24-28
无共享存储访问限制,可直接创建并访问Documents目录:
File dir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS), appFolder);
API30+
共享存储受限,默认存在Documents目录,通过SAF引导用户选择,默认定位到Documents:
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE); intent.putExtra(DocumentsContract.EXTRA_INITIAL_URI, uriToLoad);
API29
无访问限制但getExternalStoragePublicDirectory()已废弃,无法直接创建Documents目录,当前只能让用户手动创建,体验极差。
不推荐的方案
- 方案a:提示用户手动创建Documents目录:操作繁琐,用户体验恶劣
- 方案b:硬编码
/Documents/appFolder并调用mkdirs():无法适配所有设备的挂载路径,兼容性风险高
推荐实现方案
1. API29专属兼容:通过MediaStore创建Documents目录
利用MediaStore在API29中创建Documents目录,避免用户手动操作:
ContentResolver resolver = getContentResolver(); Uri externalFilesUri = MediaStore.Files.getContentUri("external"); // 查询Documents目录是否存在 String selection = MediaStore.Files.FileColumns.RELATIVE_PATH + "=?"; String[] selectionArgs = {Environment.DIRECTORY_DOCUMENTS + "/"}; Cursor cursor = resolver.query(externalFilesUri, null, selection, selectionArgs, null); if (cursor == null || cursor.getCount() == 0) { // 创建Documents目录 ContentValues values = new ContentValues(); values.put(MediaStore.Files.FileColumns.RELATIVE_PATH, Environment.DIRECTORY_DOCUMENTS + "/"); values.put(MediaStore.Files.FileColumns.MIME_TYPE, "vnd.android.document/directory"); resolver.insert(externalFilesUri, values); } if (cursor != null) cursor.close();
创建完成后,再通过SAF打开该目录作为初始选项。
2. 全版本统一SAF交互逻辑
为保持体验一致,所有API24+版本均使用SAF选择目录,针对不同版本优化前置操作:
- API24-28:自动创建Documents及应用子目录,直接引导用户选择该目录
- API29:先通过上述MediaStore方法确保Documents存在,再启动SAF选择器
- API30+:直接默认定位到Documents目录供用户选择
3. 避免硬编码路径
始终使用系统常量Environment.DIRECTORY_DOCUMENTS获取相对路径,结合MediaStore或SAF的Uri进行操作,适配不同设备的挂载差异。
内容的提问来源于stack exchange,提问作者tuxdost
相关产品推荐
相关产品推荐

