Share image using file provider android

Once this is done, we can remove the unnecessary dependencies and folders like “test” and “androidTest” folder. We can also remove the string.xml file. We can even remove the testing dependency from build.gradle of our library.

  
//testInstrumentationRunner
// "android.support.test.runner.AndroidJUnitRunner"
and
//testImplementation 'junit:junit:4.12'
//androidTestImplementation 'com.android.support.test:runner:1.0.2'
//androidTestImplementation
// 'com.android.support.test.espresso:espresso-core:3.0.2'

Please note that we need appcompat support library. The final build.gradle will be

  
apply plugin: 'com.android.library'

android {
compileSdkVersion 28

defaultConfig {
minSdkVersion 14
targetSdkVersion 28
versionCode 1
versionName "1.0"

testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"

}

buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
}

dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'com.android.support:appcompat-v7:28.0.0'
}

2. Define paths in xml file in native android

Create a new XML resource file with name provider_paths.xml in our library.


Share image using file provider android

replace the below code in the created provider_paths.xml file and save it.

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

3. Define Provider in Android manifest file.

Define Provider in the manifest.xml file of the library.

  
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.agrawalsuneet.unitysharing" >
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" / >
<application >
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="${applicationId}.provider"
android:exported="false"
android:grantUriPermissions="true" >
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/provider_paths" / >
</provider >
</application >
</manifest >

Please note that we are adding write external storage permission here only but you can add it in unity also. I added here so that we don’t miss it.

4. Export it as an Android archive file (.aar) from Android Studio

To export the aar file out of our library, run the below command in the terminal on our root folder of android project.

FileProvider is a special subclass of

<manifest>
   ...
   <application>
       ...
       <provider
           android:name="com.sample.MyFileProvider"
           android:authorities="com.mydomain.fileprovider"
           android:exported="false"
           android:grantUriPermissions="true">
           ...
       </provider>
       ...
   </application>
</manifest>
6 that facilitates secure sharing of files associated with an app by creating a
<manifest>
   ...
   <application>
       ...
       <provider
           android:name="com.sample.MyFileProvider"
           android:authorities="com.mydomain.fileprovider"
           android:exported="false"
           android:grantUriPermissions="true">
           ...
       </provider>
       ...
   </application>
</manifest>
7
<manifest>
   ...
   <application>
       ...
       <provider
           android:name="com.sample.MyFileProvider"
           android:authorities="com.mydomain.fileprovider"
           android:exported="false"
           android:grantUriPermissions="true">
           ...
       </provider>
       ...
   </application>
</manifest>
8 for a file instead of a
<manifest>
   ...
   <application>
       ...
       <provider
           android:name="com.sample.MyFileProvider"
           android:authorities="com.mydomain.fileprovider"
           android:exported="false"
           android:grantUriPermissions="true">
           ...
       </provider>
       ...
   </application>
</manifest>
9
<manifest>
   ...
   <application>
       ...
       <provider
           android:name="com.sample.MyFileProvider"
           android:authorities="com.mydomain.fileprovider"
           android:exported="false"
           android:grantUriPermissions="true">
           ...
       </provider>
       ...
   </application>
</manifest>
8.

A content URI allows you to grant read and write access using temporary access permissions. When you create an

<paths xmlns:android="http://schemas.android.com/apk/res/android">
   <files-path name="my_images" path="images/"/>
   ...
</paths>
1 containing a content URI, in order to send the content URI to a client app, you can also call
<paths xmlns:android="http://schemas.android.com/apk/res/android">
   <files-path name="my_images" path="images/"/>
   ...
</paths>
2 to add permissions. These permissions are available to the client app for as long as the stack for a receiving
<paths xmlns:android="http://schemas.android.com/apk/res/android">
   <files-path name="my_images" path="images/"/>
   ...
</paths>
3 is active. For an
<paths xmlns:android="http://schemas.android.com/apk/res/android">
   <files-path name="my_images" path="images/"/>
   ...
</paths>
1 going to a
<paths xmlns:android="http://schemas.android.com/apk/res/android">
   <files-path name="my_images" path="images/"/>
   ...
</paths>
5, the permissions are available as long as the
<paths xmlns:android="http://schemas.android.com/apk/res/android">
   <files-path name="my_images" path="images/"/>
   ...
