FileProvider authority in android library project

Viewed 3321

In a library project I'm using a FileProvider with my libraries applicationId as its authority. Now when somebody uses this library e.g. in two flavors of his app, the second one will not install because of conflicting FileProviders.

Goal

Being able to define a unique authority for my libraries FileProvider for each variant of an application.

First Approach

Im appending a random int to the authority, which works just fine.

build.gradle

static def generateContentProviderAuthority() {
    Random random = new Random()
    return new StringBuilder()
            .append("application.id.of.my.library")
            .append(".fileprovider")
            .append(String.valueOf(random.nextInt(100000)))
            .toString()
}


defaultConfig {
    ...
    manifestPlaceholders= [contentProviderAuthority: generateContentProviderAuthority()]
}

Manifest

<provider
    android:name=".helper.FileProvider"
    android:authorities="${contentProviderAuthority}"
    android:exported="false"
    android:grantUriPermissions="true">
    <meta-data
        android:name="android.support.FILE_PROVIDER_PATHS"
        android:resource="@xml/filepaths"/>
</provider>

But now the manifest changes every build, which messes with instant run and stuff...

Solution

Is it possible to get the exact applicationId of the application which uses the library in my libraries build.gradle?

2 Answers

As CommonsWare mentioned in the comment, it is enough to use dynamic ${applicationId} in the authorities section.

<provider
    android:name=".ScreenshotFileProvider"
    android:authorities="${applicationId}.library.name.screenshots"
    android:exported="false"
    android:grantUriPermissions="true">
    <meta-data
        android:name="android.support.FILE_PROVIDER_PATHS"
        android:resource="@xml/file_provider_paths"/>
</provider>

More thorough explanation at CommonsWare's blog: https://commonsware.com/blog/2017/06/27/fileprovider-libraries.html

In library manifest put code like below:

<provider
android:name="YOUR LIBRARY FILE PROVIDER CLASS"
android:authorities="${applicationId}.library.file.provider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
    android:name="android.support.FILE_PROVIDER_PATHS"
    android:resource="@xml/provider_paths"
    tools:node="merge" />

Then have a class like below in your sdk and then initialise it with context from consumer application or from your sdk content provider.

object SDK {

  lateinit var fileProviderAuthority: String

  fun init(context: Context) {
   fileProviderAuthority = "${context.packageName}.library.file.provider"
  }

}

When you need the fileAuthority string for file uri operations consume it like below:

val uri = FileProvider.getUriForFile(this, SDK.fileProviderAuthority,File(FILE_PATH))

To read more click here

Related