赞
踩
android 7.0及以上版本,应用私有目录被限制访问。此设置可防止私有文件的元数据泄漏,如它们的大小或存在性。此权限更改有多重副作用:比如 ,file:///URI可能给接收器留下无法访问的路径,推荐使用FileProvider。
FileProvider是ContentProvider的一个特殊子类,通过content://代替file:///,有助于安全地共享与应用程序相关联的文件。
Content URI授予读写访问权限用来允许您临时访问文件。当您创建包含内容URI的Intent时,为了将内容URI发送到客户端应用程序,还可以调用Intent.setFlags() 来添加权限。只要在堆栈中活跃的activity,这些权限就可用于客户端app。对于服务上的Intent,只要服务一直在运行,权限就处于可用状态。
相比之下,为了控制对文件的访问:feil:///URI,您必须修改底层文件的文件系统权限。您提供的权限对任何应用程序都可用,并在您更改它们之前保持有效。这种访问级别根本上是不安全的。
ContentURI 是提高android文件系统安全性的关键部分。
FileProvider程序包括以下内容:
由于FileProvider默认功能里包含了ContentURI的生成,所以不需要我们去定义。相反,您可以在XML中指定可用文件。要指定FileProvider组件本身,请将<provider>元素添加到您的应用清单。将android:name属性设置为android.support.v4.content.FileProvider。根据您控制的域将android:authority属性设置为URI权限;例如,如果您控制域mydomain.com,则应使用授权com.mydomain.fileprovider。将android:exported属性设置为false; FileProvider不需要公开。 将android:grantUriPermissions属性设置为true,以允许您授予对文件的临时访问权限。
例如:
- <manifest>
- ...
- <application>
- ...
- <provider
- android:name="android.support.v4.content.FileProvider"
- android:authorities="com.mydomain.fileprovider"
- android:exported="false"
- android:grantUriPermissions="true">
- ...
- </provider>
- ...
- </application>
- </manifest>
如果要覆盖FileProvider方法的任何默认行为,请扩展FileProvider类并在<provider>元素的android:name属性中使用完全限定的类名称。
FileProvider只能为您事先指定的目录中的文件生成内容URI。 要指定目录,请使用<paths>元素的子元素指定其存储区域和XML路径。 例如,以下路径元素告诉FileProvider您打算请求私有文件区域的images /子目录的内容URI。
- <paths xmlns:android="http://schemas.android.com/apk/res/android">
- <files-path name="my_images" path="images/"/>
- ...
- </paths>
<paths>元素必须包含一个或多个以下子元素:
<files-path name="name" path="path" />
代表应用程序内部存储区的files /子目录中的文件。 该子目录与Context.getFilesDir()返回的值相同。路径:eg:”/data/data/包名/files”。
<cache-path name="name" path="path" />
代表应用内部存储区的缓存子目录中的文件。 此子目录的根路径与getCacheDir()返回的值相同。路径:eg:“/data/data/包名/cache”。
<external-path name="name" path="path" />
代表外部存储区域根目录中的文件。 此子目录的根路径与Environment.getExternalStorageDirectory()返回的值相同。路径:eg:”/storage/emulated/0”。
<external-files-path name="name" path="path" />
代表应用外部存储区域根目录中的文件。 此子目录的根路径与Context#getExternalFilesDir(String)Context.getExternalFilesDir(null)返回的值相同。路径。eg:”/storage/emulated/0/Android/data/包名/files”。
<external-cache-path name="name" path="path" />
代表应用外部缓存区域根目录中的文件。 此子目录的根路径与Context.getExternalCacheDir()返回的值相同。路径。eg:”/storage/emulated/0/Android/data/包名/cache”。
<external-media-path name="name" path="path" />
代表应用外部媒体区域根目录中的文件。 此子目录的根路径与Context.getExternalMediaDirs()的第一个结果返回的值相同。
注意:此目录仅适用于API 21+设备。
这些子元素都使用相同的属性:
name="name"
一个URI路径段。 为了强制执行安全性,此值将隐藏您要共享的子目录的名称。 该值的子目录名称包含在路径属性中。
path="path"
你正在分享的子目录。 虽然name属性是一个URI路径段,但路径值是一个实际的子目录名称。 请注意,该值是指一个子目录,而不是单个文件或文件。 您无法通过文件名共享单个文件,也无法使用通配符指定文件的子集。
您必须为每个包含您需要内容URI的文件的目录指定<路径>的子元素。
例如,这些XML元素指定两个目录:
- <paths xmlns:android="http://schemas.android.com/apk/res/android">
- <files-path name="my_images" path="images/"/>
- <files-path name="my_docs" path="docs/"/>
- </paths>
将<paths>元素及其子元素放入项目中的XML文件中。 例如,您可以将它们添加到名为res / xml / file_paths.xml的新文件。 要将此文件链接到FileProvider,请将<meta-data>元素添加为定义FileProvider的<provider>元素的子元素。 将<meta-data>元素的“android:name”属性设置为android.support.FILE_PROVIDER_PATHS。 将元素的“android:resource”属性设置为@ xml / file_paths(请注意,您不指定.xml扩展名)。
例如,
- <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>
要使用内容URI与另一个应用程序共享文件,您的应用程序必须生成内容URI。 要生成内容URI,请为该文件创建一个新文件,然后将该文件传递给getUriForFile()。 您可以将getUriForFile()返回的内容URI发送到意图中的另一个应用程序。 接收内容URI的客户端应用程序可以通过调用ContentResolver.openFileDescriptor来获取ParcelFileDescriptor来打开文件并访问其内容。
例如,假设您的应用使用具有com.mydomain.fileprovider权限的FileProvider将文件提供给其他应用。 要在内部存储器的images /子目录中获取文件default_image.jpg的内容URI,请添加以下代码:
File imagePath = new File(Context.getFilesDir(), "images"); File newFile = new File(imagePath, "default_image.jpg"); Uri contentUri = getUriForFile(getContext(), "com.mydomain.fileprovider", newFile);
由于前面的代码片段,getUriForFile()返回内容URI的内容://com.mydomain.fileprovider/my_images/default_image.jpg
要为从getUriForFile()返回的内容URI授予访问权限,请执行以下操作:
有多种方式可以将文件的内容URI提供给客户端应用程序。 一种常见的方式是让客户端应用程序通过调用startActivityResult()来启动您的应用程序,该应用程序将Intent发送到您的应用程序以在您的应用程序中启动一个Activity。 作为响应,您的应用程序可以立即将内容URI返回给客户端应用程序,或者呈现允许用户选择文件的用户界面。 在后一种情况下,一旦用户选择文件,您的应用可以返回其内容URI。 在这两种情况下,您的应用都会通过setResult()发送Intent中的内容URI。
您也可以将内容URI放入ClipData对象中,然后将该对象添加到您发送给客户端应用程序的Intent中。 为此,请调用Intent.setClipData()。 当您使用这种方法时,您可以将多个ClipData对象添加到Intent,每个对象都有自己的内容URI。 当您调用Intent上的Intent.setFlags()以设置临时访问权限时,相同的权限将应用于所有内容URI。
注意:Intent.setClipData()方法仅在平台版本16(Android 4.1)及更高版本中可用。 如果您希望保持与以前版本的兼容性,您应该一次在意图中发送一个内容URI。 将操作设置为ACTION_SEND,并通过调用setData()将URI放入数据中。
要了解有关FileProvider的更多信息,请参阅使用URI安全的共享文件。
https://developer.android.com/reference/android/support/v4/content/FileProvider
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。