</paths>
5 is running.

In comparison, to control access to a

<manifest>
   ...
   <application>
       ...
       <provider
           android:name="com.sample.MyFileProvider"
           android:authorities="com.mydomain.fileprovider"
           android:exported="false"
           android:grantUriPermissions="true">
           ...
       </provider>
       ...
   </application>
</manifest>
9
<manifest>
   ...
   <application>
       ...
       <provider
           android:name="com.sample.MyFileProvider"
           android:authorities="com.mydomain.fileprovider"
           android:exported="false"
           android:grantUriPermissions="true">
           ...
       </provider>
       ...
   </application>
</manifest>
8 you have to modify the file system permissions of the underlying file. The permissions you provide become available to any app, and remain in effect until you change them. This level of access is fundamentally insecure.

The increased level of file access security offered by a content URI makes FileProvider a key part of Android's security infrastructure.

This overview of FileProvider includes the following topics:

  1. Defining a FileProvider
  2. Specifying Available Files
  3. Generating the Content URI for a File
  4. Granting Temporary Permissions to a URI
  5. Serving a Content URI to Another App

Defining a FileProvider

Extend FileProvider with a default constructor, and call super with an XML resource file that specifies the available files (see below for the structure of the XML file):

public class MyFileProvider extends FileProvider {
   public MyFileProvider() {
       super(R.xml.file_paths)
   }
}
Add a
<paths xmlns:android="http://schemas.android.com/apk/res/android">
   <files-path name="my_images" path="images/"/>
   ...
</paths>
9 element to your app manifest. Set the
<files-path name="name" path="path" />
0 attribute to the FileProvider you created. Set the
<files-path name="name" path="path" />
1 attribute to a URI authority based on a domain you control; for example, if you control the domain
<files-path name="name" path="path" />
2 you should use the authority
<files-path name="name" path="path" />
3. Set the
<files-path name="name" path="path" />
4 attribute to
<files-path name="name" path="path" />
5; the FileProvider does not need to be public. Set the android:grantUriPermissions attribute to
<files-path name="name" path="path" />
6, to allow you to grant temporary access to files. For example:
<manifest>
   ...
   <application>
       ...
       <provider
           android:name="com.sample.MyFileProvider"
           android:authorities="com.mydomain.fileprovider"
           android:exported="false"
           android:grantUriPermissions="true">
           ...
       </provider>
       ...
   </application>
</manifest>

It is possible to use FileProvider directly instead of extending it. However, this is not reliable and will causes crashes on some devices.

Specifying Available Files

A FileProvider can only generate a content URI for files in directories that you specify beforehand. To specify a directory, specify its storage area and path in XML, using child elements of the

<files-path name="name" path="path" />
7 element. For example, the following
<files-path name="name" path="path" />
8 element tells FileProvider that you intend to request content URIs for the
<files-path name="name" path="path" />
9 subdirectory of your private file area.

<paths xmlns:android="http://schemas.android.com/apk/res/android">
   <files-path name="my_images" path="images/"/>
   ...
</paths>

The

<files-path name="name" path="path" />
7 element must contain one or more of the following child elements:

  • <files-path name="name" path="path" />
    Represents files in the
    <cache-path name="name" path="path" />
    1 subdirectory of your app's internal storage area. This subdirectory is the same as the value returned by
    <cache-path name="name" path="path" />
    2.
  • <cache-path name="name" path="path" />
    Represents files in the cache subdirectory of your app's internal storage area. The root path of this subdirectory is the same as the value returned by
    <cache-path name="name" path="path" />
    3.
  • <external-path name="name" path="path" />
    Represents files in the root of the external storage area. The root path of this subdirectory is the same as the value returned by
    <cache-path name="name" path="path" />
    4.
  • <external-files-path name="name" path="path"
    />
    Represents files in the root of your app's external storage area. The root path of this subdirectory is the same as the value returned by
    <cache-path name="name" path="path" />
    5.
  • <external-cache-path name="name" path="path"
    />
    Represents files in the root of your app's external cache area. The root path of this subdirectory is the same as the value returned by
    <cache-path name="name" path="path" />
    6.
  • <external-media-path name="name" path="path"
    />
    Represents files in the root of your app's external media area. The root path of this subdirectory is the same as the value returned by the first result of
    <cache-path name="name" path="path" />
    7.

    Note: this directory is only available on API 21+ devices.

