How to use a different launcher activity in a product flavor?
Asked Answered
O

7

30

I'm working on an Android library project, in the default src/main/AndroidManifest.xml, the MainActivity is the launcher activity.

For the sake of something else, I created product flavors. Yes, it works perfect if I want to trigger / show different activitis inside different product flavors. However, I wanna keep the default launcher activity from src/main/ folder, while register another flavored activity as the new launcher activity. So that for different product flavors, I could have different launcher activities, and from them I could still start original "launcher" activity in src/main/.

Could anyone kindly tell me how to achive that? Thanks a lot.

Notes:

  1. Adding if (BuildConfig.FLAVOR.equals("flavorName")) code to original launcher activity is not prefered. Because I don't want to modify the production code from someone else (this is a library project).

  2. I've tried manifestmerger and tools:replace, but seems like it doesn't work for intent-filter (I noticed that the element merging policy for intent-filter is always).

<action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" />

If this may work, could you please kindly guide me how to make it work? Thanks.

Overblouse answered 31/8, 2015 at 21:57 Comment(0)
O
38

What I have tried:

  1. Enabling Manifest Merger, which doesn't work;
  2. Using activity-alias, which doesn't work either.

Finally I found out that the problem could be solved by just adding one line:

<category android:name="android.intent.category.DEFAULT" />

==================================================

To make it clear, I'll go through the problem and solution one more time:

Under src/main/java there is a MainActivity, and in corresponding src/main/AndroidManifest.xml it specifies MainActivity as the launcher activity:

<activity android:name=".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>

That is a very easy part. Now we start with the product flavor part.

Due to some reason, in a product flavor, I don't want to overwrite the MainActivity, instead, I have a YetAnotherMainActivity. The goal is to set the YetAnotherMainActivity as the new launcher activity in the product flavor, and it should still be able to call MainActivity.

And here, is how you can set the new activity in product flavor as the new launcher activity:

flavorX/AndroidManifest.xml:

<activity android:name="com.example.YetAnotherMainActivity"
    android:label="@string/title_yet_another_main_activity">
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
        <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
</activity>

Yep, it turns out deadly easy. Just add android.intent.category.DEFAULT.

Overblouse answered 1/9, 2015 at 17:45 Comment(6)
Thanks @AdamFręśko, maybe it's not the best solution, but so far it's working :)Overblouse
This installs two apk for when I run the app on the deviceErl
@IsmailIqbal it seems like unfortunately yesOverblouse
I followed another examples, https://mcmap.net/q/500380/-android-gradle-two-different-launcher-activities-for-two-different-product-flavorsErl
Thanks @IsmailIqbal but as I said above in one comment, "tools:node="remove" will remove that original launcher activity which I would like to keep". Where I mentioned in my original question that, "I wanna keep the default launcher activity".Overblouse
excellent, with tools:node="replace" suggested on here . Can keep the main's launcher activity while use another launcher activity on other flavorSuckerfish
A
11

I think that <activity-alias> fits there more than any other solution (have no idea why @JingLi couldn't get it working. Maybe there were some troubles year ago, but for now it's okay).

For example, we have the following manifest in main:

<manifest
        xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.example.application">
    <application>
        <activity android:name=".InfoActivity"/>
        <activity-alias 
            android:name="com.example.application.Launcher"
            android:targetActivity=".InfoActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>
                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity-alias>
    </application>
</manifest>

And we want to replace launcher activity with DebugInfoActivity from debug flavor. So, we need to just replace the targetActivity attribute in the specified <activity-alias> tag:

<manifest 
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools">
    <application>
        <activity android:name=".DebugInfoActivity"/>
        <!-- to not litter the manifest -->
        <activity 
                android:name="com.example.application.InfoActivity"
                tools:node="remove"/>
        <activity-alias
                android:name="com.example.application.Launcher"
                android:targetActivity=".DebugInfoActivity"
                tools:replace="android:targetActivity"/>
    </application>
</manifest>

Notes:

  • In the example we use the same package name for main and debug.
  • We have to enter the full name for activity-alias, so the merger can merge their correctly.

With the solution we also can inherit all attributes and childs from main activity-alias to not duplicate their in debug.

Amused answered 21/10, 2016 at 2:26 Comment(4)
I haven't tried if <activity-alias> works or not now (after one year as you said). But my question is about "using a different launcher activity, without removing the original launcher activity". That's why I prefer simply adding <category android:name="android.intent.category.DEFAULT" />. And your code here tools:node="remove" will remove that original launcher activity which I would like to keep. Thanks anyway :)Overblouse
Ouch. Don't know how I missed that. So, especially if you want to preserve your intent-filter for MainActivity, maybe your variant fits there good too.Amused
This works, except I would do tools:node="replace" instead of tools:node="remove" so you can still keep your InfoActivity and just change which acts as launcher. For me @JingLi alternative created two different launchers (as is I had the app installed twice)Rollback
This works. Saved the day!!Gherkin
O
2

I guess I am not late :) So today I got the same problem. @seroperson solution was correct but If you do not want the default launcher activity at all then just use the below code in your flavor's manifest:

<activity
        android:name=".DefaultLauncherActivity"
        tools:node="remove"
        >
Oriana answered 28/10, 2018 at 17:6 Comment(2)
My question is about "using a different launcher activity, without removing the original launcher activity". And your code here tools:node="remove" will remove that original launcher activity which I would like to keep.Overblouse
This works for the general case of removing a default merged item in a build variant.B
H
1

Android merger is merging intent-filter from main manifest lancher to flavors. I have not found way to prevent that. You end up with 2 app icons on device (each for launcher Activity).

Based on that, you cannot override completely settings from main manifest. Solition may be to keep only shell of manifest in main folder and implement manifest in each flavor or to remove conflict Activities from main folder and implemenent independently in each flavor.

<?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.adamassistant.app">

    <!-- empty shell, implementation in flavors folders -->

</manifest>
Holography answered 16/4, 2021 at 6:45 Comment(0)
M
-1

The simplest and cleanest solution is to keep only one Manifest and write two different MainActivity.java class one for each flavor in order to avoiding duplication of manifest nodes.

Given two flavors in gradle

productFlavors {
        paid {
            packageName "com.example"
        }

        demo {
            packageName "com.example.demo"
        }
    }

Given this project structure

app/
|--libs/
|--src/
   |--paid/
   |  |--java/
   |     |--com/example/
   |        |--MainActivity.java
   |--demo/
   |  |--java/
   |     |--com/example/
   |        |--MainActivity.java
   |--main/
      |--java/
      |  |--...
      |--res/
      |  |--...
      |--AndroidManifest.xml

And this Android Manifest

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

    <application
            android:icon="@mipmap/ic_launcher"
            android:label="@string/app_name"
            android:theme="@style/AppTheme">

        <activity
                android:name=".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>

    </application>

</manifest>
Meakem answered 1/3, 2016 at 9:51 Comment(1)
Thanks but sorry, you should read my question carefully. I mentioned "I wanna keep the default launcher activity, but have another new activity as the new launcher activity". So your solution doesn't work for me, since it's replacing the other MainActivity.Overblouse
T
-1

Create a different AndroidManifest.xml file in your flavor. And there set your DifferentFlavorMainActivity.java as the launcher activity with full name like:

android:name="com.android.application.paid.MainActivity"
Triptolemus answered 23/3, 2018 at 10:5 Comment(0)
A
-3

The working simplest solution is to use manifest merging and using

<intent-filter tools:node="removeAll">  

as suggested in the following post :

Merging android manifest files, conflicting filter

Aliunde answered 6/4, 2016 at 20:48 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.