动态配置LauncherActivity/根据不同资源文件生成apk

需求

1.同一份代码,采用三份不同的资源文件,生成三个不同的apk;

2.同一份代码,采用相同代码和资源文件,仅有LauncherActivity不同,生成两个apk;

经过一番查询,以上需求可以通过Gradle中配置ProductFlavors完美解决。

BuildVariants基本知识

使用manifestPlaceholders改变 meta-data

标签meta-data是提供组件额外的数据用的,它本身就是一个键值对,可以自定义名称和值。它可以包含在以下组件当中:activity\application\service\receiver。

manifestPlaceholders的作用 :在build.gradle文件中定义字符串并将值映射到 AndroidManifest清单文件的指定位置.

1.AndroidMenifest.xml中添加meta-data

1
2
3
<meta-data
android:name="APP_CHANNEL"
android:value="${APP_CHANNEL_VALUE}"/>

2.build.gradle(Moudle)中添加(以下两种写法相同)

1
2
3
4
5
6
7
8
productFlavors{
eyewatch {
manifestPlaceholders = [APP_CHANNEL: "eyewatch"] }
ipremium {
manifestPlaceholders = [APP_CHANNEL: "ipremium"] }
echo {
manifestPlaceholders = [APP_CHANNEL: "echo"] }
}
1
2
3
4
5
6
7
8
productFlavors {
eyewatch {}
ipremium {}
echo {}
productFlavors.all { flavor ->
flavor.manifestPlaceholders = [APP_CHANNEL: name]
}
}
构建变体BuildType

当创建工程时,Android Studio会自动生成debug/release两种buildtype,我们可以根据自己定义生成更多的buildtype

productFlavors支持与 defaultConfig 相同的属性(defaultConfig 实际上属于 ProductFlavor 类)。这意味着,您可以在 defaultConfig {} 代码块中提供所有风味的基本配置,每种风味均可更改任何这些默认值。

buildType x productFlavor x flavorDimensions = 生成的APK数量

buildtype和productFlaovr的关系

assemble命令简介
1
2
3
4
5
6
7
8
./gradlew assembleDebug 
编译并生成Debug包,包含productFlavors下所有定义的产品或渠道包
./gradlew assembleRelease
编译并生成Release包,包含productFlavors下所有定义的产品或渠道包
./gradlew assembleProductARelease
编译并生成Release包,包含pProductA下所有定义的产品或渠道包
./gradlew assembleProductADebug
编译并生成Debug包,包含pProductA下所有定义的产品或渠道包
flavor跟main的文件合并规则

①java中代码合并,如果有相同的文件是会报错重复错误的,所以main文件夹中,应该存放共有的代码,而flavor文件夹中存放自己所需要的独立的代码。
②res中资源的合并,优先级是flavor高于main,即flavor中资源会加入或覆盖main中资源。如果falvor渠道要求指定的icon和appName,则在special中res中替换到默认的icon,在string.xml中改正相应的appName即可。

需求1.同一份代码,不同资源文件

在/src中,main同级目录新建对应falvor名称的文件夹。各个falvor文件内目录应与main目录结构完全一致,需要替换的资源文件名字也要相同。如/eyewatch/drawable/bg.png 与 /main/drawable/bg.png。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
defaultConfig {
applicationId "com.echo.settings"
minSdkVersion 19
targetSdkVersion 22
versionCode 1
versionName "1.2"
flavorDimensions "versionCode"
//执行lint检查,有任何的错误或者警告提示,都会终止构建,我们可以将其关掉。
lintOptions {
abortOnError false
checkReleaseBuilds false
}

buildTypes {
debug {
// 显示Log
buildConfigField "boolean", "LOG_DEBUG", "true"

versionNameSuffix "-debug"
minifyEnabled false
zipAlignEnabled false
shrinkResources false

android.applicationVariants.all { variant ->
variant.outputs.all {
outputFileName = "Settings_v${defaultConfig.versionName}_${releaseTime()}_${variant.productFlavors[0].name}.apk"
}
}
}
}

// 多渠道打包
productFlavors {
echo {}
eyewatch {}
ipremium {}
}


productFlavors.all { flavor ->
flavor.manifestPlaceholders = [APP_CHANNEL_VALUE: name]
}

需求2.同一份代码,不同LauncherActivity

在/src中main同级目录中创建对应flavor文件夹,复制一份manifest.xml文件。

将原LauncherActivity下 添加 tools:node=”merge”,Intent-filter中添加 tools:node=”remove”

1
2
3
4
5
6
7
8
9
10
11
12
13
<activity
android:name=".app.launcher.Launcher"
android:launchMode="singleTask"
android:exported="true"
android:screenOrientation="landscape"
tools:node="merge"
>
<intent-filter tools:node="remove">
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
<category android:name="android.intent.category.LEANBACK_LAUNCHER"/>
</intent-filter>
</activity>

在对应想要启动的Activity下设置即可。

1
2
3
4
5
6
7
8
9
10
11
<activity
android:name=".app.launcher.SimpleLaunch"
android:exported="true"
android:launchMode="singleTask"
android:screenOrientation="landscape">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
<category android:name="android.intent.category.LEANBACK_LAUNCHER"/>
</intent-filter>
</activity>

meta-data

ProductFlavor

AndroidSourceSet

合并多个清单文件

使用gradle的productFlavors实现Android项目多渠道打包

Android Gradle manifestPlaceholders 占位符详解