Android—Gradle教程(四)

前言

在上一篇中已经讲到Gradle的依赖管理相关的知识点,在这一篇中将会对Gradle的配置以及产品风味进行详解。

版本说明

  • 关于Andoird构建配置的相关文档,推荐官方这个文档
  • 后面讲到的Andorid构建配置都是针对的AGP4.2.0以上版本,请悉知

1、android{}

android{},由AGP引入的节点:

  • compileSdkVersion:编译使用版本
  • buildToolsVersion:buildTools版本
  • defaultConfig:默认产品风味
  • productFlavors:自定义产品风味
  • buildTypes:构建类型
  • compileOptions:编译选项
  • signingConfigs:签名设置

相信所有读者看到这都非常熟悉这一段节点,前两个版本就不过多讲解了,直接从defaultConfig开始讲解。

1.1 defaultConfig{}:默认产品风味

plugins {
    id 'com.android.application'
    id 'kotlin-android'
}
// 上面闭包引入的 application gradle脚本与下面这个单独引入gradle脚本一致
// apply plugin: 'com.android.application'


// AGP
//com.android.application提供
// 配置安卓工程的构建
android {
    compileSdkVersion 30 // 编译时使用SDK的版本
    // ProductFlavor:产品风味,针对一次Android应用构建的设置
    // defaultConfig默认的产品风味
    defaultConfig {
        applicationId "com.hqk.gradledemo03" //不一定是包名
        applicationIdSuffix "aaa" // 往applicationId加后缀 ,applicationId+applicationIdSuffix 才是应用标识,才是包名 
        minSdkVersion 21 // 最小的支持的Android系统版本
        targetSdkVersion 30 // 针对开发的使用的Android SDK版本,一般compileSdkVersion保持一致
        versionCode 1 // 这个应用的版本号
        versionName "1.0" // 这个应用的版本名称
        //versionNameSuffix '' //versionName后缀
        manifestPlaceholders = [CHANNEL_VALUE: 'hqk'] //默认设置AndroidManifest占位符类型
        //testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" // Gradle引擎
    }

...略
...略
}

首先第一句,通过 代码id 'com.android.application' 将 AGP(Android Gradle Plugin)脚本插件引入进来,其次再通过android {}闭包配置编译相关的内容。

而这里的AGP又是在项目根目录对应的build.gradle里面的classpath "com.android.tools.build:gradle:4.2.1"引入进来的。kotlin 脚本插件亦是如此!

注意:这里有个问题是容易被忽略的。

请问一下 applicationId 一定能代表是APK的包名么?

答案当然是不一定的,注意看我在后面加了 applicationIdSuffix 这个属性,编译后我们看看编译后的AndroidManifest.xml文件:

Android—Gradle教程(四)

当然这个有点哗众取宠了,毕竟大多数都用不了这个加后缀这个东西,后面的 versionNameSuffix 依是如此。接下来继续下一个专题。

1.2 buildTypes {}:构建类型

android {

...略
    // 配置应用的签名信息
    signingConfigs {
        release {
            storeFile file('key_store.jks')
            storePassword "a123123"
            keyAlias "aaa"
            keyPassword "a123123"
        }
        debug {
            storeFile file('key_store.jks')
            storePassword "a123123"
            keyAlias "aaa"
            keyPassword "a123123"
        }
    }
    
    // 构建类型: debug, release
    buildTypes {
        release {
//            zipAlignEnabled true// 是否开启 zipAlign
            shrinkResources true // 清理无效资源
            minifyEnabled true // 是否启用代码混淆
            // 指定代码混淆的配置文件
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
            signingConfig signingConfigs.release //配置对应类型的签名文件
        }
//        debug{
//
//        }
//        custom{
//            initWith release
//        }
    }

...略

}

在 buildTypes 闭包里面,你可以创建对应build 类型。当您创建新模块时,Android Studio 会自动为您创建“debug”build 类型和“release”build 类型。即使没有在 buildTypes 里面创建 debug类型,但 Android Studio 会使用 debuggable true 配置它。这样,您就可以在安全的 Android 设备上调试应用,并使用常规调试密钥库配置 APK 签名。

而签名配置里面无非就是 releasedebug配置,如果配置签名的话,AndroidStudio将会使用默认配置签名,对应目录文件:C:\Users\用户主机名\.android\debug.keystore

接下来就引来了比较常用但又不常用的东西了 productFlavors(自定义产品风味)

1.3 productFlavors{} :自定义产品风味