These child elements all use the same attributes:

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

    A URI path segment. To enforce security, this value hides the name of the subdirectory you're sharing. The subdirectory name for this value is contained in the

    <cache-path name="name" path="path" />
    9 attribute.

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

    The subdirectory you're sharing. While the

    <external-path name="name" path="path" />
    1 attribute is a URI path segment, the
    <cache-path name="name" path="path" />
    9 value is an actual subdirectory name. Notice that the value refers to a subdirectory, not an individual file or files. You can't share a single file by its file name, nor can you specify a subset of files using wildcards.

You must specify a child element of

<files-path name="name" path="path" />
7 for each directory that contains files for which you want content URIs. For example, these XML elements specify two directories:

public class MyFileProvider extends FileProvider {
   public MyFileProvider() {
       super(R.xml.file_paths)
   }
}
0

Put the

<files-path name="name" path="path" />
7 element and its children in an XML file in your project. For example, you can add them to a new file called
<external-path name="name" path="path" />
5. To link this file to the FileProvider, pass it to super() in the constructor for the FileProvider you defined above, add a element as a child of the
<external-path name="name" path="path" />
6 element that defines the FileProvider. Set the
<external-path name="name" path="path" />
7 element's "android:name" attribute to
<external-path name="name" path="path" />
8. Set the element's "android:resource" attribute to
<external-path name="name" path="path" />
9 (notice that you don't specify the
<external-files-path name="name" path="path"
/>
0 extension). For example:

public class MyFileProvider extends FileProvider {
   public MyFileProvider() {
       super(R.xml.file_paths)
   }
}
1

Generating the Content URI for a File

To share a file with another app using a content URI, your app has to generate the content URI. To generate the content URI, create a new

<external-files-path name="name" path="path"
/>
1 for the file, then pass the
<external-files-path name="name" path="path"
/>
1 to
<external-files-path name="name" path="path"
/>
3. You can send the content URI returned by
<external-files-path name="name" path="path"
/>
3 to another app in an
<paths xmlns:android="http://schemas.android.com/apk/res/android">
   <files-path name="my_images" path="images/"/>
   ...
</paths>
1. The client app that receives the content URI can open the file and access its contents by calling
<external-files-path name="name" path="path"
/>
6 to get a
<external-files-path name="name" path="path"
/>
7.

For example, suppose your app is offering files to other apps with a FileProvider that has the authority

<files-path name="name" path="path" />
3. To get a content URI for the file
<external-files-path name="name" path="path"
/>
9 in the
<files-path name="name" path="path" />
9 subdirectory of your internal storage add the following code:

public class MyFileProvider extends FileProvider {
   public MyFileProvider() {
       super(R.xml.file_paths)
   }
}
2As a result of the previous snippet,
<external-files-path name="name" path="path"
/>
3 returns the content URI
<external-cache-path name="name" path="path"
/>
2.

Granting Temporary Permissions to a URI

To grant an access permission to a content URI returned from

<external-files-path name="name" path="path"
/>
3, you can either grant the permission to a specific package or include the permission in an intent, as shown in the following sections.

Grant Permission to a Specific Package

Call the method

<external-cache-path name="name" path="path"
/>
4 for the
<manifest>
   ...
   <application>
       ...
       <provider
           android:name="com.sample.MyFileProvider"
           android:authorities="com.mydomain.fileprovider"
           android:exported="false"
           android:grantUriPermissions="true">
           ...
       </provider>
       ...
   </application>
</manifest>
7
<manifest>
   ...
   <application>
       ...
       <provider
           android:name="com.sample.MyFileProvider"
           android:authorities="com.mydomain.fileprovider"
           android:exported="false"
           android:grantUriPermissions="true">
           ...
       </provider>
       ...
   </application>
