基于Android FileProvider 属性配置详解及FileProvider多节点问题

所属分类: 软件编程 / Android 阅读数: 97
收藏 0 赞 0 分享

众所周知在android7.0,修改了对私有存储的限制,导致在获取资源的时候,不能通过Uri.fromFile来获取uri了我们需要适配7.0+的机型需要这样写:

1:代码适配

 if (Build.VERSION.SDK_INT > 23) {//
        intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
        Uri contentUri = FileProvider.getUriForFile(context, SysInfo.packageName + ".fileProvider", outputFile);
        intent.setDataAndType(contentUri, "application/vnd.android.package-archive");
      } else {
        intent.setDataAndType(Uri.fromFile(outputFile), "application/vnd.android.package-archive");
      }

2:创建provider_paths.xml

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
  <!-- /storage/emulated/0/Download/${applicationId}/.beta/apk-->
  <external-path name="beta_external_path" path="Download/"/>
  <!--/storage/emulated/0/Android/data/${applicationId}/files/apk/-->
  <external-path name="beta_external_files_path" path="Android/data/"/>
 
</paths>

其中 provider_path属性详解

name和path

name:uri路径片段。为了执行安全,这个值隐藏你所共享的子目录名。此值的子目录名包含在路径属性中。

path:你所共享的子目录。虽然name属性是一个URI路径片段,但是path是一个真实的子目录名。注意,path是一个子目录,而不是单个文件或者多个文件。

1.files-path

代表与Context.getFileDir()相同的文件路径

2.cache-path

<cache-path name="name" path="path" />

代表与getCacheDir()相同的文件路径

3.external-path

<external-path name="name" path="path" />

代表与Environment.getExternalStorageDirectory()相同的文件路径

4.external-files-path

<external-files-path name="name" path="path" />

代表与Context#getExternalFilesDir(String) 和Context.getExternalFilesDir(null)相同的文件路径

5.external-cache-path

<external-cache-path name="name" path="path" />

代表与Context.getExternalCacheDir()相同的文件路径

6:配置AndroidManifest.xml

android:authorities在FileProvider中使用

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

7:使用FileProvider

*** 返回URI:content://com.mydomain.fileprovider/my_images/default_image.jpg.

File imagePath = new File(Context.getFilesDir(), "images"); 
File newFile = new File(imagePath, "default_image.jpg"); 
Uri contentUri = getUriForFile(getContext(), "com.mydomain.fileprovider", newFile); 

8.自定义FileProvider


class MyFileProvider extends FileProvider {}

AndroidMenifest.xml中配置 android:authorities即可

3:我们项目中可能会用到其他一些第三方sdk有用到拍照功能的话,他也为了适配android7.0也添加了这个节点,此时有些人可能就不知道如何下手了,其实很简单我们只要重写一个类 继承自FileProvider,然后就按上述方法在添加一个节点就可以了:

<provider
  android:name="com.blueZhang.MyFileProvider"
  android:authorities="${applicationId}.provider"
  android:grantUriPermissions="true"
  android:exported="false">
  <meta-data
    android:name="android.support.FILE_PROVIDER_PATHS"
    android:resource="@xml/cust_file_paths" />
</provider>

如果你不想自定义FileProvider,那么还有一种方法,那就是把第三方sdk中的路径配置copy到provider_paths.xml即可。

如下所示:

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
  <!-- /storage/emulated/0/Download/${applicationId}/.beta/apk-->
  <external-path name="beta_external_path" path="Download/"/>
  <!--/storage/emulated/0/Android/data/${applicationId}/files/apk/-->
  <external-path name="beta_external_files_path" path="Android/data/"/>
 
  <external-path name="external_storage_root" path="."/>
  <files-path name="files" path="."/>
 
</paths>

注意⚠️:在使用provider时 配置路径 path="."代表所有路径

生成 Content URI

在 Android 7.0 出现之前,我们通常使用 Uri.fromFile() 方法生成一个 File URI。这里,我们需要使用 FileProvider 类提供的公有静态方法 getUriForFile 生成 Content URI。

比如:

Uri contentUri = FileProvider.getUriForFile(this,
BuildConfig.APPLICATION_ID + ".fileProvider", myFile);


需要传递三个参数。第二个参数便是 Manifest 文件中注册 FileProvider 时设置的 authorities 属性值,第三个参数为要共享的文件,并且这个文件一定位于第二步我们在 path 文件中添加的子目录里面。

举个例子:

String filePath = Environment.getExternalStorageDirectory() + "/images/"+System.currentTimeMillis()+".jpg";
File outputFile = new File(filePath);
if (!outputFile.getParentFile().exists()) {
  outputFile.getParentFile().mkdir();
}
Uri contentUri = FileProvider.getUriForFile(this,
    BuildConfig.APPLICATION_ID + ".fileProvider", outputFile);

生成的 Content URI 是这样的:

content://com.yifeng.samples.myprovider/my_images/1493715330339.jpg

其中,构成 URI 的 host 部分为 <provider> 元素的 authorities 属性值(applicationId + customname),path 片段 my_images 为 res/xml 文件中指定的子目录别名(真实目录名为:images)。

第四步,授予 Content URI 访问权限

生成 Content URI 对象后,需要对其授权访问权限。授权方式有两种:

第一种方式,使用 Context 提供的 grantUriPermission(package, Uri, mode_flags) 方法向其他应用授权访问 URI 对象。三个参数分别表示授权访问 URI 对象的其他应用包名,授权访问的 Uri 对象,和授权类型。其中,授权类型为 Intent 类提供的读写类型常量:

