Android - Removing Activity from Flavor
Asked Answered
S

2

10

How to remove an activity from an app flavor? Here is a simplified example, I have an app which has the following two flavors (Paid and Free). The app is small and only has 3 activities (MainActivity, ActivityOne and ActivityTwo). The paid app does not need any limitations since it will use the full code base. The free app however requires it to have MainActivity and ActivityTwo accessible to the user and not ActivityOne. How can I do a "Manifest Merge" when compiling the code so that ActivityOne is not present on the free version? In other words how should src/free/AndroidManifest.xml be created so that the free app does not have ActivityOne?

Below is the build.gradle file for the app:

apply plugin: 'com.android.application'

android {
    compileSdkVersion 21
    buildToolsVersion "21.1.2"

    defaultConfig {
        applicationId "com.example.calculator"
        minSdkVersion 21
        targetSdkVersion 21
        versionCode 1
        versionName "1.0"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
    productFlavors {
        paid {
            applicationId "com.example.paid"
            resValue "string", "app_name", "Paid Calculator"
            versionName "1.0-full"
        }
        free {
            applicationId "com.example.free"
            resValue "string", "app_name", "Free Calculator"
            versionName "1.0-free"
        }
    }
    sourceSets {
        paid {
            manifest.srcFile 'src/paid/AndroidManifest.xml'
        }
        free {
            manifest.srcFile 'src/free/AndroidManifest.xml'
        }
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    compile 'com.android.support:cardview-v7:21.0.0'
    compile 'com.android.support:recyclerview-v7:21.0.0'
    compile 'com.android.support:design:22.2.0'
    compile 'com.android.support:appcompat-v7:22.2.0'
}

Below is the manifest file for the app It is located at src/main/AndroidManifest.xml:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.calculator">

    <application
        android:name="com.example.calculator.ui.activities.AppController"
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:theme="@style/AppTheme">
        <activity
            android:name=".ui.activities.MainActivity"
            android:label="@string/app_name">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity
            android:name=".ui.activities.ActivityOne"
            android:label="@string/title_activity_one"
            android:parentActivityName=".ui.activities.MainActivity">
            <meta-data
                android:name="android.support.PARENT_ACTIVITY"
                android:value=".ui.activities.MainActivity" />
        </activity>
        <activity
            android:name=".ui.activities.ActivityTwo"
            android:label="@string/title_activity_two"
            android:parentActivityName=".ui.activities.MainActivity">
            <meta-data
                android:name="android.support.PARENT_ACTIVITY"
                android:value=".ui.activities.MainActivity" />
        </activity>
    </application>
</manifest>
Schmidt answered 25/9, 2015 at 1:53 Comment(0)
O
12

You can set android:enabled attribute with a placeholder

AndroidManifest.xml:

<activity 
    android:name=".ui.activities.ActivityOne" 
    android:enabled="${isPaidVersion}"/>

build.config:

defaultConfig {
  ...
  manifestPlaceholders = [isPaidVersion: "false"]
}

productFlavors {
    paid {
        ... 
        manifestPlaceholders = [isPaidVersion:"true"]
    }
    free {
        ...
    }
}
Outward answered 27/5, 2016 at 13:23 Comment(1)
This will still add all the class files and the XML filesHeartland
C
11

In your free flavor, in the AndroidManifest you can specify:

<activity android:name=".ui.activities.ActivityOne" tools:node="remove"/>

The marker tools:node="remove" will make the merger remove any activities with android:name=".ui.activities.ActivityOne"

Crews answered 25/9, 2015 at 7:4 Comment(5)
Just as a clarification, make sure to leave your main manifest.xml as it is. You only need to make sure there is a copied manifest under your free directory and modify that activity node in the free flavor's manifest. Thanks, @GabrieleMariotti !Coxalgia
It seems that the marker tools:node="remove" works with activity sub-nodes, but it does not work with the activity node itself. I also checked the merged manifest in the apk with the aapt tool, and the activity node is not removed. The solution by anagaf works like a charm.Haslam
@PoianaApuana Before downvoting an answer you should consider the age of the same answer. It was written 2 years ago, it means that a lot of thing changed in the meanwhile and may be it was the best answer at that time but not the best one today. The manifestPlaceholders didn't exist 2 years ago....Crews
@gabriele I do not know if one year ago it worked, but right now your answer is wrong and misleading, I lost my time following your suggestion. Then, instead of replying to my downvote, why don't you re-edited your answer to fix it?Haslam
Just tried this solution today and it is working as expected so it was either a bug in build system or a wrong priority as described here developer.android.com/studio/build/manifest-merge (tried with as 3.2.1)Cableway

© 2022 - 2024 — McMap. All rights reserved.