Android 7.0 中 FileProvider空指针

java.lang.NullPointerException: Attempt to invoke virtual method 'android.content.res.XmlResourceParser android.content.pm.ProviderInfo.loadXmlMetaData(android.content.pm.PackageManager, java.lang.String)' on a null object reference

Android 7.0 中 FileProvider空指针_第1张图片

 具体原因:

为了提高私有目录的安全性,防止应用信息的泄漏,从 Android 7.0 开始,应用私有目录的访问权限被做限制。具体表现为,开发人员不能够再简单地通过 file:// URI 访问其他应用的私有目录文件或者让其他应用访问自己的私有目录文件。

备注:如果你对应用私有目录不太清楚的话,可以阅读我的这篇文章:了解 Android 应用的文件存储目录,掌握持久化数据的正确姿势。

同时,也是从 7.0 开始,Android SDK 中的 StrictMode 策略禁止开发人员在应用外部公开 file:// URI。具体表现为,当我们在应用中使用包含 file:// URI 的 Intent 离开自己的应用时,程序会发生故障。

开发中,如果我们在使用 file:// URI 时忽视了这两条规定,将导致用户在 7.0 及更高版本系统的设备中使用到相关功能时,出现 FileUriExposedException 异常,导致应用出现崩溃闪退问题。而这两个过程的替代解决方案便是使用 FileProvider。
 

解决方法:

第一步:在Androidmanifes.xml中注册一个FileProvider

在项目所在的AndroidManifest.xml里面注册一个provider:


        
    

第二步:在res/下面新建一个xml文件夹,添加共享目录就是上面注册的resource/的地址:

目录结构如下:

Android 7.0 中 FileProvider空指针_第2张图片

文件内容:



    
    
    

需要注意的是 path的填写和前面的external-path / external-cache-path 嘻嘻相关,具体关系如下:




    
    
    
    
    
    
    
    
    
    
    
    
    
    

path路径填写错误则会爆出以下错误:

java.lang.IllegalArgumentException: Failed to find configured root that contains /storage/emulated/0/Android/data/com.icfun.game.cn/cache/upgrade_apk/icfun_new.apk
        at android.support.v4.content.FileProvider$SimplePathStrategy.getUriForFile(FileProvider.java:738)

其实 cache-path-external 等价于 /storage/emulated/0/Android/data/com.icfun.game.cn/cache

例如:我只需要在path中写上upgrade_apk即可找到我的apk的文件路径了

第三步:代码中生成Content URI 使用:

                    Uri uri;
                    File file = new File(Uri.parse(downloadFileUrl).getPath());
                    if (file.exists()) {
                        if ((Build.VERSION.SDK_INT >= 24)) {//判读版本是否在7.0以上
                            uri = FileProvider.getUriForFile(context, "com.qushuru.fileprovide", file);
                        } else {
                            uri = Uri.parse(downloadFileUrl);
                        }
                        startInstall(context, uri);
private boolean startInstall(Context context, Uri uri) {
        Intent intent = new Intent();
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        intent.setAction(Intent.ACTION_VIEW);
        if ((Build.VERSION.SDK_INT >= 24)) {//判读版本是否在7.0以上
            intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); //添加这一句表示对目标应用临时授权该Uri所代表的文件
        }
        intent.setDataAndType(uri, "application/vnd.android.package-archive");
        context.startActivity(intent);
        return true;
    }

 

你可能感兴趣的:(Android)