You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android API≥24下FileProvider使用报错及解决方案问询

解决Android API≥24下的FileProvider和DownloadManager兼容性问题

我来帮你逐个搞定这两个头疼的兼容性问题:


一、FileProvider抛出IllegalArgumentException(找不到配置根目录)

从报错日志里能看到路径变成了/file:/storage/emulated/0/Images/IMAGE_xxx.jpg——这明显是多了个file://前缀搞出来的问题!你在调用FileProvider.getUriForFile时,错误地把file://和已有的File对象路径拼接成了新的File,可File本身就代表本地文件路径,完全不需要加这个前缀。

修正后的FileProvider代码:

if(vid.equals("")) {
    inFileName = img.substring(img.lastIndexOf('/') + 1);
    File sdcard = Environment.getExternalStorageDirectory();
    File filex = new File(sdcard, inDir + "/" + "IMAGE_" + inFileName);
    if(filex.exists()) {
        if (inDialog.isShowing()) inDialog.dismiss();
        // 直接传入已有的filex对象,不要画蛇添足加file://前缀
        Uri uri = FileProvider.getUriForFile(
            inContext, 
            inContext.getApplicationContext().getPackageName() + ".provider", 
            filex
        );
        Intent i = new Intent(Intent.ACTION_VIEW);
        i.setDataAndType(uri, "image/*");
        i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        i.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
        inContext.startActivity(i);
    } else {
        inTmp = Uri.parse(img);
        Image_DownloadId = DownloadData(inTmp, "IMAGE_" + inFileName);
    }
}

还要确认FileProvider的XML配置是否正确

如果还没配置,先在res/xml下创建file_paths.xml:

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <!-- 对应外部存储根目录,匹配你代码里的Environment.getExternalStorageDirectory() -->
    <external-path name="external_files" path="."/>
</paths>

然后在AndroidManifest.xml里注册FileProvider:

<provider
    android:name="androidx.core.content.FileProvider"
    android:authorities="${applicationId}.provider"
    android:exported="false"
    android:grantUriPermissions="true">
    <meta-data
        android:name="android.support.FILE_PROVIDER_PATHS"
        android:resource="@xml/file_paths"/>
</provider>

注意:如果你用的是旧版support库,把provider name改成android.support.v4.content.FileProvider即可。


二、BroadcastReceiver中DownloadManager.COLUMN_LOCAL_FILENAME弃用引发SecurityException

从Android Q(API 29)开始,直接读取COLUMN_LOCAL_FILENAME会触发权限异常,官方推荐用COLUMN_LOCAL_URI获取文件Uri,通过ContentResolver来操作,或者直接用这个Uri构建Intent。

修正后的BroadcastReceiver代码:

BroadcastReceiver downloadReceiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
        long referenceId = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1);
        if(referenceId == Image_DownloadId) {
            DownloadManager.Query ImageDownloadQuery = new DownloadManager.Query();
            ImageDownloadQuery.setFilterById(Image_DownloadId);
            Cursor cursor = downloadManager.query(ImageDownloadQuery);
            if(cursor.moveToFirst()){
                // 替换弃用的COLUMN_LOCAL_FILENAME,改用COLUMN_LOCAL_URI获取文件Uri
                int uriIndex = cursor.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI);
                Uri fileUri = Uri.parse(cursor.getString(uriIndex));
                
                Intent i = new Intent();
                if(inTenTipe.equals("repost")) {
                    i.setAction(Intent.ACTION_SEND);
                    i.putExtra(Intent.EXTRA_STREAM, fileUri);
                    i.setType("image/*");
                    i.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
                }else {
                    i.setAction(Intent.ACTION_VIEW);
                    i.setDataAndType(fileUri, "image/*");
                    i.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
                }
                try {
                    if (inDialog.isShowing()) inDialog.dismiss();
                    // 非Activity上下文启动需要加这个flag
                    if (!(context instanceof Activity)) {
                        i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                    }
                    context.startActivity(i);
                } catch (android.content.ActivityNotFoundException ex) {
                    // 根据系统版本选择文件删除方式,适配Android Q+的存储权限
                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
                        context.getContentResolver().delete(fileUri, null, null);
                    } else {
                        File file = new File(fileUri.getPath());
                        boolean deleted = file.delete();
                    }
                    Image_DownloadId = DownloadData(inTmp, "IMAGE_" + inFileName);
                }
            }
            // 别忘了关闭Cursor,避免内存泄漏
            cursor.close();
        }
    }
};

关键改动说明:

  1. 用COLUMN_LOCAL_URI替代COLUMN_LOCAL_FILENAME,直接获取文件Uri,绕开本地路径的权限限制;
  2. 给Intent添加FLAG_GRANT_READ_URI_PERMISSION,确保目标应用能读取这个Uri指向的文件;
  3. 适配Android Q+的存储规则,删除文件时用ContentResolver而非直接操作File;
  4. 新增Cursor关闭逻辑,避免内存泄漏。

内容的提问来源于stack exchange,提问作者Dany Hermawan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 03:40:52