Using a different manifestPlaceholder for each Bui

2020-02-04 06:41发布

I will start by saying that I am very new to Gradle, so I apologize if this has already been answered.

I'm working on an Android application that uses an API key to access a 3rd party tool. A different API key needs to be used depending on both the flavor and build type of the app.

Here is a basic outline of what I'm trying to do:

android {
    defaultConfig {
        manifestPlaceholders = [ apiKey:"DEBUG_KEY" ]
    }

    buildTypes{
        debug{
            // Some debug setup
        }
        release{
            // Some release setup
        }
    }

    productFlavors {
        // List of flavor options
    }
    productFlavors.all{ flavor->
        if (flavor.name.equals("someFlavor")) {
            if (buildType.equals("release")) {
                manifestPlaceholders = [ apiKey:"RELEASE_KEY_1" ]
            } else {
                manifestPlaceholders = [ apiKey:"DEBUG_KEY" ]
            }
        } else {
            if (buildType.equals("release")) {
                manifestPlaceholders = [ apiKey:"RELEASE_KEY_2" ]
            } else {
                manifestPlaceholders = [ apiKey:"DEBUG_KEY" ]
            }    
        }
    }
}

So far the manifestPlaceholders statement is working in a very simple case, but I don't know how to reference the buildType from within the productFlavors block so that I can use it as a conditional.

6条回答
倾城 Initia
2楼-- · 2020-02-04 07:28

You may set manifestPlaceholders inside applicationVariants by accessing mergedFlavor for specific applicationVariant.

android.applicationVariants.all { variant ->
    def mergedFlavor = variant.getMergedFlavor()
    mergedFlavor.manifestPlaceholders = [appPackageId: "myPackage1"]

}

查看更多
小情绪 Triste *
3楼-- · 2020-02-04 07:32

Similarly to the accepted answer, you could do it with string resources, if you didn't want to duplicate your manifests.

For example, if you had two flavors (flavor1 and flavor2) You'd end up w/ the following source sets.

app/
  src/
    main/
      res/
         values/strings.xml
    flavor1Release/
      res/
         values/strings.xml
    flavor1Debug/
      res/
         values/strings.xml

    flavor2Release/
       res/
         values/strings.xml
    flavor2Debug/
       res/
         values/strings.xml

You could then just use a string resource for your key value

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
          xmlns:tools="http://schemas.android.com/tools">    
    <application>    
        <meta-data
            android:name="io.fabric.ApiKey"
            android:value="@string/apiKey" tools:replace="android:value"/>
    </application>    
</manifest>

One further optimization to keep all your keys in one place is to define them all in strings.xml in your main source set. and then have the flavor/build source sets reference those.

for example:

<resources>
    <string name="flavor1ReleaseKey">flavor1ReleaseKey</string>
    <string name="flavor1DebugKey">flavor1DebugKey</string>
    <string name="flavor2ReleaseKey">flavor2ReleaseKey</string>
    <string name="flavor2DebugKey">flavor2DebugKey</string>
</resources>

then in each of your flavor/build sourceSets, you just reference those keys.

flavor1Release/res/values/strings.xml

<resources>
     <string name="apiKey">@string/flavor1ReleaseKey</string>
</resources>
查看更多
放荡不羁爱自由
4楼-- · 2020-02-04 07:44

I believe that you need a manifestPlaceHolder to read that value in your Java code, right? If this is the case, you can already read the FLAVOR name in your generated BuildConfig.java. For example, if you define a flavor whose name is smartphone you can access that value using BuildConfig.FLAVOR String; then in your code you can use a simple if (BuildConfig.FLAVOR.equals("smartphone"))...

But maybe you need to read a sort of configuration of your app, an apiKey. In that case, the best way to go is to create a Class or a string resource for every flavor; this is the link for you.

查看更多
爱情/是我丢掉的垃圾
5楼-- · 2020-02-04 07:44

What i did is copied current AndroidManifest.xml into app/src/debug

and changed the key there debug Manifest :

 <meta-data
            android:name="com.crashlytics.ApiKey"
            tools:replace="android:value"
            android:value="@string/crashlytics_debug" />

app/src/main Manifest is like :

<meta-data
        android:name="com.crashlytics.ApiKey"
        android:value="@string/crashlytics_live" />
查看更多
叼着烟拽天下
6楼-- · 2020-02-04 07:46

I would guess that you are referring to Fabric ApiKey? :) I just spent hours trying to do it in a similar way with the placeholders and specifying the ApiKey in the gradle file although it does not seem possible as of com.android.tools.build:gradle:1.3.1. It is possible to specify a placeholder for a specific flavor but not for a flavor AND buildType.

Just to correct your syntax, the way you would have to do it (if it was possible) would be something like that but manifestPlaceholders are unknown to variants.

applicationVariants.all{ variant->
    if (variant.productFlavors.get(0).name.equals("someFlavor")) {
        if (variant.buildType.name.equals("release")) {
            manifestPlaceholders = [ apiKey:"RELEASE_KEY_1" ]
        } else {
            manifestPlaceholders = [ apiKey:"DEBUG_KEY" ]
        }
    } else {
        if (variant.buildType.name.equals("release")) {
            manifestPlaceholders = [ apiKey:"RELEASE_KEY_2" ]
        } else {
            manifestPlaceholders = [ apiKey:"DEBUG_KEY" ]
        }    
    }
}

What you actually need to do is to keep the key in the AndroidManifest.xml and handle it with multiple manifest file

src/AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
          xmlns:tools="http://schemas.android.com/tools">    
    <application>    
        <meta-data
            android:name="io.fabric.ApiKey"
            android:value="DEBUG_KEY" tools:replace="android:value"/>
    </application>    
</manifest>

src/someFlavorRelease/AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
          xmlns:tools="http://schemas.android.com/tools">    
    <application>    
        <meta-data
            android:name="io.fabric.ApiKey"
            android:value="RELEASE_KEY_1" tools:replace="android:value"/>
    </application>    
</manifest>

src/someOtherFlavorRelease/AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
          xmlns:tools="http://schemas.android.com/tools">    
    <application>    
        <meta-data
            android:name="io.fabric.ApiKey"
            android:value="RELEASE_KEY_2" tools:replace="android:value"/>
    </application>    
</manifest>

The manifestMerger will handle the replacement and you will end up with the proper key in every scenario. I just implemented it successfully. I just hope you were really referring to the Fabric key! :)

Hope this helps!

查看更多
▲ chillily
7楼-- · 2020-02-04 07:46

I found this great solution in https://azabost.com/android-manifest-placeholders/

android {
    ...
    buildTypes {
        release {
            ...
            manifestPlaceholders.screenOrientation = "portrait"
        }
        debug {...}
    }
}

or

android {
    ...
    flavorDimensions "features"

    productFlavors {

    paid {
        dimension "features"
        manifestPlaceholders.hostName = "www.paid-example.com"
    }
    free {
        dimension "features"
        manifestPlaceholders.hostName = "www.free-example.com"
    }
}
查看更多
登录 后发表回答