Android编译变体配置简介-构建不同版本类型(buildTypes)和多渠道打包(productFlavors)

2,020 阅读5分钟

一、概述

在Android开发中,我们需要构建不同的版本类型(Relase、Debug、Alpha),或者是不同渠道(豌豆荚、小米、三星等),这些都可以配置编译变体来实现,本文就是希望通过简短且概括性的文字来进行解释。

以下内容均可在Google官方文档中找到,详看:配置编译变体

二、使用buildTypes构建不同版本类型

什么叫不同版本类型?根据我的理解就是,Google提供了一系列属性(参考:版本类型 DSL参考),然后我们可以根据需要为不同版本配置不同的属性,从而实现打出来差异化的包。

如果你没接触过,你应该会觉得很抽象,举个例子:

比如说,我要给当前项目构建两种包(Debug和Release),Debug版本可以支持adb debug,Release版本则不行,同时Debug版本的包名后缀需要在原有基础上增加“.debug”,那么我们就可以通过配置buildTypes来实现,代码如下:

1.修改app目录下的build.gradle文件

⚠️注意:release版本里面一定要加上签名,不然打出来的包安装不了,会提示没有签名信息!!签名过程这里不赘述了,不懂的同学也是自行搜索。

android {
    //...
    
    buildTypes {
        release {
            minifyEnabled true
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
            // release版本签名
            signingConfig signingConfigs.release
        }

        debug {
            applicationIdSuffix ".debug"
            debuggable true
        }
    }
    
    //...
}

2.同步代码

一般修改build.gradle后,都会要求你Sync Now,不懂怎么同步代码的同学自行搜索。

3.编包

在Teminal执行命令gradlew assemble,编译成功会提示如下:

image

然后打开你的目录app下的build/apk/目录,下面多了两个文件夹,分别是debug和release,里面分别有两个apk,如下图所示。

image

4.验证

分别安装两个app,我们就可以验证它们是否满足我们的要求。

首先安装debug目录下的apk,打开调试工具可以看到,包名确实变成了“.debug”结尾,并且是可以调试的。

image

再来看relase包,安装后在调试工具看不到对应的可调试app,因为我们没有设置它是debuggable,通过pm list packages命令查看已安装app,确实有一个com.ryan.testbuildtype的app,跟debug包的包名是不一样的。

image

由此验证得知,确实可以通过buildTypes来构建不同类型的包,当然,在版本类型 DSL参考里面提供了很多不同的属性,如是否可以调试JNI代码的属性jniDebuggable、是否打开Proguard的属性useProguard、是否压缩资源文件的属性shrinkResources等,你都可以根据自己的需求来进行构建不同属性类型的包。

三、使用productFlavors实现多渠道打包

在Google官方的解释是productFlavors是用以构建不同产品特性使用的,但是国内的开发者都喜欢用以实现多渠道打包,所以本文暂且这么来写。

我们都知道通过buildTypes可以实现构建不同属性的包,但是针对不同类型维度的打包,确实有心无力,怎么说?

比如,我们需要构建不同区域的包,实现内容是一样的,但是所有网络请求的域名随区域的变化而变化,假如我们在代码中通过if-else来实现,会显得非常冗余,下面就以这个例子来讲解productFlavors的使用。

1.首先在app目录下的build.gradle文件增加productFlavors属性

首先需要定义一个flavorDimensions,例如我定义的是location作为区分维度。假如你有多个维度,那么最终就会构建出来几个维度多种组合的包。

android {
    // ...
     // 特性维度
    flavorDimensions "location"
    productFlavors {
        guangzhou{
            dimension "location"
        }

        chengdu {
            dimension "location"
        }
    }
    // ...
}

2.同步代码

3.在src目录创建对应flavor的目录

如我们要根据地区,构建不同的ip地址,那么我们就可以把ip定义到java文件里面,在app目录下的src目录,右键new->Folder->Java Folder,然后选择对应的flavors,如本例中的guangzhou,就会生成一个guangzhou的目录,然后在java目录下新建一个包名(这个是必须要的),然后创建一个文件,如下图所示:

image

然后在里面定义广州的域名:

public class MyConstants {
    public static final String DOMAIN = "http://www.guangzhou.com";
}

同样地,创建成都的目录,并创建同样的包名和类名,并创建同样的变量:

public class MyConstants {
    public static final String DOMAIN = "http://www.chengdu.com";
}

也许你的java文件变成了红色,如下图所示:

image

不用担心,只是你当前的flavor是广州而已,选择as左下角的Build Variants,切换到成都的flavor,你的文件就是正常的类了。

image

4.在main目录下的文件引用不同flavor的属性

为了测试方便,我们就在MainActivity中打印MyConstants的值即可,代码如下所示:

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);


        TextView textView = findViewById(R.id.tv_text);
        textView.setText(MyConstants.DOMAIN);
    }
}

使用teminal打包,构建出两个flavor的debug包:

image

分别安装,可以看到最终打印的域名是不一样的,从而实现了不同渠道打包:

image

image

当然,这只是非常简单的应用,当你需要进行更大代码差异化的时候,也可以利用productFlavors来划分特性,从而可以同时构建出不同渠道的apk,避免在代码中进行冗杂的if-else判断。