Android 10 如何在Documents/MyFolder下创建SQLite数据库
Android 10 该场景适配结论
你拿到的/tree/home:/document/home:MyFolder是存储访问框架(SAF)返回的内容URI路径,不是Linux文件系统的真实路径,直接拼接字符串传给openOrCreateDatabase、或者用File类校验必然失败。
先直接回答你的两个疑问:
- Android 10 强制启用分区存储,且没有提供Android 11才有的全局文件访问权限(MANAGE_EXTERNAL_STORAGE),在没有特殊配置的前提下,就算你知道文件夹真实存储路径是
/storage/emulated/0/Documents/MyFolder,也没有权限直接通过File类访问。 - 不要尝试从SAF返回的URI中解析真实文件路径:不同厂商ROM的URI格式不统一,就算解析出真实路径,你也没有该路径的访问权限,这条路完全走不通。
可行适配方案
方案1:合规SAF实现(无特殊权限要求,适配成本中等)
不要取URI的path字段拼接路径,直接通过DocumentFile在目标目录下创建数据库文件,再通过ContentResolver获取文件描述符打开SQLite数据库,参考实现:
// 在ActivityResult回调中,判断RESULT_OK之后 Uri treeUri = result.getData().getData(); // 首先持久化URI权限,否则应用重启后权限会失效 int takeFlags = result.getData().getFlags() & (Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION); mContext.getContentResolver().takePersistableUriPermission(treeUri, takeFlags); DocumentFile pickedDir = DocumentFile.fromTreeUri(mContext, treeUri); DocumentFile newDir = pickedDir.findFile("MyFolder"); if (newDir == null) { newDir = pickedDir.createDirectory("MyFolder"); } // 查找或创建数据库文件 DocumentFile dbFile = newDir.findFile("MyDatabase.sqlite"); if (dbFile == null) { dbFile = newDir.createFile("application/x-sqlite3", "MyDatabase.sqlite"); } // 通过文件描述符打开数据库 try (ParcelFileDescriptor pfd = mContext.getContentResolver().openFileDescriptor(dbFile.getUri(), "rw")) { mDb = SQLiteDatabase.openDatabase(pfd.getFileDescriptor(), null, SQLiteDatabase.OPEN_READWRITE); } catch (Exception e) { Log.e(TAG, "数据库打开失败", e); }
注意:通过该方式打开的数据库,不要做任何依赖文件路径的操作,所有数据库操作直接使用返回的
SQLiteDatabase实例即可。
方案2: legacy兼容模式(老项目快速适配,成本最低)
如果老项目改造成本过高,可以在AndroidManifest.xml的<application>标签下添加如下配置:
android:requestLegacyExternalStorage="true"
该配置会在Android 10系统上临时关闭分区存储,你可以沿用旧版本逻辑,直接使用真实文件路径/storage/emulated/0/Documents/MyFolder/MyDatabase.sqlite调用openOrCreateDatabase,不需要修改原有数据库逻辑。
提示:该配置在Android 11及以上系统会被自动忽略,你已经完成Android 11+的全路径访问适配的话,只要加版本判断逻辑,不会影响高版本系统的运行表现。
避坑说明
- 不要使用网上流传的各类「URI转真实路径」工具类:这类方法在Android 10+上要么解析出的路径错误,要么解析后没有访问权限,没有实际使用价值。
- 使用SAF方案必须调用
takePersistableUriPermission持久化权限,否则应用重启后之前获取的URI会直接报权限错误。 - Android 10没有开放全文件访问权限的申请入口,不要尝试在Android 10上适配MANAGE_EXTERNAL_STORAGE权限,该权限仅在Android 11及以上系统生效。
内容的提问来源于stack exchange,提问作者SparkyNZ
相关产品推荐
相关产品推荐

