productFlavors多马甲打包
先上官方文档,写的很不错了,地址:https://developer.android.com/studio/build/build-variants?utm_source=android-studio#product-flavors
这里只是总结下用法和一些注意点。
背景
有时候公司需要我们打很多马甲包(改包名和名字,其他一样的)、或者对不同应用市场的渠道包(应用图标不同、启动图或者厂商的推送分开集成)等需求,就可能需要创建很多项目去单独修改,很是麻烦。但是google提供了这种多变种配置来处理这种清空
配置构建变体
debug和release变体
可以在模块级 build.gradle 文件中的 android 代码块内创建和配置构建类型。当您创建新模块时,Android Studio 会自动为您创建“debug”构建类型和“release”构建类型。虽然“debug”构建类型没有出现在构建配置文件中,但 Android Studio 会使用 debuggable true 配置它。这样,您就可以在安全的 Android 设备上调试应用,并使用常规调试密钥库配置 APK 签名。——官方解释
就是我们可以在模块级中给debug和release配置不同的参数和配置项,比如签名信息、是否开启zip、区分包命名、manifestPlaceholders等参数等,方便你测试不同情景。我觉得其实这是一个更好的约束,是对release包防护吧。
注意
注意:官方文档里定义了如下属性
debug {
applicationIdSuffix ".debug"
debuggable true
}
applicationIdSuffi
意思就是针对目标版本替换了新包名。其实我们对于debug和release区别只是要求配置参数不同,而不是要求不同包名,对于大部分需求其实不需要包名的对照,而是需要配置参数的对照。当然你需要同时安装debug包或者release包还是可以配置的。
常规配置
buildTypes {
//定义2个
def buildrelease
def builddebug
buildrelease = {
minifyEnabled true
zipAlignEnabled true
shrinkResources true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard.cfg'
buildConfigField "boolean", "LOGENABLE", log
buildConfigField "String", "APIENV", '"' + environment + '"'
manifestPlaceholders = [AMAP_KEY : "release"
, CC_EXPORTED : 'false'
, LICENSE_KEYBOARD: '654321']
}
builddebug = {
minifyEnabled false
zipAlignEnabled false
shrinkResources false
//设置签名
signingConfig signingConfigs.testConfig
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard.cfg'
buildConfigField "boolean", "LOGENABLE", log
buildConfigField "String", "APIENV", '"' + environment + '"'
manifestPlaceholders = [AMAP_KEY : "debug"
, CC_EXPORTED : 'true'
, LICENSE_KEYBOARD: '123456']
}
release buildrelease
debug builddebug
}
反正你觉得要隔离debug和release都可以这里区分。
配置风味版本
如果需要多条产品线配置不同内容,并且在一个编译版本上,就需要配置productFlavors
代码块。在新的3.0版本上,需要配置flavorDimensions
增加多个纬度。
flavorDimensions "app"
//设置渠道
productFlavors {
teacher {
dimension "app"
manifestPlaceholders = [
package : "com.hujin.student",
WAN_CHANNEL_VALUE: "teacher",
name : "老师端"]
signingConfig signingConfigs.debug
applicationId "com.hujin.wan"
}
student {
dimension "app"
manifestPlaceholders = [
package : "com.hujin.student",
WAN_CHANNEL_VALUE: "studnet",
name : "学生端"]
signingConfig signingConfigs.debug
applicationId "com.hujin.student"
}
}
更多配置
这样就会生成debug-release * teacher-student 四个包。
还可以配置多个纬度的包,设置不同的dimension
。还可以设置过滤规则variantFilter
。
flavorDimensions "app","size"
//设置渠道
productFlavors {
teacher {
dimension "app"
manifestPlaceholders = [
package : "com.hujin.student",
WAN_CHANNEL_VALUE: "teacher",
name : "老师端"]
signingConfig signingConfigs.debug
applicationId "com.hujin.wan"
}
student {
dimension "app"
manifestPlaceholders = [
package : "com.hujin.student",
WAN_CHANNEL_VALUE: "studnet",
name : "学生端"]
signingConfig signingConfigs.debug
applicationId "com.hujin.student"
}
normal{
dimension "size"
}
big{
dimension "size"
}
}
//过滤某个 不能过滤debug 和 release 标示
variantFilter { variant ->
def names = variant.flavors*.name
if (names.contains("normal") && names.contains("student")) {
System.out.println("过滤成功")
setIgnore(true)
}
}
这样就会生成debug-release * teacher-student * big-normal - studentNormalDebug包 - studentNormalRelease包 共 六个包。具体在student左边侧边栏下部可以查看:
可以点击选择切换不同的包后自动同步,完成切换。
除此之外,还可以设置sourceSets
sourceSets {
teacher {
java.srcDirs = ['src/main/java']
manifest.srcFile 'AndroidManifest.xml'
res.srcDirs = ['src/main/res']
}
student {
java.srcDirs = ['src/student/java']
res.srcDirs = ['src/student/res']
manifest.srcFile 'src/student/AndroidManifest.xml'
}
}
还可以配置不同的dependencies
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'androidx.appcompat:appcompat:1.2.0'
implementation 'androidx.constraintlayout:constraintlayout:2.0.1'
studentImplementation 'org.greenrobot:eventbus:3.1.1'
debugImplementation 'com.readystatesoftware.chuck:library:1.1.0'
}
例外还可以设置BuildConfig
,这个可以有很多操作空间了,比如设置不同host。
flavorDimensions "app"
//设置渠道
String hostStudent = "www.baidu.com";
String hostMain = "www.qq.com";
productFlavors {
teacher {
dimension "app"
manifestPlaceholders = [
package : "com.hujin.student",
WAN_CHANNEL_VALUE: "teacher",
name : "老师端"]
signingConfig signingConfigs.debug
buildConfigField ("String", "HOST", '"'+ hostMain + '"')
applicationId "com.hujin.wan"
}
student {
dimension "app"
manifestPlaceholders = [
package : "com.hujin.student",
WAN_CHANNEL_VALUE: "studnet",
name : "学生端"]
signingConfig signingConfigs.debug
buildConfigField ("String", "HOST", '"'+ hostStudent + '"')
applicationId "com.hujin.student"
}
}
设置了HOST,build后会在BuildConfig
下生成HOST字段了,然后再设置网络请求就可以用BuildConfig.HOST
设置达到不同的host效果。
public final class BuildConfig {
public static final boolean DEBUG = Boolean.parseBoolean("true");
public static final String APPLICATION_ID = "com.hujin.wan";
public static final String BUILD_TYPE = "debug";
public static final String FLAVOR = "teacher";
public static final int VERSION_CODE = 1;
public static final String VERSION_NAME = "1.0";
// Fields from product flavor: teacher
public static final String HOST = "www.qq.com";
}
public final class BuildConfig {
public static final boolean DEBUG = Boolean.parseBoolean("true");
public static final String APPLICATION_ID = "com.hujin.student";
public static final String BUILD_TYPE = "debug";
public static final String FLAVOR = "student";
public static final int VERSION_CODE = 1;
public static final String VERSION_NAME = "1.0";
// Fields from product flavor: student
public static final String HOST = "www.baidu.com";
}
举个例子
比如这里配置了studeng风格的包,我需要分别设置不同资源和代码。
对于studeng风格的,资源方面会自动优先寻找studeng包下的资源,如果没有找到则会找默认包下面的资源。
对于代码不同需要设置sourceSets
如上面所说,最重要的是对于不同的包下的
sourceSets {
teacher {
java.srcDirs = ['src/main/java']
manifest.srcFile 'AndroidManifest.xml'
res.srcDirs = ['src/main/res']
}
student {
java.srcDirs = ['src/student/java']
res.srcDirs = ['src/student/res']
manifest.srcFile 'src/student/AndroidManifest.xml'
}
}
AndroidManifest.xml
的合并需要特别注意:具体查看
https://my.oschina.net/wolfcs/blog/550127?fromerr=bHHJWN7F文章。
这里特意设置了不同的风格有自己的AndroidManifest.xml文件。
主:
<?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.hujin.wan">
<application
android:allowBackup="true"
android:name="MyApplication"
android:icon="@mipmap/ic_launcher"
android:label="${name}"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme"
tools:ignore="GoogleAppIndexingWarning">
<activity android:name=".TestActivity"/>
<activity android:name=".MainActivity"
android:label="${name}">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<meta-data
android:name="WAN"
android:value="${WAN_CHANNEL_VALUE}" />
</application>
</manifest>
student:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<application
tools:replace="android:icon, android:theme"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="${name}"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme"
tools:ignore="GoogleAppIndexingWarning">
<activity android:name="com.hujin.student.MainActivity"
android:label="${name}">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<meta-data
android:name="WAN"
android:value="${WAN_CHANNEL_VALUE}" />
</application>
</manifest>
注意点:
- 风格包下的不需要再设置包名了,要不然会冲突。
- 不同icon和风格可适用如下配置
tools:replace="android:icon, android:theme"
- 最好风格包下的类,最好全路径来设置(我的项目上出现类找不到)
- 运行不起来的,可以看下
Project Structure
-Bulid-Variants
下不同变体的各属性是否缺失