android {
...略

    flavorDimensions "channel" // 维度,就是针对一种类型的产品风味的描述
    
    // 产品风味的自定义,也就是变种
    productFlavors {
        huawei {
            dimension "channel"
            manifestPlaceholders = [CHANNEL_VALUE: 'huawei']
        }

        xiaomi {
            dimension "channel"
            manifestPlaceholders = [CHANNEL_VALUE: 'xiaomi']
        }

        oppo {
            applicationId "com.oppo.gradledemo03"
            //applicationIdSuffix "aaa" 
            dimension "channel"
            manifestPlaceholders = [CHANNEL_VALUE: 'oppo']
        }
        
    }

...略
}

当我们上架不同的应用市场或者跟第三方合作的时候,阔能会存在这个需求,不同的渠道需要不同的定制化打包,此时这个就派上用场了。

首先你要定义一个flavorDimensions 用来表示对应多渠道的维度描述,随后通过productFlavors里面的闭包创建不同平台或不同合作商的渠道,对应渠道里面可以配置不同的内容,对应的内容与defaultConfig内容一致。

比如说,你可以实现,不同渠道能打出不同渠道标识号CHANNEL_VALUE 以及不同的应用包名applicationId+applicationIdSuffix,甚至不同渠道不同的应用版本也能实现等等。

这个功能是不是很香?哈哈哈,看看效果。

Android—Gradle教程(四)
如图所示

打包编译的时候,就能看到我们刚刚配置的多渠道打包选项,将它全部选择点击finish看最终效果。

Android—Gradle教程(四)
如图所示

这边已经完美的打包好了不同渠道对应的APK,并且对应oppo下的apk应用包名已经变成了oppo相关的。

注意:配置oppo应用包名的时候,并没有配置applicationIdSuffix属性,但是打包好的oppo对应的apk包名却有后缀,往上看发现 defaultConfig里面applicationIdSuffix属性还在。也就是说,下面多渠道没有配置的内容将会默认使用defaultConfig里面的属性。

我们刚刚配置了 不同渠道对应的CHANNEL_VALUE值是不同的,那么该如何通过逻辑代码获取呢?

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        
        var textViewTxt=findViewById<TextView>(R.id.text_txt)
        var appInfo=packageManager.getApplicationInfo(packageName, PackageManager.GET_META_DATA)
        var appName=appInfo.loadLabel(packageManager)
        var appChannel=appInfo.metaData.getString("CHANNEL_VALUE")
        textViewTxt.text=appChannel
    }
}

对应AndroidManifest.xml文件加入如下代码

        <meta-data
            android:name="CHANNEL_VALUE"
            android:value="${CHANNEL_VALUE}" />

注意:这里的CHANNEL_VALUE一定要和build.gradle里面一一对应上。

再次打包运行下看看效果:

Android—Gradle教程(四)
完美运行成功,效果也按照预期实现了。但现在有个问题就是,不同渠道版本名字格式都一样,那如何吧版本号加上去?

    applicationVariants.all { variant ->
        variant.outputs.all { output ->
            def outputFile = output.outputFile
            if (outputFile != null && outputFile.name.endsWith('.apk')) {
                // 遍历所有的产品风味
                productFlavors.each { flavor ->
                    //app_v1.0_huawei_release.apk
                    def fileName = "app_v${defaultConfig.versionName}_${flavor.manifestPlaceholders.CHANNEL_VALUE}_${variant.getName()}.apk"
                    outputFileName = fileName
                }
            }
        }
    }

这段代码的意思就是,获取所有的渠道列表将里面对应渠道号里不同的版本不同类型进行命名操作。现在重新编译打包所有看看效果:

Android—Gradle教程(四)

这里也如愿的变成了想要的效果。不过现在又有个问题,就是配置了这么多渠道包,我不想每次都打包所有,我想直接运行我想要的渠道号以及对应的debug/release版本那该怎样操作呢?

Android—Gradle教程(四)

如图所示

按照数字依次操作,先点击AndroidStudio里面的Build Variants选项,其次再选项卡选择你想运行的版本类型,最后就可以点击AndroidStudio上面的运行按钮直接运行安装在你的测试机上了。想要切换其他版本再次按照这样的顺序切换即可。

结束语

本篇到这里差不多结束了,相信在这一篇和上一篇中,你已经完全理解了我们在Gradle常用的相关功能。在下一篇中,将会更进一步的深入Gradle。

上一篇:RabbitMQ详解


下一篇:Fabric v2.3测试网络 - 创建通道 返回结果分析