</manifest>
8, using the desired mode flags. This grants temporary access permission for the content URI to the specified package, according to the value of the the
<external-cache-path name="name" path="path"
/>
7 parameter, which you can set to
<external-cache-path name="name" path="path"
/>
8,
<external-cache-path name="name" path="path"
/>
9 or both. The permission remains in effect until you revoke it by calling
<external-media-path name="name" path="path"
/>
0 or until the device reboots.

Include the Permission in an Intent

To allow the user to choose which app receives the intent, and the permission to access the content, do the following:

  1. Put the content URI in an
    <paths xmlns:android="http://schemas.android.com/apk/res/android">
       <files-path name="my_images" path="images/"/>
       ...
    </paths>
    
    1 by calling
    <external-media-path name="name" path="path"
    />
    2.
  2. Call the method

    <paths xmlns:android="http://schemas.android.com/apk/res/android">
       <files-path name="my_images" path="images/"/>
       ...
    </paths>
    
    2 with either
    <external-cache-path name="name" path="path"
    />
    8 or
    <external-cache-path name="name" path="path"
    />
    9 or both.

    To support devices that run a version between Android 4.1 (API level 16) and Android 5.1 (API level 22) inclusive, create a

    <external-media-path name="name" path="path"
    />
    6 object from the content URI, and set the access permissions on the
    <external-media-path name="name" path="path"
    />
    7 object:

    public class MyFileProvider extends FileProvider {
       public MyFileProvider() {
           super(R.xml.file_paths)
       }
    }
    
    3
  3. Send the
    <paths xmlns:android="http://schemas.android.com/apk/res/android">
       <files-path name="my_images" path="images/"/>
       ...
    </paths>
    
    1 to another app. Most often, you do this by calling
    <external-media-path name="name" path="path"
    />
    9.

Permissions granted in an

<paths xmlns:android="http://schemas.android.com/apk/res/android">
   <files-path name="my_images" path="images/"/>
   ...
</paths>
1 remain in effect while the stack of the receiving
<paths xmlns:android="http://schemas.android.com/apk/res/android">
   <files-path name="my_images" path="images/"/>
   ...
</paths>
3 is active. When the stack finishes, the permissions are automatically removed. Permissions granted to one
<paths xmlns:android="http://schemas.android.com/apk/res/android">
   <files-path name="my_images" path="images/"/>
   ...
</paths>
3 in a client app are automatically extended to other components of that app.

Serving a Content URI to Another App

There are a variety of ways to serve the content URI for a file to a client app. One common way is for the client app to start your app by calling

public class MyFileProvider extends FileProvider {
   public MyFileProvider() {
       super(R.xml.file_paths)
   }
}
03, which sends an
<paths xmlns:android="http://schemas.android.com/apk/res/android">
   <files-path name="my_images" path="images/"/>
   ...
</paths>
1 to your app to start an
<paths xmlns:android="http://schemas.android.com/apk/res/android">
   <files-path name="my_images" path="images/"/>
   ...
</paths>
3 in your app. In response, your app can immediately return a content URI to the client app or present a user interface that allows the user to pick a file. In the latter case, once the user picks the file your app can return its content URI. In both cases, your app returns the content URI in an
<paths xmlns:android="http://schemas.android.com/apk/res/android">
   <files-path name="my_images" path="images/"/>
   ...
</paths>
1 sent via
<external-media-path name="name" path="path"
/>
9.

You can also put the content URI in a

<external-media-path name="name" path="path"
/>
6 object and then add the object to an
<paths xmlns:android="http://schemas.android.com/apk/res/android">
   <files-path name="my_images" path="images/"/>
   ...
</paths>
1 you send to a client app. To do this, call
public class MyFileProvider extends FileProvider {
   public MyFileProvider() {
       super(R.xml.file_paths)
   }
}
10. When you use this approach, you can add multiple
<external-media-path name="name" path="path"
/>
6 objects to the
<paths xmlns:android="http://schemas.android.com/apk/res/android">
   <files-path name="my_images" path="images/"/>
   ...
</paths>
1, each with its own content URI. When you call
<paths xmlns:android="http://schemas.android.com/apk/res/android">
   <files-path name="my_images" path="images/"/>
   ...
</paths>
2 on the
<paths xmlns:android="http://schemas.android.com/apk/res/android">
   <files-path name="my_images" path="images/"/>
   ...
