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

Posted

技术标签:

【中文标题】如何在产品风味中使用不同的启动器活动?【英文标题】:How to use a different launcher activity in a product flavor? 【发布时间】:2015-11-26 00:56:31 【问题描述】:

我正在做一个 android 库项目,在默认的 src/main/AndroidManifest.xml 中,MainActivity 是启动器活动。

为了别的,我创造了产品风味。是的,如果我想在不同的产品口味中触发/显示不同的活动,它非常有效。但是,我想保留 src/main/ 文件夹中的 默认启动器活动,同时将另一个风味活动注册为新的启动器活动。这样对于不同的产品风格,我可以有不同的启动器活动,并且我仍然可以从它们开始在 src/main/ 中的原始“启动器”活动。

谁能告诉我如何做到这一点?非常感谢。

注意事项:

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

    我尝试过manifestmergertools:replace,但似乎不适用于intent-filter(我注意到intent-filter 的元素合并策略始终是)。

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

如果这可行,请您指导我如何使其工作?谢谢。

【问题讨论】:

【参考方案1】:

我尝试过的:

    启用 Manifest Merger,这不起作用; 使用 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,也许这不是最好的解决方案,但到目前为止它正在工作:) 这会在我在设备上运行应用程序时安装两个 apk @IsmailIqbal 不幸的是,是的 我跟着另一个例子,***.com/a/34183747/4944007 感谢@IsmailIqbal,但正如我在上面的一条评论中所说,“tools:node="remove" 将删除我想保留的原始启动器活动”。我在最初的问题中提到“我想保留默认的启动器活动”。【参考方案2】:

我认为&lt;activity-alias&gt; 比任何其他解决方案都更适合那里(不知道为什么@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 替换启动器活动。所以,我们只需要替换指定&lt;activity-alias&gt;标签中的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的全名,这样合并才能正确合并它们。

通过该解决方案,我们还可以从mainactivity-alias 继承所有属性和子项,以免在debug 中重复它们。

【讨论】:

我还没有尝试过&lt;activity-alias&gt; 现在是否有效(如您所说,一年后)。但我的问题是关于“使用不同的启动器活动,而不删除原始启动器活动”。这就是为什么我更喜欢简单地添加&lt;category android:name="android.intent.category.DEFAULT" /&gt;。您在tools:node="remove" 的代码将删除我想保留的原始启动器活动。无论如何谢谢:) 哎哟。不知道我是怎么错过的。所以,特别是如果你想为MainActivity 保留你的intent-filter,也许你的变体也很适合。 这行得通,除了我会用tools:node="replace" 而不是tools:node="remove" 这样你仍然可以保留你的 InfoActivity 并且只需更改哪个作为启动器。对我来说,@JingLi 替代品创建了两个不同的启动器(因为我安装了两次应用程序)【参考方案3】:

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

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

【讨论】:

我的问题是关于“使用不同的启动器活动,而不删除原始启动器活动”。您的代码tools:node="remove" 将删除我想保留的原始启动器活动。 这适用于在构建变体中删除默认合并项的一般情况。【参考方案4】:

Android 合并正在将 intent-filter 从主要清单 lancher 合并到风味。我还没有找到防止这种情况的方法。您最终会在设备上看到 2 个应用程序图标(每个用于启动器 Activity)。

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

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

【讨论】:

【参考方案5】:

根据您的喜好创建一个不同的 AndroidManifest.xml 文件。并将您的 DifferentFlavorMainActivity.java 设置为启动器活动,全名如下:

android:name="com.android.application.paid.MainActivity"

【讨论】:

【参考方案6】:

最简单和最干净的解决方案是只保留一个 Manifest 并为每种风格编写两个不同的 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。【参考方案7】:

最简单的解决方案是使用清单合并和使用

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

按照以下帖子中的建议:

Merging android manifest files, conflicting filter

【讨论】:

以上是关于如何在产品风味中使用不同的启动器活动?的主要内容,如果未能解决你的问题,请参考以下文章

如何启动在与小部件不同的包中定义的活动?

如何自定义产品风味的 APK 文件名?

在 Gradle 产品风味上调试签名配置

如何在 Android Studio 中使用具有不同应用名称的风味?

如何在活动启动时在recyclerview中显示已选中的复选框(多对多关系)

如何在活动中显示计时器?