FileProvider and Libraries

TL;DR: If you write an Android library, and it needs FileProvider capabilities, create and use your own subclass of FileProvider, so you can have a separate <provider> element in the manifest and not collide with that of the app or any other library.

A few weeks ago, I blogged about how libraries need to coordinate JobScheduler job IDs with their hosting apps, since those are app-wide constants.

In general, anything that is app-wide or device-wide needs to be configurable by the app developer, even if the library might offer a default solution that works most of the time.

A classic example of this is Application. An app can only have one Application class registered on the <application> element. For a while, too many libraries were insisting that, to use the library, you had to use their Application class (or extend from it). Narrowly, that’s fine, but once the app developer needs 2+ libraries with this requirement, the developer is screwed, as Java does not support multiple inheritance. Instead, libraries might offer a canned Application class, but need to support developers initializing the library by some other means that does not require a magic Application class.

The job ID scenario that I blogged about is another example: while the library might default to certain job IDs, those values need to be configurable, in case some other library also defaults to those IDs. The app developer needs to be able to mediate the conflict.

Another example is FileProvider.

Content providers have two settings that have uniqueness requirements:

  • There can be only one <provider> element in a manifest for a given android:name attribute, pointing to some specific Java class

  • The authority strings must be unique for a device

Historically, this was not a big problem. Few libraries needed to have a <provider> element, and many of those that did needed it because the point of the library was to provide the provider.

FileProvider, though, is a bit different. in that libraries might need it to overcome the ban on the file scheme instituted in Android 7.0.

If a library has a <provider> element for android.support.v4.content.FileProvider, now neither the app nor libraries can have that element. In principle, they could and let the manifest merger somehow sort it out, but that does not work well for authority strings or the FileProvider required <meta-data> element.

However, as Stuart Kent points out, you can create your own trivial subclass of FileProvider:

public class MyVeryOwnFileProvider extends FileProvider {
  
}

Now, you can have a <provider> element that points to your custom FileProvider subclass, and (usually) it will not conflict with that of anyone else. Your authority string and <meta-data> can live alongside that of others in the app, and FileProvider handles this situation, even for things like FileProvider.getUriForFile().

However, your authority string still needs to be unique on the device. Base it off of the ${applicationId} and have a nice distinctive suffix that prevents accidental collision (e.g., android:authorities="${applicationId}.your.library.package.name.goes.here.provider")). Now, once again, you should be independent from other libraries or from the app’s own use of FileProvider.

In many respects, these are all just variants on library-level encapsulation. You don’t want the implementation of the library to “leak” and pollute namespaces outside of the library’s control. It’s just that Android make library-level encapsulation trickier than you may encounter in other platforms.