Search code examples
androidgradleandroid-buildandroid-productflavorsandroid-build-flavors

Android, Gradle, product flavors and the manifest


In build.gradle, I have product flavors set up:

productFlavors
{
    AlternateFlavour
    {
        applicationId "com.myapp.alternateflavour"
    }
}

Then in the sourceSets section, I use different resource, assets and manifest directories for those flavours:

sourceSets {
    main {
        manifest.srcFile 'AndroidManifest.xml'
        java.srcDirs = ['src']
        res.srcDirs = ['res']
        assets.srcDirs = ['assets']
    }

    AlternateFlavour {
        manifest.srcFile 'manifest-tmp/AlternateFlavour/AndroidManifest.xml'
        java.srcDirs = ['src']
        res.srcDirs = ['res-tmp/AlternateFlavour']
        assets.srcDirs = ['assets-tmp/AlternateFlavour']
        }
   }

OK so far.

In that manifest being used by the flavor, which is in part automatically generated, I have:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.myapp.myapp"
    android:versionCode="1010001"
    android:versionName="V1.1.0.1" >

but in the original manifest in the root project is as follows:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.myapp.myapp"
    android:versionCode="1010000"
    android:versionName="V1.1.0.DEBUG" >

This causes Gradle to fail:

Error:
    Attribute manifest@versionCode value=(1010001) from AndroidManifest.xml:4:5-28
    is also present at AndroidManifest.xml:4:5-28 value=(1010000).
Attributes of <manifest> elements are not merged.

Why is it trying to merge with the original manifest at all, when I've specified it should look elsewhere?

And how can I stop this?

I expect some will question why I'm doing it this way at all, or indeed why I'm not using the suggested flavor project structure. Well, I need a normal manifest to use outside of Gradle, e.g. for deploying from Eclipse (one thing at a time please!) and I also need versions to be injected by the build process.


Solution

  • I'll be keeping in mind what @CommonsWare said in their answer, but for now, I've resolved this as follows:

    <?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        package="com.myapp.myapp"
        tools:replace="android:versionName,android:versionCode"
        android:versionCode="1010001"
        android:versionName="V1.1.0.1" >
    

    Note the two tools snippets.

    I knew about this originally, but I was put off trying it, because the full Gradle error referred to three problems:

    • versionCode
    • versionName
    • the Maps API key

    all of which are auto-inserted. However it only proferred tools:replace as a suggestion for the last of those, so I got the impression that it wouldn't work on manifest attributes. In fact it does.