FLAG_GRANT_READ_URI_PERMISSION

FLAG_GRANT_WRITE_URI_PERMISSION

或者二者同时授权。这种形式的授权方式,权限有效期截止至发生设备重启或者手动调用 revokeUriPermission() 方法撤销授权时。

第二种方式,配合 Intent 使用。通过 setData() 方法向 intent 对象添加 Content URI。然后使用 setFlags() 或者 addFlags() 方法设置读写权限,可选常量值同上。这种形式的授权方式,权限有效期截止至其它应用所处的堆栈销毁,并且一旦授权给某一个组件后,该应用的其它组件拥有相同的访问权限。

第五步,提供 Content URI 给其它应用

拥有授予权限的 Content URI 后,便可以通过 startActivity() 或者 setResult() 方法启动其他应用并传递授权过的 Content URI 数据。当然,也有其他方式提供服务。

如果你需要一次性传递多个 URI 对象,可以使用 intent 对象提供的 setClipData() 方法,并且 setFlags() 方法设置的权限适用于所有 Content URIs。

常见使用场景

前面介绍的内容都是理论部分,在 开发者官方 FileProvider 部分 都有所介绍。接下来我们看看,实际开发一款应用的过程中,会经常遇见哪些 FileProvider 的使用场景。

自动安装文件

版本更新完成时打开新版本 apk 文件实现自动安装的功能,应该是最常见的使用场景,也是每个应用必备功能之一。常见操作为,通知栏显示下载新版本完毕,用户点击或者监听下载过程自动打开新版本 apk 文件。适配 Android 7.0 版本之前,我们代码可能是这样:

File apkFile = new File(getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), "app_sample.apk");
 
Intent installIntent = new Intent(Intent.ACTION_VIEW);
installIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
installIntent.setDataAndType(Uri.fromFile(apkFile), "application/vnd.android.package-archive");
startActivity(installIntent)

现在为了适配 7.0 及以上版本的系统,必须使用 Content URI 代替 File URI。

在 res/xml 目录下新建一个 file_provider_paths.xml 文件(文件名自由定义),并添加子目录路径信息:

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
 
  <external-files-path name="my_download" path="Download"/>
 
</paths>

然后在 Manifest 文件中注册 FileProvider 对象,并链接上面的 path 路径文件:

<provider
  android:name="android.support.v4.content.FileProvider"
  android:authorities="com.yifeng.samples.myprovider"
  android:exported="false"
  android:grantUriPermissions="true">
 
  <meta-data
    android:name="android.support.FILE_PROVIDER_PATHS"
    android:resource="@xml/file_provider_paths"/>
 
</provider>

修改 java 代码,根据 File 对象生成 Content URI 对象,并授权访问:

File apkFile = new File(getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), "app_sample.apk");
Uri apkUri = FileProvider.getUriForFile(this,
    BuildConfig.APPLICATION_ID+".fileProvider", apkFile);
 
Intent installIntent = new Intent(Intent.ACTION_VIEW);
installIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
installIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
installIntent.setDataAndType(apkUri, "application/vnd.android.package-archive");
startActivity(installIntent);

好了 有不明白的 及时联系

以上这篇基于Android FileProvider 属性配置详解及FileProvider多节点问题就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持脚本之家。

更多精彩内容其他人还在看

Android网络编程之获取网络上的Json数据实例

这篇文章主要介绍了Android网络编程之获取网络上的Json数据实例,本文用完整的代码实例讲解了在Android中读取网络中Json数据的方法,需要的朋友可以参考下
收藏 0 赞 0 分享

Android中的windowSoftInputMode属性详解

这篇文章主要介绍了Android中的windowSoftInputMode属性详解,本文对windowSoftInputMode的9个属性做了详细总结,需要的朋友可以参考下
收藏 0 赞 0 分享

Android网络编程之UDP通信模型实例

这篇文章主要介绍了Android网络编程之UDP通信模型实例,本文给出了服务端代码和客户端代码,需要的朋友可以参考下
收藏 0 赞 0 分享

Android中使用ListView实现漂亮的表格效果

这篇文章主要介绍了Android中使用ListView实现漂亮的表格效果,本文用详细的代码实例创建了一个股票行情表格,需要的朋友可以参考下
收藏 0 赞 0 分享

Android中刷新界面的二种方法

这篇文章主要介绍了Android中刷新界面的二种方法,本文使用Handler、postInvalidate两种方法实现界面刷新,需要的朋友可以参考下
收藏 0 赞 0 分享

Android SDK三种更新失败及其解决方法

这篇文章主要介绍了Android SDK三种更新失败及其解决方法,需要的朋友可以参考下
收藏 0 赞 0 分享

Android学习笔记——Menu介绍(一)

Android3.0(API level 11)开始,Android设备不再需要专门的菜单键。随着这种变化,Android app应该取消对传统6项菜单的依赖。取而代之的是提供anction bar来提供基本的用户功能
收藏 0 赞 0 分享

Android学习笔记——Menu介绍(二)

这次将继续上一篇文章没有讲完的Menu的学习,上下文菜单(Context menu)和弹出菜单(Popup menu)
收藏 0 赞 0 分享

Android学习笔记——Menu介绍(三)

今天继续昨天没有讲完的Menu的学习,主要是Popup Menu的学习,需要的朋友可以参考下
收藏 0 赞 0 分享

Android显示网络图片实例

这篇文章主要介绍了Android显示网络图片的方法,以实例形式展示了Android程序显示网络图片的方法,非常具有实用价值,需要的朋友可以参考下
收藏 0 赞 0 分享
查看更多