第八章 分享文件
app通常需要和其它的app分享文件,比如,一个图片查看器需要向一个图片编辑器分享图片,或者一个文件管理app可能允许用户复制粘贴到外部存储中。
一种方式就是向一个接收的app中发送分享的文件。
在所有的case中,从你的app中分享文件给其它的app安全可靠的一种方式是向接收的app分享文件的URI,并确保程序有对那个URI暂时的访问权限。只有暂时的访问的uri是安全的,因为他们只是暂时的给接收文件的app访问权限,这些权限会自动消除。Android的FileProvider部分提供一个getUriForFile()生成文件内容的URI。
如果你只是分享少量的文本或者数据信息,你应该使用Intent去做,就是之前的章节讲到的。
这篇文章讲述你的程序和其它的程序之间如何通过分享文件的uri,获取暂时的访问权限来分享数据,uri是通过FileProvider提供的。
第一节 设置文件分享
为了可以让你的app给其它的app提供文件,你应该配置Ixia你的app,可以让它提供一个文件的uri。 Android的FileProvider部分就可以基于你提供在xml的部分生成这样个uri,这篇文章教你这么添加一个默认的FileProvider实现到你的app中,怎么传输你你指定的文件。
FileProvider类是v4 Support Library的一部分
1. 指定FileProvider
定义一个FileProvider需要在你的manifest文件中增加入口,入口定了使用这个生成的uri的授权,而且指定了xml文件中哪个文件目录可以被分享。
下面的代码片段就是在manifest文件中加入<provider>元素来指定FileProvider类,授权,和xml文件名称。
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.myapp">
<application
...>
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="com.example.myapp.fileprovider"
android:grantUriPermissions="true"
android:exported="false">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/filepaths" />
</provider>
...
</application>
</manifest>
在这个例子中,android:authorities属性指定了uri的授权,在这个例子中,授权给"com.example.myapp.fileprovider".对于你自己的app来说,指定一个authority包括app的android:package 值,需要了解更多的audhority 值,请看Content URI章节。
<meta-data>元素提供了你想要分享的xml文件的目录,android:resoutce属性是文件的路径和文件的名称,文件的内容在下一个小节讲述。
2. 指定分享的目录
一旦你将FileProvider加入你的app 的manifest文件中,你需要指定文件中你想要分享的内容。为了分享文件的目录,在res/xml/文件目录下创建一个filepaths.xml目录。在这个文件中为每个目录增加一个xml元素,下面的程序代码片段就是在res/xml文件中增加filepath.xml的元素,这个片段也展示了如果分享/files目录下的内容。
<paths>
<files-path path="images/" name="myimages" />
</paths>
这个文件中通过path指定了文件的目录,
所以整个的文件uri名称就是
content://com.example.myapp.fileprovider/myimages/default_image.jpg
第二节 分享文件
一旦你建立你的文件内容分享uri,你就可以响应其它app的文件请求,一种方式是提供一个文件选择接口给其它的app调用。这种途径允许其它的app从服务端选择一个文件然后接收它的内容uri。
这篇文章教你在你的app中怎么创建一个文件选择的activity
1. 接收文件请求
建立你的文件选择Activity,先从你的Activity的manifest文件开始,你需要设置Action_PICK, CATEGORY_DEFAULT, CATEGORY_OPENABLE等内容,也需要在你的服务端app中加入mine类型,这下面的是创建一个带有intent filter的app.
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
...
<application>
...
<activity
android:name=".FileSelectActivity"
android:label="@File Selector" >
<intent-filter>
<action
android:name="android.intent.action.PICK"/>
<category
android:name="android.intent.category.DEFAULT"/>
<category
android:name="android.intent.category.OPENABLE"/>
<data android:mimeType="text/plain"/>
<data android:mimeType="image/*"/>
</intent-filter>
</activity>
2. 写文件选择Activity
public class MainActivity extends Activity {
// The path to the root of this app's internal storage
private File mPrivateRootDir;
// The path to the "images" subdirectory
private File mImagesDir;
// Array of files in the images subdirectory
File[] mImageFiles;
// Array of filenames corresponding to mImageFiles
String[] mImageFilenames;
// Initialize the Activity
@Override
protected void onCreate(Bundle savedInstanceState) {
...
// Set up an Intent to send back to apps that request a file
mResultIntent =
new Intent("com.example.myapp.ACTION_RETURN_FILE");
// Get the files/ subdirectory of internal storage
mPrivateRootDir = getFilesDir();
// Get the files/images subdirectory;
mImagesDir = new File(mPrivateRootDir, "images");
// Get the files in the images subdirectory
mImageFiles = mImagesDir.listFiles();
// Set the Activity's result to null to begin with
setResult(Activity.RESULT_CANCELED, null);
/*
* Display the file names in the ListView mFileListView.
* Back the ListView with the array mImageFilenames, which
* you can create by iterating through mImageFiles and
* calling File.getAbsolutePath() for each File
*/
...
}
...
}
3. 反馈文件选择
protected void onCreate(Bundle savedInstanceState) {
...
// Define a listener that responds to clicks on a file in the ListView
mFileListView.setOnItemClickListener(
new AdapterView.OnItemClickListener() {
@Override
/*
* When a filename in the ListView is clicked, get its
* content URI and send it to the requesting app
*/
public void onItemClick(AdapterView<?> adapterView,
View view,
int position,
long rowId) {
/*
* Get a File for the selected file name.
* Assume that the file names are in the
* mImageFilename array.
*/
File requestFile = new File(mImageFilename[position]);
/*
* Most file-related method calls need to be in
* try-catch blocks.
*/
// Use the FileProvider to get a content URI
try {
fileUri = FileProvider.getUriForFile(
MainActivity.this,
"com.example.myapp.fileprovider",
requestFile);
} catch (IllegalArgumentException e) {
Log.e("File Selector",
"The selected file can't be shared: " +
clickedFilename);
}
...
}
});
...
}
分享文件以后再写,以后再看,现在看没有理解没有用。
其中还包括
第三节 请求分享文件
第四节 获取文件信息
第二章 使用NFC分享文件
第一节 向其它设备发送文件
第二节 接收其它设备的文件