Android, Gradle, product flavors and the manifest
Asked Answered
L

3

8

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.

Lout answered 4/3, 2016 at 12:39 Comment(0)
L
0

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.

Lout answered 4/3, 2016 at 13:9 Comment(0)
T
4

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

You said the flavor manifest is elsewhere. The manifest merger process merges all relevant manifests:

  • main
  • the build type
  • the product flavor(s)
  • libraries

The manifest in main is always relevant.

And how can I stop this?

You don't, insofar as the manifest in main is always relevant.

The best solution, in general, is to get rid of versionCode and versionName from all manifests, and set them in build.gradle, where you have full programmatic control.

The next-best solution is to move the versionCode and versionName out of the main manifest into the product flavor that you're not showing here. I have never seen anyone create just one product flavor, as AFAIK it's pointless — you can only ever build that one product flavor (as AFAIK there are no flavorless builds once you introduce flavors). Product flavors usually come in groups of 2+ (e.g., the google flavor that uses Play Services and the standalone flavor that doesn't). If the values in main are really for the non-AlternateFlavour flavor, move your main version... stuff there.

Beyond that, you're welcome to review the documentation on the manifest merger process to see if you can put in the right directives to get what you want.

Tree answered 4/3, 2016 at 12:58 Comment(3)
So first of all, there's loads of flavors here - I just tried to keep the given example simple. I can't (AFAIK) get away with removing the attributes from the original manifest because that's the one used by IDE deployment. However I could possibly create a third one, without the attributes, and have Gradle use that by default. Seems excessive!Lout
@RobPridham: "that's the one used by IDE deployment" -- if you're using Android Studio, the Build Variants tool controls what is used by the IDE.Tree
Indeed. Not there yet unfortunately - still using Eclipse & ADT for this development, for a variety of good (albeit less good over time) reasons.Lout
L
0

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.

Lout answered 4/3, 2016 at 13:9 Comment(0)
B
0

The Android official documentation will tell you why multiple manifest files will be merged during building process.

Merge Multiple Manifest Files

I have met the same problems while I want to get different flavors with different versionCode and versionName.When you want to do this,remove all versionCode and versionName from AndroidManifest.xml and try to do flavors in build.gradle file.

Brogdon answered 28/5, 2018 at 3:43 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.