> In all cases, the only secure way to offer a file from your app to another app is to send the receiving app the file's content URI and grant temporary access permissions to that URI.
If you want to share small amounts of text or numeric data between apps, you should send an Intent
that contains the data.
The AndroidFileProvider
component generates content URIs for files, based on specifications you provide in XML.
Note: The FileProvider
class is part of the v4 Support Library. For information about including this library in your application, see Support Library Setup.
<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>
>detect the selected file and get a content URI for it:
fileUri = FileProvider.getUriForFile( MainActivity.this, "com.example.myapp.fileprovider", requestFile);> set read permission for the file:
mResultIntent.addFlags( Intent.FLAG_GRANT_READ_URI_PERMISSION);
> Caution: Calling setFlags()
is the only way to securely grant access to your files using temporary access permissions. Avoid calling Context.grantUriPermission()
method for a file's content URI, since this method grants access that you can only revoke by calling Context.revokeUriPermission()
.
FileProvider
that generates content URIs for files in the
files/
directory of your app's internal storage or for files in subdirectories of
files/
. When your app generates a content URI for a file, it contains the authority specified in the
<provider>
element (
com.example.myapp.fileprovider
), the path
myimages/
, and the name of the file.
> Once you have set up your app to share files using content URIs, you can respond to other apps' requests for those files.
To set up the file selection Activity
, start by specifying the Activity
in your manifest, along with an intent filter that matches the action ACTION_PICK
and the categories CATEGORY_DEFAULT
and CATEGORY_OPENABLE
. Also add MIME type filters for the files your app serves to other apps. The following snippet shows you how to specify the new Activity
and intent filter:
<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>
if (fileUri != null) { ... // Put the Uri and MIME type in the result Intent mResultIntent.setDataAndType( fileUri, getContentResolver().getType(fileUri)); // Set the result MainActivity.this.setResult(Activity.RESULT_OK, mResultIntent); } else { mResultIntent.setDataAndType(null, ""); MainActivity.this.setResult(RESULT_CANCELED, mResultIntent); } }Provide users with an way to return immediately to the client app once they have chosen a file. One way to do this is to provide a checkmark or Done button. Associate a method with the button using the button's
android:onClick
attribute. In the method, call
finish()
.
> When an app wants to access a file shared by another app, the requesting app (the client) usually sends a request to the app sharing the files (the server). In most cases, the request starts an Activity
in the server app that displays the files it can share. The user picks a file, after which the server app returns the file's content URI to the client app.
The method openFileDescriptor()
returns a ParcelFileDescriptor
for the file. From this object, the client app gets a FileDescriptor
object, which it can then use to read the file.
> To get the data type of a shared file given its content URI, the client app calls ContentResolver.getType()
. This method returns the file's MIME type. By default, a FileProvider
determines the file's MIME type from its filename extension.
/* * Get the file's content URI from the incoming Intent, * then query the server app to get the file's display name * and size. */ Uri returnUri = returnIntent.getData(); Cursor returnCursor = getContentResolver().query(returnUri, null, null, null, null); /* * Get the column indexes of the data in the Cursor, * move to the first row in the Cursor, get the data, * and display it. */ int nameIndex = returnCursor.getColumnIndex(OpenableColumns.DISPLAY_NAME); int sizeIndex = returnCursor.getColumnIndex(OpenableColumns.SIZE); returnCursor.moveToFirst(); TextView nameView = (TextView) findViewById(R.id.filename_text); TextView sizeView = (TextView) findViewById(R.id.filesize_text); nameView.setText(returnCursor.getString(nameIndex)); sizeView.setText(Long.toString(returnCursor.getLong(sizeIndex)));