如何在产品风味中使用不同的启动器 activity?
How to use a different launcher activity in a product flavor?
我正在开发一个 Android 库项目,在默认 src/main/AndroidManifest.xml 中,MainActivity 是启动器 activity.
为了其他事情,我创建了产品口味。是的,如果我想在不同的产品口味中触发/显示不同的活动,它就完美了。但是,我想保留 默认启动器 activity 来自 src/main/ 文件夹,同时注册另一个风味 activity 作为新的启动器 activity。因此,对于不同的产品口味,我可以有不同的启动器活动,并且从它们我仍然可以在 src/main/.
中开始原始的 "launcher" activity
谁能告诉我如何实现它?非常感谢。
备注:
不推荐将 if (BuildConfig.FLAVOR.equals("flavorName"))
代码添加到原始启动器 activity。因为我不想修改别人的生产代码(这是一个库项目)。
我试过 manifestmerger
和 tools:replace
,但似乎对 intent-filter
不起作用(我注意到 intent 的元素合并策略-过滤器总是)。
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
如果这可行,能否请您指导我如何使它工作?谢谢。
我尝试过的:
- 启用清单合并,这不起作用;
- 使用 activity-alias,这也不起作用。
最后发现加一行就可以解决问题了:
<category android:name="android.intent.category.DEFAULT" />
============================================= =====
为了说清楚,我将再过一遍问题和解决方案:
在src/main/java
下面有一个MainActivity
,在对应的src/main/AndroidManifest.xml
里面指定了MainActivity作为启动器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>
这是一个非常简单的部分。现在我们从产品风味部分开始。
由于某种原因,在产品风味中,我不想覆盖 MainActivity,而是有一个 YetAnotherMainActivity
。目标是 将 YetAnotherMainActivity
设置为产品风味中的新启动器 activity,它应该仍然可以调用 MainActivity
。
在这里,您可以将产品风味中的新 activity 设置为新启动器 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>
是的,事实证明这非常容易。只需添加 android.intent.category.DEFAULT
.
最简单和最干净的解决方案是只保留一个 Manifest 并编写两个不同的 MainActivity.java class 每个 flavor 一个,以避免清单节点重复。
在 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>
最简单的工作解决方案是使用清单合并并使用
<intent-filter tools:node="removeAll">
如下所示 post :
Merging android manifest files, conflicting filter
我认为 <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。所以,我们只需要替换指定的 <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>
备注:
- 在示例中,我们为
main
和 debug
使用相同的包名称。
- 我们必须输入activity-别名的全名,这样合并才能正确合并它们。
通过解决方案,我们还可以从 main
activity 别名继承所有属性和子项,而不是在 debug
.
中重复它们
根据您的风格创建一个不同的 AndroidManifest.xml 文件。然后将您的 DifferentFlavorMainActivity.java 设置为启动器 activity,全名如下:
android:name="com.android.application.paid.MainActivity"
我想我没有迟到:)
所以今天我遇到了同样的问题。 @seroperson 解决方案是正确的,但如果您根本不需要默认启动器 activity,则只需在您的口味清单中使用以下代码:
<activity
android:name=".DefaultLauncherActivity"
tools:node="remove"
>
Android 合并正在将 intent-filter 从主清单 lancher 合并到 flavors。我还没有找到防止这种情况发生的方法。您最终在设备上有 2 个应用程序图标(每个用于启动器 Activity)。
基于此,您无法完全覆盖主清单中的设置。 Solition 可能是在主文件夹中仅保留 shell 的清单并在每个版本中实现清单,或者从主文件夹中删除冲突活动并在每个版本中独立实现。
<?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>
我正在开发一个 Android 库项目,在默认 src/main/AndroidManifest.xml 中,MainActivity 是启动器 activity.
为了其他事情,我创建了产品口味。是的,如果我想在不同的产品口味中触发/显示不同的活动,它就完美了。但是,我想保留 默认启动器 activity 来自 src/main/ 文件夹,同时注册另一个风味 activity 作为新的启动器 activity。因此,对于不同的产品口味,我可以有不同的启动器活动,并且从它们我仍然可以在 src/main/.
中开始原始的 "launcher" activity谁能告诉我如何实现它?非常感谢。
备注:
不推荐将
if (BuildConfig.FLAVOR.equals("flavorName"))
代码添加到原始启动器 activity。因为我不想修改别人的生产代码(这是一个库项目)。我试过
manifestmerger
和tools:replace
,但似乎对intent-filter
不起作用(我注意到 intent 的元素合并策略-过滤器总是)。
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
如果这可行,能否请您指导我如何使它工作?谢谢。
我尝试过的:
- 启用清单合并,这不起作用;
- 使用 activity-alias,这也不起作用。
最后发现加一行就可以解决问题了:
<category android:name="android.intent.category.DEFAULT" />
============================================= =====
为了说清楚,我将再过一遍问题和解决方案:
在src/main/java
下面有一个MainActivity
,在对应的src/main/AndroidManifest.xml
里面指定了MainActivity作为启动器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>
这是一个非常简单的部分。现在我们从产品风味部分开始。
由于某种原因,在产品风味中,我不想覆盖 MainActivity,而是有一个 YetAnotherMainActivity
。目标是 将 YetAnotherMainActivity
设置为产品风味中的新启动器 activity,它应该仍然可以调用 MainActivity
。
在这里,您可以将产品风味中的新 activity 设置为新启动器 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>
是的,事实证明这非常容易。只需添加 android.intent.category.DEFAULT
.
最简单和最干净的解决方案是只保留一个 Manifest 并编写两个不同的 MainActivity.java class 每个 flavor 一个,以避免清单节点重复。
在 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>
最简单的工作解决方案是使用清单合并并使用
<intent-filter tools:node="removeAll">
如下所示 post :
Merging android manifest files, conflicting filter
我认为 <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。所以,我们只需要替换指定的 <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>
备注:
- 在示例中,我们为
main
和debug
使用相同的包名称。 - 我们必须输入activity-别名的全名,这样合并才能正确合并它们。
通过解决方案,我们还可以从 main
activity 别名继承所有属性和子项,而不是在 debug
.
根据您的风格创建一个不同的 AndroidManifest.xml 文件。然后将您的 DifferentFlavorMainActivity.java 设置为启动器 activity,全名如下:
android:name="com.android.application.paid.MainActivity"
我想我没有迟到:) 所以今天我遇到了同样的问题。 @seroperson 解决方案是正确的,但如果您根本不需要默认启动器 activity,则只需在您的口味清单中使用以下代码:
<activity
android:name=".DefaultLauncherActivity"
tools:node="remove"
>
Android 合并正在将 intent-filter 从主清单 lancher 合并到 flavors。我还没有找到防止这种情况发生的方法。您最终在设备上有 2 个应用程序图标(每个用于启动器 Activity)。
基于此,您无法完全覆盖主清单中的设置。 Solition 可能是在主文件夹中仅保留 shell 的清单并在每个版本中实现清单,或者从主文件夹中删除冲突活动并在每个版本中独立实现。
<?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>