Skip to content

Instantly share code, notes, and snippets.

@cmelchior
Last active December 25, 2015 13:59
Show Gist options
  • Star 11 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save cmelchior/6988275 to your computer and use it in GitHub Desktop.
Save cmelchior/6988275 to your computer and use it in GitHub Desktop.
Adding support for ".res-auto" in ContentProvider authorities in AndroidManifest.xml. This replaces ".res-auto" with the current package name, making it possible to install multiple build variants on the same devices without getting [INSTALL_FAILED_CONFLICTING_PROVIDER]
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.trifork.example"
android:installLocation="auto"
android:versionName="@string/client_info" >
<!-- ... -->
<application
android:hardwareAccelerated="true"
android:icon="@drawable/icon"
android:label="@string/app_name"
android:theme="@style/Theme.Standard" >
<!-- ... -->
<provider
android:name="path.to.provider.ProviderImpl"
android:authorities=".res-auto.path.to.provider.ProviderImpl"
android:exported="false" >
</provider>
<provider
android:name="path.to.provider.ProviderImpl"
android:authorities="@string/provider_auth"
android:exported="false" >
</provider>
</application>
</manifest>
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:0.6.+'
}
}
apply plugin: 'android'
apply from: './build_extras.gradle'
repositories {
mavenCentral()
}
android {
compileSdkVersion 18
buildToolsVersion "18.0.1"
defaultConfig {
minSdkVersion 10
targetSdkVersion 18
}
}
dependencies {
}
/**
* Version 1.1.
*
* Add support for installing multiple variants of the same app which have a
* content provider. Do this by overriding occurrences of ".res-auto" in
* android:authorities with the current package name (which should be unique)
*
* V1.0 : Initial version
* V1.1 : Support for ".res-auto" in strings added,
* eg. use "<string name="auth">.res-auto.path.to.provider</string>"
*
*/
def overrideProviderAuthority(buildVariant) {
def flavor = buildVariant.productFlavors.get(0).name
def buildType = buildVariant.buildType.name
def pathToManifest = "${buildDir}/manifests/${flavor}/${buildType}/AndroidManifest.xml"
def ns = new groovy.xml.Namespace("http://schemas.android.com/apk/res/android", "android")
def xml = new XmlParser().parse(pathToManifest)
def variantPackageName = xml.@package
// Update all content providers
xml.application.provider.each { provider ->
def newAuthorities = provider.attribute(ns.authorities).replaceAll('.res-auto', variantPackageName)
provider.attributes().put(ns.authorities, newAuthorities)
}
// Save modified AndroidManifest back into build dir
saveXML(pathToManifest, xml)
// Also make sure that all strings with ".res-auto" are expanded automagically
def pathToValues = "${buildDir}/res/all/${flavor}/${buildType}/values/values.xml"
xml = new XmlParser().parse(pathToValues)
xml.findAll{it.name() == 'string'}.each{item ->
if (!item.value().isEmpty() && item.value()[0].startsWith(".res-auto")) {
item.value()[0] = item.value()[0].replace(".res-auto", variantPackageName)
}
}
saveXML(pathToValues, xml)
}
def saveXML(pathToFile, xml) {
def writer = new FileWriter(pathToFile)
def printer = new XmlNodePrinter(new PrintWriter(writer))
printer.preserveWhitespace = true
printer.print(xml)
}
// Post processing of AndroidManifest.xml for supporting provider authorities
// across build variants.
android.applicationVariants.all { variant ->
variant.processManifest.doLast {
overrideProviderAuthority(variant)
}
}
@paour
Copy link

paour commented Feb 21, 2014

@influenced, in searchable.xml you can use something like

<?xml version="1.0" encoding="utf-8"?>
<searchable xmlns:android="http://schemas.android.com/apk/res/android"
            android:label="@string/app_name"
            android:hint="@string/search_hint"
            android:searchSuggestAuthority="@string/search_provider"
            android:searchSuggestSelection=" ?"
        >
</searchable>

and add to your strings.xml

    <string name="search_provider">.res-auto.util.LocationSuggestionProvider</string>

But I do have the same issue with the values being overwritten when I use IntelliJ.

@influenced
Copy link

That's what I'd like to do - and what I originally did - but by the time it gets onto the device, it'll have been reset to .res-auto again, so the OS won't be able to find that provider.

@paour
Copy link

paour commented Feb 24, 2014

I spent way too much time on this, but I finally have a version that works. Please check out https://gist.github.com/paour/9189462

@martingg88
Copy link

@influenced: do you manage to get .res-auto replaced when you hit run/debug?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment