程序员

Android Studio使用Gradle构建示例

2018-10-04  本文已影响9人  xiongmao_123

前言

最近遇到了问题,大概是 APPT2 ERROR 错误,这个错误很常见,说的是 .9图片 有问题,但是网上的回答都非常的零散和不够系统。编译的时候从 LOG终端 中也看不了太多信息。网上的建议是加编译参数 --stacktrace --debug ,所以就想着把 Gradle 构建系统详细了解下。
以下说的大多是学习总结,一些概念可能描述的不准确,更多信息请参考文中和文末的资料链接。

问题

  1. Android Studio, Gradle, Groovy 的关系
  2. Android Studio 生成的项目中 build.gradle , settings.gradle , gradle.properties , gradle-wrapper.properties 这些文件的作用
  3. 如何构建不同渠道的多个包
  4. 如何构建服务器地址不同的包,甚至逻辑不同的版本,而不是新开分支

回答

Android Studio, Gradle, Groovy 的关系
Android Studio 生成的项目中 build.gradle , settings.gradle , gradle.properties , gradle-wrapper.properties 这些文件的作用
如何构建不同渠道的多个包

这个问题和接下来的问题,将涉及到两个主要概念,build typesproduct flavors ,这两个概念弄明白了,我们的问题也就差不多解决了。 build types 是什么? build types 是站在程序员的角度来说的,比如 debug , release 版本,它并不为终端用户所感知。而 product flavors 则可以理解为面向终端用户的,比如 免费版付费版 ,又比如各大应用市场的不同版本。

我们看个复杂的实例,构建不同渠道的免费和收费的DEBUG、RELEASE两种版本。这个例子分开来看的话,一共是3个阶段。第一阶段,构建 releasedebug 版本;第二阶段,构建 channel1channel2 两个不同渠道的版本;第三阶段,构建 freepay 收费模式版本。组合起来的话,一共 2*2*2 最终会构建成 8 版本。

buildTypes 构建apk类型,即 debugrelease ; productFlavors 构建用户感知的app变体,即不同的app; flavorDimensions 构建多维度的 flavor,可以理解为多维度的用户使用情形。比如该例子说的是,既要区分不同渠道,又要对不同渠道做 freepay 两种产品的区分。具体的写法参考下面的 build.gradle 中的代码。下面的代码也展示如何在 AndroidManifest.xml 中插入我们配置的值,以及如何在 build.gradle 中配置运行时变量。 在项目代码中还展示了如何读取 meta-data 的值和在 build.gradle 中配置的值。

当我们 sync 我们的项目时,IDE中的 Build Variants 选项卡也会出现对应的各种APP变体。更官方的 Build Variants 可以参考这里,而 build.gradleblock代码 块中的属性值或方法具体是什么意思或该怎么用,可以参考这里

下面是我们编译出来的共 8 个APP变体。 8 种不同的 flavors

app-channe2-free-debug.apk
app-channe2-free-release.apk
app-channe2-pay-debug.apk
app-channe2-pay-release.apk
app-channel-free-debug.apk
app-channel-free-release.apk
app-channel-pay-debug.apk
app-channel-pay-release.apk

//默认配置
defaultConfig {

    //应用包名,注意和 AndroidManifest.xml 中的 packageName 区别,
    //后者影响资源的R类的生成; 前者是唯一包名
    applicationId "com.bbg.gradledemo"          
                        
    minSdkVersion 16
    targetSdkVersion 25
    versionCode 1
    versionName "1.0"
    testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"

    //manifest 占位符, map类型
    //buildConfigField 生成 BuildConfig 类的静态值,可以代码访问
    //
    manifestPlaceholders = ["KEY_TYPE": "KEY-default"]      
    buildConfigField("String", "var1", "\"var-default\"")   
                                                            
}

//签名配置
signingConfigs {
    config {
        keyAlias 'key0'
        keyPassword '123456'
        storeFile file("$rootProject.rootDir/keystore.jks")
        storePassword '123456'
    }
}

//build types
buildTypes {
    release {
        minifyEnabled true
        debuggable true
        shrinkResources true
        zipAlignEnabled true
        proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        signingConfig signingConfigs.config
        applicationIdSuffix ".release"
    }
    debug {
        minifyEnabled true
        debuggable true
        shrinkResources true
        zipAlignEnabled true
        proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        signingConfig signingConfigs.config
        applicationIdSuffix ".debug"
    }
}

