zoukankan      html  css  js  c++  java
  • FileProvider解决FileUriExposedException

    FileUriExposedException

    在给app做版本升级的时候,先从服务器下载新版本的apk文件到sdcard路径,然后调用安装apk的代码,一般写法如下:

    private void openAPK(String fileSavePath){
        File file=new File(fileSavePath);
        Intent intent = new Intent(Intent.ACTION_VIEW);
        Uri data = Uri.fromFile(file);
        intent.setDataAndType(data, "application/vnd.android.package-archive");
        startActivity(intent);
    }
    

    这样的写法在Android7.0版本之前是没有任何问题,只要给一个apk文件路径就能打开安装。但是在Android7.0版本上会报错:

     android.os.FileUriExposedException:
     file:///storage/emulated/0/Download/FileProvider.apk 
     exposed beyond app through Intent.getData()
    

    从Android 7.0开始,一个应用提供自身文件给其它应用使用时,如果给出一个file://格式的URI的话,应用会抛出FileUriExposedException。这是由于谷歌认为目标app可能不具有文件权限,会造成潜在的问题。所以让这一行为快速失败。

    FileProvider方式解决

    这是谷歌官方推荐的解决方案。即使用FileProvider来生成一个content://格式的URI。

    1.在Manifest.xml中声明一个provider。

    <application ···>
            ···
        <provider
            android:name="android.support.v4.content.FileProvider"
            android:authorities="com.ansen.fileprovider.fileprovider"
            android:grantUriPermissions="true"
            android:exported="false">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/file_paths" />
        </provider>
    </application>
    

    android:name值是固定的,android:authorities随便写但是必须得保证唯一性,我这边用的是包名+"fileprovider",android:grantUriPermission跟android:exported固定值。

    里面包含一个meta-data标签,这个标签的name属性固定写法,android:resource对应的是一个xml文件。我们在res文件夹下新建一个xml文件夹,在xml文件夹下新建file_paths.xml文件。内容如下:

    <?xml version="1.0" encoding="utf-8"?>
    <paths>
        <external-path name="name" path="Download"/>
    </paths>
    

    name表示生成URI时的别名,path是指相对路径。

    paths标签下的子元素一共有以下几种:

    files-path 对应  Context.getFilesDir()
    cache-path 对应  Context.getCacheDir()
    external-path 对应 Environment.getExternalStorageDirectory()
    external-files-path 对应  Context.getExternalFilesDir()
    external-cache-path 对应  Context.getExternalCacheDir()
    

    2.当然我们还需要修改打开apk文件的代码

    首先判断下版本号,如果手机操作系统版本号大于等于7.0就通过FileProvider.getUriForFile方法生成一个Uri对象。

    private void openAPK(String fileSavePath){
        File file=new File(fileSavePath);
        Intent intent = new Intent(Intent.ACTION_VIEW);
        Uri data;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {//判断版本大于等于7.0
            // "com.ansen.fileprovider.fileprovider"即是在清单文件中配置的authorities
            // 通过FileProvider创建一个content类型的Uri
            data = FileProvider.getUriForFile(this, "com.ansen.fileprovider.fileprovider", file);
            intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);// 给目标应用一个临时授权
        } else {
            data = Uri.fromFile(file);
        }
        intent.setDataAndType(data, "application/vnd.android.package-archive");
        startActivity(intent);
    }
    

    源码下载

    如果你想第一时间看我的后期文章,扫码关注公众号,每周不定期推送Android开发实战教程文章...

          Android开发666 - 安卓开发技术分享
                 扫描二维码加关注
    

    Android开发666

  • 相关阅读:
    Git Extensions system.invalidoperationexception尚未提供文件名,因此无法启动进程
    批处理将文件夹下的文件名称写入到一个文本里
    hdwiki 参考资料改成可点击跳转的(默认不能点)
    执行存储过程报错——ora-01031:权限不足
    Web Service——CXF发布REST服务
    Web Service——CXF+Spring 整合
    Web Service——CXF
    xmlhttp.readyState==4 && xmlhttp.status==200的探究
    XMLHttpRequest cannot load ...谷歌浏览器跨域问题
    Web Service基础——四种客户端调用方式
  • 原文地址:https://www.cnblogs.com/yishaochu/p/7488589.html
Copyright © 2011-2022 走看看