Android不同API版本Activity关联.ctdb扩展名:API30+下载目录识别失败如何解决?
问题根源
Android 11(API 30)开始,Downloads目录下非系统标准MIME类型的文件,通过DownloadProvider返回的content URI默认采用content://com.android.providers.downloads.documents/document/msf:<文件ID>格式,这类URI的路径部分不携带原始文件名和后缀,你当前的intent filter依赖pathPattern匹配.ctdb后缀的规则自然失效。
私有目录、API 29及更低版本下载目录的文件返回的URI路径自带完整文件名和后缀,所以可以正常匹配。你观察到API 31下csv文件可以正常打开,是因为csv是系统已识别的标准MIME类型,DownloadProvider会返回带完整路径的raw:格式URI,而自定义后缀的ctdb文件系统无法识别,就返回了无路径的msf:格式URI。
解决方案
方案1:拆分intent filter规则
不要在同一个intent filter里同时声明file和content协议的匹配规则,拆成两个独立的filter分别处理:
- 针对
file协议的filter保留原有pathPattern匹配逻辑,适配本地文件路径场景 - 针对
content协议的filter移除所有pathPattern规则,改为通过MIME类型匹配
<!-- 处理file协议的文件请求 --> <intent-filter android:icon="@mipmap/ic_launcher" android:label="Import DB"> <action android:name="android.intent.action.VIEW" /> <category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.BROWSABLE" /> <data android:scheme="file" /> <data android:host="*" /> <data android:mimeType="*/*" /> <data android:pathPattern=".*\\.ctdb" /> <data android:pathPattern=".*\\..*\\.ctdb"/> <data android:pathPattern=".*\\..*\\..*\\.ctdb"/> <data android:pathPattern=".*\\..*\\..*\\..*\\.ctdb"/> <data android:pathPattern=".*\\..*\\..*\\..*\\..*\\.ctdb"/> <data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\.ctdb"/> <data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\.ctdb"/> <data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.ctdb"/> <data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.ctdb"/> </intent-filter> <!-- 处理content协议的文件请求 --> <intent-filter android:icon="@mipmap/ic_launcher" android:label="Import DB"> <action android:name="android.intent.action.VIEW" /> <category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.BROWSABLE" /> <data android:scheme="content" /> <data android:host="*" /> <data android:mimeType="application/octet-stream" /> </intent-filter>
方案2:Activity内增加文件后缀校验
放开content协议的MIME匹配后可能会接收到非ctdb文件的打开请求,需要在ImportDatabase的onCreate或onNewIntent方法中手动校验文件真实后缀:
// Java示例代码,Kotlin逻辑同理 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Uri fileUri = getIntent().getData(); if (fileUri == null) { finish(); return; } // 从content URI查询真实文件名 String fileName = null; Cursor cursor = getContentResolver().query(fileUri, new String[]{OpenableColumns.DISPLAY_NAME}, null, null, null); if (cursor != null && cursor.moveToFirst()) { fileName = cursor.getString(cursor.getColumnIndexOrThrow(OpenableColumns.DISPLAY_NAME)); cursor.close(); } // 校验后缀 if (fileName == null || !fileName.toLowerCase().endsWith(".ctdb")) { Toast.makeText(this, "仅支持ctdb格式的数据库文件", Toast.LENGTH_SHORT).show(); finish(); return; } // 后续执行正常的文件导入逻辑 }
方案3:申请特殊存储权限(不推荐)
如果你的应用属于文件管理类工具,可申请MANAGE_EXTERNAL_STORAGE特殊权限,申请后可以直接读取所有公共目录的文件完整路径,沿用原有匹配逻辑。但普通应用申请该权限无法通过Google Play上架审核,需要提供特殊用途说明。
内容的提问来源于stack exchange,提问作者Michael Kochiashvili