//多维度flavor解决方法,前后顺序影响生成的 variants 类型
//然后在product flavors 指定 deminsion 

flavorDimensions "channel", "mode"

productFlavors {
    channel {
        dimension "channel"
        manifestPlaceholders = ["KEY_TYPE": "KEY-channel"]
        buildConfigField("String", "var1", "\"var-channel\"")
    }
    channe2 {
        dimension "channel"
        manifestPlaceholders = ["KEY_TYPE": "KEY-channe2"]
        buildConfigField("String", "var1", "\"var-channe2\"")
    }

    free {
        dimension "mode"
        buildConfigField("String", "mode", "\"mode-free\"")
    }

    pay {
        dimension "mode"
        buildConfigField("String", "mode", "\"mode-pay\"")
    }
}
为不同的Flavor变体加入不同的资源和逻辑

从上面中的回答,我们可以知道,这种方式已经可以满足我们提出的要求了。一些不同的 Build Variants , 可以根据变量值,在代码中进行设置,进行不同的逻辑处理。 假如我们不同的 Variants 需要不一样的启动图标,甚至逻辑部分不同,有没有另外的解决方案。答案是有的,当我们在 build.gradle 中配置了 buildTypsproductFlavors 的时候,Android Studio 就逻辑关系将每个源代码和资源分组为 源集

Android Studio 按逻辑关系将每个模块的源代码和资源分组为源集。模块的 main/ 源集包括其所有构建变体共用的代码和资源。其他源集目录为可选项,在您配置新的构建变体时,Android Studio 不会自动为您创建这些目录。不过,创建类似于 main/ 的源集有助于让 Gradle 只应在构建特定应用版本时使用的文件和资源井然有序

如果不同的 源集 包含同一文件的不同版本,Gradle 将按以下优先顺序决定使用哪一个:

构建变体 > 构建类型 > 产品风味 > 主源集 > 库依赖项

我们实践下,我们把上面的 channe2 变体的应用图标修改,把第一次进入时候的是否 pay 的逻辑改成 free 。具体的代码请参考Github。我们创建文件时,可以借助 IDE 来选择不同的 源集。这样我们的 app 目录结构大概是这样:

```
app
|
└─src
    ├─androidTest
    │  └─java
    │      └─com
    │          └─bbg
    │              └─gradledemo
    ├─channe2
    │  └─res
    │      ├─mipmap-xhdpi
    │      └─values
    ├─free
    │  ├─java
    │  │  └─com
    │  │      └─bbg
    │  │          └─gradledemo
    │  └─res
    │      └─values
    ├─main
    │  ├─java
    │  │  └─com
    │  │      └─bbg
    │  │          └─gradledemo
    │  └─res
    │      ├─drawable
    │      ├─layout
    │      ├─mipmap-hdpi
    │      ├─mipmap-mdpi
    │      ├─mipmap-xhdpi
    │      ├─mipmap-xxhdpi
    │      ├─mipmap-xxxhdpi
    │      └─values
    ├─pay
    │  ├─java
    │  │  └─gradledemo
    │  └─res
    │      └─values
    └─test
        └─java
            └─com
                └─bbg
                    └─gradledemo


```

我们在 chane2 变体中引入 ic_launcher,在 payfree 变体中处理是否收费逻辑。编译的时候,可以把我们想要的都一起编译出来,实现自动化,简直完美。显然, gradle 知道该如何合并。我们可以参考这里,了解是 gradle 是如何处理合并的。

结尾

到这里,我们顺利的解决了提出的问题。发现 GRADLE 构建系统太出色了。这么好的工具,当然要用起来。期间查阅学习了较多资料,写成此文,希望对读者有帮助。文中有较多参考链接可以扩展查阅,最后末尾附上一些相关的参考补充资料。

如果文章对你有帮助,请点小心心或赞赏支持。欢迎留言交流。

Gradle 完整指南(Android)
深入理解Android(一):Gradle详解
构建配置
Groovy File IO Document
gradle 编译不过,Build可以问题解决方法
gradle实战
Android SDK构建视频
Android Gradle
Build Type, Flavour and Build Variant

上一篇 下一篇

猜你喜欢

热点阅读