One of the main benefits of switching to Gradle for your Android build system is the ability to create multiple packages from a single commit. This enables installing debug & release versions of the same app on a single phone, as well as more complicated flavor setups such as free/paid versions. Although setting up the actual package naming is simple, unfortunately some Android systems breakdown when the package name varies. One common problem is INSTALL_FAILED_CONFLICTING_PROVIDER errors when your app includes Content Providers.
Content Providers are accessed via Content URIs. The first portion of the Content URI is the Content Authority, which should correspond with the package name of the app. The Content URI has to match in both the Manifest and the definition of the Content Provider’s authority in Java. A typical implementation of a Content Provider’s manifest & Content URI definition for an app with a constant package name is below. (For a complete example of implementing a Content Provider I recommend Wolfram Rittmeyer’s post.)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
|
Generating multiple packages from Gradle is relatively straightforward. You can either specify the entire package name for a particular build variant or use a packageNameSuffix. The example below specifies the complete package name, but in practice I prefer setting the root of the package name in the manifest and then appending build variant specific suffixes. This example shows splitting the packages based on build flavor (free v paid), though this applies equally to splitting the packages based on build type (debug vs release), or some combination of both.
1 2 3 4 5 6 7 8 9 |
|
No matter how you decide to split the packages, setting up the Content Provider Authority is the same. Since the release of Gradle Plugin 0.7.0 the package name is automatically added to the BuildConfig file and is available for use in constants.
1
|
|
If you are working with several build variants, it is important to understand how Gradle merges the various sources sets. For Manifests, the XML from main, buildType, and buildFlavor are combined. This means that you do not have to duplicate your entire manifest into each build variant folder. Leave the constant portion in src/main, and then only extract the variable portion to the build variant specific folders. The example below is for splitting the package based on build flavor (free/paid), but would also apply for splitting based on build type (debug/release). In this case, nothing about the Content Providers is in the debug & release specific Manifests. Note that you still must put the Content Provider definition within the application block in the build variant specific manifests.
The actual definition will have an authority derived from the package name, but the Content Provider class reference does not change. When you change the package name for your app it effects the .apk’s ‘package name’, but it doesn’t actually change the Java packages at all.
1 2 3 4 5 6 7 8 9 10 11 |
|
1 2 3 4 5 6 7 8 9 10 11 12 |
|
1 2 3 4 5 6 7 8 9 10 11 12 |
|
You can inspect the merged manifests in build/manifests/free/debug/AndroidManifest.xml and build/manifests/paid/debug/AndroidManifest.xml. If everything is setup correctly, the final merged manifest for any particular build variant will look almost exactly like the original single manifest, except with package name specific Content Authorities. This will allow you to run both apps on a single phone at one time.