解决 Android N 上报错:android.os.FileUriExposedException: file:///storage/emulated/0/

简介: 解决 Android N 上报错:android.os.FileUriExposedException: file:///storage/emulated/0/

解决android N文件访问crash android.os.FileUriExposedException file:///storage/emulated/0/xxx

原因:

Android N对访问文件权限收回,按照Android N的要求,若要在应用间共享文件,您应发送一项 content://URI,并授予 URI 临时访问权限。

而进行此授权的最简单方式是使用 FileProvider类。

解决方法:

1.在mainfest中加入FileProvider注册

<application>
 ......
     <provider
         android:authorities="你的应用名.fileprovider"
         android:name="android.support.v4.content.FileProvider"
         android:grantUriPermissions="true"
         android:exported="false">
         <meta-data
           android:name="android.support.FILE_PROVIDER_PATHS"
               android:resource="@xml/filepaths"/>
    </provider>
</application>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

2.配置filepaths文件

<?xml version="1.0" encoding="utf-8"?>
<paths>
    <external-path path="honjane/" name="files_path" />
</paths>
  • 1
  • 2
  • 3
  • 4

其中:

files-path代表的根目录: Context.getFilesDir()

external-path代表的根目录: Environment.getExternalStorageDirectory()

cache-path代表的根目录: getCacheDir()

<external-path path="honjane/" name="files_path" />
  • 1

path 代表要共享的目录

name 只是一个标示,随便取吧 自己看的懂就ok

举个栗子:通过provider获取到的uri链接

content://com.honjane.providerdemo.fileprovider/files_path/files/b7d4b092822da.pdf

name对应到链接中的files_path

path对应到链接中的 files ,当然files是在honjane/目录下

3.访问文件

 /**
     * 打开文件
     * 当手机中没有一个app可以打开file时会抛ActivityNotFoundException
     * @param context     activity
     * @param file        File
     * @param contentType 文件类型如:文本(text/html)     
     */
    public static void startActionFile(Context context, File file, String contentType) throws ActivityNotFoundException {
        if (context == null) {
            return;
        }
        Intent intent = new Intent(Intent.ACTION_VIEW);
        intent.addCategory(Intent.CATEGORY_DEFAULT);
        intent.setDataAndType(getUriForFile(context, file), contentType);
        if (!(context instanceof Activity)) {
            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        }
        context.startActivity(intent);
    }
    /**
     * 打开相机
     *
     * @param activity    Activity
     * @param file        File
     * @param requestCode result requestCode
     */
    public static void startActionCapture(Activity activity, File file, int requestCode) {
        if (activity == null) {
            return;
        }
        Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
        intent.putExtra(MediaStore.EXTRA_OUTPUT, getUriForFile(activity, file));
        activity.startActivityForResult(intent, requestCode);
    }
    private static Uri getUriForFile(Context context, File file) {
        if (context == null || file == null) {
            throw new NullPointerException();
        }
        Uri uri;
        if (Build.VERSION.SDK_INT >= 24) {
            uri = FileProvider.getUriForFile(context.getApplicationContext(), "你的应用名.fileprovider", file);
        } else {
            uri = Uri.fromFile(file);
        }
        return uri;
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48

同样访问相机相册都通过FileProvider.getUriForFile申请临时共享空间

已写成工具类上传到github,需要直接下载

使用方法简单,一行代码搞定

打开文件:

 try {
      FileUtils.startActionFile(this,path,mContentType);
    }catch (ActivityNotFoundException e){
 }
  • 1
  • 2
  • 3
  • 4
  • 5

调用相机:

 FileUtils.startActionCapture(this, file, requestCode);
  • 1

修复bug:

java.lang.IllegalArgumentException: Failed to find configured root that contains /storage/emulated/0/xxx/xxx/file/12b31d2cab6ed.pdf

external与storage/emulated/0/对应,乍一看貌似没什么问题,path设置的是external的根路径,对应Environment.getExternalStorageDirectory(),

然而这个方法所获取的只是内置SD卡的路径,所以当选择的相册中的图片是外置SD卡的时候,就查找不到图片地址了,因此便抛出了failed to find configured root that contains的错误。

通过分析FileProvider源码发现,在xml解析到对应的标签后,会执行 buildPath() 方法来将根标签(files-path,cache-path,external-path等)对应的路径作为文件根路径,

在buildPath(),会根据一些常量判断是构建哪个目录下的path,除了上面介绍的几种path外还有个TAG_ROOT_PATH = “root-path” ,只有当不是root-path时才会去构建其他path,

官方也没介绍这个root-path,测试了一下发现对应的是DEVICE_ROOT指向的整个存储的根路径,这个bug就修复了

修改filepaths文件:

<paths>
      <root-path name="honjane" path="" />
</paths>


相关文章
|
1月前
|
Android开发
Android JNI 报错(signal 6 (SIGABRT), code -1 (SI_QUEUE), fault addr )
Android JNI 报错(signal 6 (SIGABRT), code -1 (SI_QUEUE), fault addr )
157 1
|
10天前
|
搜索推荐 物联网 Linux
鸿蒙OS Next与安卓系统的比较
【6月更文挑战第2天】鸿蒙OS Next与安卓系统的比较
28 2
|
9天前
|
存储 Android开发 Kotlin
Kotlin开发安卓app,在使用 MediaPlayer 播放 res/raw 中的音乐时遇到突然中断的问题,而 onErrorListener 没有接收到任何报错
在使用 Android MediaPlayer 播放 res/raw 中的音乐时遇到中断问题,可能的原因包括资源问题、媒体文件编码格式、生命周期管理和设备资源配置。要排查问题,检查音频文件是否正确包含,格式编码是否支持,MediaPlayer 是否正确管理及释放,以及设备是否有足够存储和配置。通过设置 onErrorListener 日志和确保在 onDestroy 中释放资源来调试。如果文件过大,考虑使用 AssetManager。遵循这些步骤可帮助诊断并解决播放中断的问题。
|
1月前
|
XML API Android开发
android S 上 安装apk出现android.os.FileUriExposedException
android S 上 安装apk出现android.os.FileUriExposedException
42 6
|
15天前
|
Shell Go 开发工具
How to decompile Google Android .apk file as readable dump【原创】
How to decompile Google Android .apk file as readable dump【原创】
10 0
|
1月前
|
安全 编译器 API
Android HAL深入探索(5): 调试HAL报错与解决方案
Android HAL深入探索(5): 调试HAL报错与解决方案
168 1
|
1月前
|
API Android开发
Android Framework增加API 报错 Missing nullability on parameter
Android Framework增加API 报错 Missing nullability on parameter
53 1
|
1月前
|
Android开发 开发者
安卓投屏神器 Scrcpy安 报错ERROR: Could not find any ADB device
安卓投屏神器 Scrcpy安 报错ERROR: Could not find any ADB device
285 9
|
1月前
|
缓存 Java Android开发
Android 9.0 WiFi 扫描结果上报和获取流程
Android 9.0 WiFi 扫描结果上报和获取流程
31 0
|
1月前
|
编译器 Android开发
Android S内置APK时AndroidManifest使用uses-library编译报错
Android S内置APK时AndroidManifest使用uses-library编译报错
24 0