如何在产品风格中使用不同的启动器活动?

28

我正在进行一个Android库项目的工作,在默认的src/main/AndroidManifest.xml中,MainActivity是启动器活动。

为了某些原因,我创建了产品风味。如果我想在不同的产品风味中触发/显示不同的活动,则非常完美。但是,我想保留src/main/文件夹中的默认启动器活动,并注册另一个带有风味的活动作为新的启动器活动。因此,对于不同的产品风味,我可以拥有不同的启动器活动,并且我仍然可以从它们中启动src/main/中的原始“启动器”活动。

请问有谁能告诉我如何实现这一点?谢谢。

注:

  1. 不建议在原始启动器活动中添加if (BuildConfig.FLAVOR.equals("flavorName"))代码。因为我不想修改别人的生产代码(这是一个库项目)。

  2. 我已经尝试了manifestmerger和tools:replace,但似乎对intent-filter无效(我注意到intent-filter的元素合并策略始终为always)。

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

如果这可能有效,您能否请指导我如何使其有效?谢谢。

7个回答

36

我尝试过的方法:

  1. 启用清单合并,但没有起作用;
  2. 使用activity-alias也不行。

最后我发现只需添加一行代码即可解决问题:

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

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

为了让大家更加清楚,我将再一次说明问题和解决方案:

src/main/java 目录下有一个 MainActivity 文件,并且在对应的 src/main/AndroidManifest.xml 文件中指定了 MainActivity 作为启动活动:

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

<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>

这是一个非常简单的部分,现在我们开始处理产品口味。

由于某些原因,在一个产品口味中,我不想覆盖MainActivity,而是有一个YetAnotherMainActivity。目标是YetAnotherMainActivity设置为产品口味中的新启动活动,并且仍然能够调用MainActivity

下面是如何将产品口味中的新活动设置为新的启动活动:

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>

没错,原来如此简单。只需添加android.intent.category.DEFAULT即可。


谢谢@AdamFręśko,也许这不是最好的解决方案,但目前它正在工作 :) - Jing Li
3
这将安装两个apk,以便在设备上运行应用程序。 - Ismail Iqbal
@IsmailIqbal 似乎很不幸,是的。 - Jing Li
2
我跟随了其他的例子,https://dev59.com/bVwY5IYBdhLWcg3wsphj#34183747 - Ismail Iqbal
1
感谢@IsmailIqbal,但正如我在之前的评论中所说,“tools:node="remove"将会移除原始的启动器活动(即我想要保留的活动)”。而我在原始问题中提到,“我想要保留默认的启动器活动”。 - Jing Li

10

我认为<activity-alias>比任何其他解决方案更适合那里(不知道为什么@JingLi无法使其工作。也许一年前存在某些问题,但现在没问题了)。

例如,我们在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>

我们希望将启动器活动替换为来自debug风格的DebugInfoActivity。因此,我们只需要在指定的<activity-alias>标签中替换targetActivity属性:

<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>

注:

  • 在此示例中,我们对maindebug使用相同的包名。
  • 我们必须输入完整的activity-alias名称,以便合并程序可以正确地将它们合并。

通过这种解决方案,我们还可以从main活动别名继承所有属性和子项,以避免在debug中重复它们。


我现在还没有尝试过<activity-alias>是否有效(就像你说的一年后)。但我的问题是关于“使用不同的启动器活动,而不删除原始的启动器活动”。这就是为什么我更喜欢简单地添加<category android:name="android.intent.category.DEFAULT" />。而你在这里的代码tools:node="remove"将会删除我想要保留的原始启动器活动。无论如何,谢谢 :) - Jing Li
哎呀,不知道怎么错过了那个。所以,特别是如果您想保留MainActivityintent-filter,也许您的变体也适合在那里使用。 - seroperson
1
这个方案可行,不过我会使用 tools:node="replace" 而不是 tools:node="remove",这样你就可以保留你的 InfoActivity 并更改其作为启动器。对我来说,@JingLi 的替代方案创建了两个不同的启动器(因此我安装了两次应用程序)。 - Mauricio
这个有效。救了我们的一天!! - umesh

2

我想我没有迟到:) 今天我遇到了同样的问题。@seroperson的解决方案是正确的,但如果您根本不想使用默认的启动器活动,则只需在您的口味清单中使用以下代码:

<activity
        android:name=".DefaultLauncherActivity"
        tools:node="remove"
        >

我的问题是关于“使用不同的启动器活动,而不删除原始的启动器活动”。您在这里的代码tools:node="remove"将删除我想要保留的原始启动器活动。 - Jing Li
这适用于在构建变体中删除默认合并项的一般情况。 - Mr-IDE

0

Android merger 正在将主清单启动器的 intent-filter 合并到味道中。我还没有找到防止这种情况发生的方法。你最终会在设备上得到 2 个应用程序图标(每个都是启动器活动)。

基于此,您无法完全覆盖主清单中的设置。解决方案可能是仅在主文件夹中保留清单外壳,并在每个口味中实现清单,或从主文件夹中删除冲突活动,并在每个口味中独立实现。

<?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>

-1

最简单、最干净的解决方案是只保留一个清单文件,并编写两个不同的 MainActivity.java 类,每个口味一个,以避免清单节点的重复。

在 Gradle 中给定两个口味

productFlavors {
        paid {
            packageName "com.example"
        }

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

考虑到这个项目的结构

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

还有这个 Android 清单

<?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>

谢谢,但很抱歉,您应该仔细阅读我的问题。我提到“我想保留默认的启动器活动,但有另一个新活动作为新的启动器活动”。所以您的解决方案对我无效,因为它替换了其他MainActivity。 - Jing Li

-1
在您的Flavor中创建一个不同的AndroidManifest.xml文件。并将DifferentFlavorMainActivity.java设置为启动活动,并以全名形式命名:
android:name="com.android.application.paid.MainActivity"

-3

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接