</paths>
1 to set temporary access permissions, the same permissions are applied to all of the content URIs.

Note: The

public class MyFileProvider extends FileProvider {
   public MyFileProvider() {
       super(R.xml.file_paths)
   }
}
10 method is only available in platform version 16 (Android 4.1) and later. If you want to maintain compatibility with previous versions, you should send one content URI at a time in the
<paths xmlns:android="http://schemas.android.com/apk/res/android">
   <files-path name="my_images" path="images/"/>
   ...
</paths>
1. Set the action to
public class MyFileProvider extends FileProvider {
   public MyFileProvider() {
       super(R.xml.file_paths)
   }
}
17 and put the URI in data by calling
<external-media-path name="name" path="path"
/>
2.

More Information

To learn more about FileProvider, see the Android training class Sharing Files Securely with URIs.

Summary

Public constructors

public class MyFileProvider extends FileProvider {
   public MyFileProvider() {
       super(R.xml.file_paths)
   }
}
19

Protected constructors

public class MyFileProvider extends FileProvider {
   public MyFileProvider() {
       super(R.xml.file_paths)
   }
}
20

Public methods

public class MyFileProvider extends FileProvider {
   public MyFileProvider() {
       super(R.xml.file_paths)
   }
}
21

public class MyFileProvider extends FileProvider {
   public MyFileProvider() {
       super(R.xml.file_paths)
   }
}
22

After the FileProvider is instantiated, this method is called to provide the system with information about the provider.

public class MyFileProvider extends FileProvider {
   public MyFileProvider() {
       super(R.xml.file_paths)
   }
}
23

public class MyFileProvider extends FileProvider {
   public MyFileProvider() {
       super(R.xml.file_paths)
   }
}
24

Deletes the file associated with the specified content URI, as returned by

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

public class MyFileProvider extends FileProvider {
   public MyFileProvider() {
       super(R.xml.file_paths)
   }
}
26

public class MyFileProvider extends FileProvider {
   public MyFileProvider() {
       super(R.xml.file_paths)
   }
}
27

Returns the MIME type of a content URI returned by

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

public class MyFileProvider extends FileProvider {
   public MyFileProvider() {
       super(R.xml.file_paths)
   }
}
29

public class MyFileProvider extends FileProvider {
   public MyFileProvider() {
       super(R.xml.file_paths)
   }
}
30

Return a content URI for a given

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

public class MyFileProvider extends FileProvider {
   public MyFileProvider() {
       super(R.xml.file_paths)
   }
}
32

public class MyFileProvider extends FileProvider {
   public MyFileProvider() {
       super(R.xml.file_paths)
   }
}
33

Return a content URI for a given

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

<manifest>
   ...
   <application>
       ...
       <provider
           android:name="com.sample.MyFileProvider"
           android:authorities="com.mydomain.fileprovider"
           android:exported="false"
           android:grantUriPermissions="true">
           ...
       </provider>
       ...
   </application>
</manifest>
8

public class MyFileProvider extends FileProvider {
   public MyFileProvider() {
       super(R.xml.file_paths)
   }
}
36

By default, this method throws an

public class MyFileProvider extends FileProvider {
   public MyFileProvider() {
       super(R.xml.file_paths)
   }
}
37. You must subclass FileProvider if you want to provide different functionality.

How to share file using file provider in Android?

To make FileProvider work follow these three steps: Define the FileProvider in your AndroidManifest file. Create an XML file that contains all paths that the FileProvider will share with other applications. Bundle a valid URI in the Intent and activate it.

What is file provider in Android?

FileProvider is a special subclass of ContentProvider that facilitates secure sharing of files associated with an app by creating a content:// Uri for a file instead of a file:/// Uri . A content URI allows you to grant read and write access using temporary access permissions.

How to send image with intent in android?

Share Image and Text using android Intent.
val sendIntent = Intent() sendIntent.action = Intent.ACTION_SEND. sendIntent.putExtra( ... .
fun shareImageFromURI(url: String?) { Picasso.get().load(url).into(object : Target { override fun onBitmapLoaded(bitmap: Bitmap?, ... .
fun getBitmapFromView(bmp: Bitmap?): Uri? { var bmpUri: Uri? =.