Gradle相关配置

1. 自定义字段

在开发的时候需要控制debug、release不同情况下某些开关的控制,如日志打印,debug需要打印,release不需要打印。以前做法是在assets中创建一个config.properties文件,通过读取参数去控制,但是每次release都得去修改,不方便且难免有遗漏。在AS中我们可以在build.gradle配置文件中配置,设置好了之后就直接debug、release即可,无需来回切换修改。

1.1 默认字段

项目中的build.gradle编译之后会生成一个BuildConfig的java文件,其中有部分参数是默认每个APP都会有的,与gradle文件中参数的对应关系如下:

build.gradle文件路径:../app/buildgradle

BuildConfig文件路径:../app/build/generated/source/buildConfig/flavourName(未配置productFlavors,则没有该目录)/debug/包名/BuildConfig

  • DEBUG↔debuggable:

buildTypes {
    debug {
		...
        debuggable true    //是否为debug状态,也可以不配置,默认为true
	}
}

这个参数默认是不用配置的,debug中默认为true,release中默认为false。

但是有些特殊情况下为release模式又需要打印log就可以显示的设置这个值,比如preview预览版本的时候。

  • BUILD_TYPE↔buildTypes中的每种类型的名字,其中debug、release就是BUILD_TYPE的值

buildTypes {
	debug {
		…
	}
	release {
		…
	}
}

  • FLAVOR↔productFlavors中的每种flavor的名字,其中xiaomi、tencent就是FLAVOR的值

productFlavors{
	xiaomi{
		…
	}
	tencent{
		…
	}
}

  • APPLICATION_ID↔applicationId
  • VERSION_CODE↔versionCode
  • VERSION_NAME↔versionName

1.2 自定义字段

除了这些系统预设的字段外,我们自己还可以根据需要设置自己的字段,比如在测试环境和生产环境中baseUrl是不相同的,我们就可以在debug、release中分别设置对应的字段值,这样就不必每次切换了。其中在buildTypes不同模式中公共字段信息我们可以设置在defaultConfig里面,不必再每个buildTypes中都设置。

android {
   defaultConfig { //默认项目配置信息,buildTypes中公共字段可以配置在这里
       …
       //公共字段
       buildConfigField('String', 'logTag', '"TAG"')    //打印日志输出的TAG标记名
       buildConfigField('boolean', 'crashInfoSaveAsJson', 'false') //崩溃日志保存为JSON,否则直接保存为String
    }
    //自定义字段语法 buildConfigField('boolean','API_ENV','true')
   buildTypes { //构建的类型方式
       debug {
           …
           buildConfigField('boolean', 'delAttachment', 'false')   //邮件发送成功后,是否删除附件
           buildConfigField('String', ‘baseUr’l,'"http://www.android.com/test"') //测试网络
        }
 
       release {
           …
           buildConfigField('boolean', 'delAttachment', 'true')    //邮件发送成功后,是否删除附件
           buildConfigField('String', 'baseUrl','" http://www.android.com/product "') //生产网络
        }
    }
}

这里需要注意的值如果是String类型的自定义字段,value需要放在双引号里面,例如:’”TAG”’。 

编译之后就可以直接使用BuildConfig.baseUrl就可以了,以后debug、release切换的时候都不用去切换值了。

2. 签名文件配置

在多渠道分发的时候,我们可以在不同的渠道使用不同的签名文件,但是debug的时候只能使用一个。签名文件根据keystore的信息存放位置不同,可以分为三种。

1) 直接将签名的所有信息配置在gradle中

signingConfigs {
    release {
        storeFile file('../keystore.jks')
        storePassword '123456'
        keyAlias 'HomeKey'
        keyPassword '123456'
    }
}

2) 将gradle信息存放在local.properties或新建一个properties文件,相对来讲,这种方式取值的时候比较麻烦

signingConfigs {
    release {
        storeFilefile(properties.getProperty("keystroe_storeFile"))
        storePasswordproperties.getProperty("keystroe_storePassword")
        keyAliasproperties.getProperty("keystroe_keyAlias")
        keyPasswordproperties.getProperty("keystroe_keyPassword")
    }
}

local.properties中的配置,路径:../modul/local.properties,在与app同级的目录中:

keystroe_storeFile=../keystore.jks #keystory所在路径
keystroe_keyAlias=HomeKey  #别名不能为中文
keystroe_storePassword=123456
keystroe_keyPassword=123456

3) 第三种方法综合了前两种方法的优点,既保护了签名信息,使用起来又方便。将签名信息保存到gradle.properties文件中,默认是没有的,需要自己建。

signingConfigs {
    release {
        keyAlias RELEASE_KEY_ALIAS
        keyPassword RELEASE_KEY_PASSWORD
        storeFile file(RELEASE_STORE_FILE)
        storePassword RELEASE_STORE_PASSWORD
    }
}

gradle.properties中的配置,路径:../project/gradle.properties,在与app同级的目录中

RELEASE_KEY_ALIAS= HomeKey               #别名不能为中文
RELEASE_KEY_PASSWORD=123456
RELEASE_STORE_PASSWORD=123456
RELEASE_STORE_FILE=../../keystore.jks

在keystore配置相对路径的时候,要以实际使用的build.gradle文件所在目录为起点去找keystore文件所在目录。

如果按照第二、第三种方式去配置签名文件,则在整个project中都可以使用,配置成了一个通用的工具。

3. 多渠道打包

多渠道打包可以实现两个作用:

1) 可以实现渠道标识,根据不同的渠道加载不同的logo、资源等。

2) 可以实现在同一台手机上安装多个APK。

3.1 加入渠道变量

在AndroidManifest.xml 里添加渠道变量:

CHANNEL_VALUE}" />

3.2 配置渠道信息

在使用多渠道的时候,我们可以为不同的渠道设置不同的applicationId、logo、加载的资源等。实现不同的渠道的个性化需求。

配置:

productFlavors { //多渠道分发 gradlewassembleFlavorRelease
    xiaomi { //小米
        applicationIdSuffix ‘.debug’  //在原有applicationId的基础上加上此后缀
    }
    tencent { //腾讯
        applicationId"com.xx.xx.tencent" //在此渠道使用新的包名,将会替换manifeset中package的值,其他不变
    }
    qihu360 { //360
    }
 
productFlavors.all {
         //CHANNEL_VALUE同manifest中meta-data标签(CHANNEL)中的value值保存一致
        flavor ->flavor.manifestPlaceholders = [CHANNEL_VALUE: name]
    }
}

不同的渠道、编译类型如果想改变包名有两种方式:

1) applicationIdSuffix ‘.debug’,在applicationId的末尾追加后缀,形成一个新的包名

2) 重写applicationId指定一个完全不一样的包名

3.3 Release打包配置

在release里面配置混淆、批量更改APK名字。

release {
    buildConfigField('boolean','delAttachment', 'true')    //邮件发送成功后,是否删除附件
 
    zipAlignEnabled true    // 开启ZipAlign优化
    shrinkResources true    //移除无用的资源文件
 
    minifyEnabled true  //编译时是否混淆
    proguardFilesgetDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
 
    signingConfig signingConfigs.release     //签名信息
 
    applicationVariants.all { variant ->
        variant.outputs.each { output ->
            def outputFile = output.outputFile
            if (outputFile != null &&outputFile.name.endsWith('.apk') &&'release'.equals(variant.buildType.name)) {
                def fileName =outputFile.name.replace("${variant.flavorName}", "V${defaultConfig.versionName}-${variant.flavorName}")
                fileName =fileName.replace(".apk", "-${buildTime()}.apk")
                output.outputFile = newFile(outputFile.parent, fileName)
            }
        }
    }
}

获取时间方法:

def buildTime() { //生成时间
    return new Date().format('yyyyMMddHHmmss')
}

在批量打包生成APK名字的时候,有个地方需要注意,因为我打包的时候APK名字加上了'yyyyMMddHHmmss'这个时间限制,所有在debug的时候会报错,报错信息为找不到安装包,因为Debug命名的apk同pull到手机上的apk名字对不上,生成的时间会相差几秒。

解决办法:

1) 时间不精确到秒,直接yyyyMMdd就可以了,但是这样的话还是存在一个问题,在output文件夹中每天都会产生一个新的debug的apk,需要勤clean项目,不然会越来越大。

2) 加上一个限制条件'release'.equals(variant.buildType.name),判断当前build的类型,只有release的时候我们才执行改名操作,这样debug的时候生成的apk也永远只有一个。

执行命令gradlew  assembleRelease就可以批量生成每一个渠道的签名包了,在../app/build/outputs/apk/...文件中可以找到。至此,基本的多渠道打包就可以啦。

4. BuildTypes切换

其中buildTypes+productFlavors会生成Build Variants中的选项,选择不同的build variant的,则你在点击run、debug的时候就是执行的相应的variant。之前每次安装带签名的APK的时候都是通过打包好APK,然后传到手机上安装的。在这里我们在release中配置好打包签名信息之后(完整配置附在文章结尾),选择xiaomiRelease直接run就相当于你安装了一个带签名的APK,就是这么叼。

Gradle相关配置_第1张图片 

5. 渠道个性化

在不同的渠道显示不同的splash页面、logo等是最常见的需求,我们也可以根据渠道的不同在java文件中做不同的逻辑操作,这些在gradle的配置中都可以轻松实现。

5.1 运行多个APK

在程序Debug的时候,我们就不能在这台手机上执行Release,无法同时跑两个(或更多)应用。而我想要实现Debug的时候APP的名字和logo区分开来。有两种方法可以实现:

5.1.1 第一种方法

这种方法只适合做一些简单的个性化,比如修改APP名称、启动图标等。

首先修改manefest中的值:

然后在buildTypes中配置对应的信息:

debug {
    ...
    applicationIdSuffix ".debug"    //这里是在applicationId中添加了一个后缀
    manifestPlaceholders = [app_icon: '@mipmap/ic_launcher_1' ,app_name:'@string/app_name_1']
}
release {
    ...
    manifestPlaceholders = [app_icon: '@mipmap/ic_launcher' ,app_name:'@string/app_name']
}

运行项目便可以达到切换logo图标、app名称的目的。同理可以推广到其他的资源文件的个性化需求,但是这种方法就无法对java源码做个性化操作,在维护起来也比较困难。

5.1.2 第二种方法

首先在buildTypes中给debug配置applicationIdSuffix,形成一个新的applicationId,此时debug的APK就可以同release的APK同时安转在手机上了。

debug {
    …
    debuggable true    //是否为debug状态,也可以不配置,默认为true
    applicationIdSuffix ".debug"    //这里是在applicationId中添加了一个后缀
    buildConfigField('boolean','delAttachment', 'false')   //邮件发送成功后,是否删除附件
}

然后在../app/src目录下新建一个debug名字的文件夹(名字必须与buildTypeName、flavorName保存一致),将需要替换的resource、java文件等资源创建,其中目录结构必须与mian中的保存一致。

Gradle相关配置_第2张图片

此时运行APP可以看到debug的apk与release的apk可以共存且名字与logo都不一样。这种方法同样适用于flavor的个性化操作

5.2 多渠道独立签名

首先配置多个签名信息

signingConfigs {
    release_xiaomi {
        keyAlias RELEASE_KEY_ALIAS
        keyPassword RELEASE_KEY_PASSWORD
        storeFile file(RELEASE_STORE_FILE)
        storePassword RELEASE_STORE_PASSWORD
    }
    release_tencent {
        keyAlias RELEASE_KEY_ALIAS_1
        keyPassword RELEASE_KEY_PASSWORD_1
        storeFile file(RELEASE_STORE_FILE)_2
        storePassword RELEASE_STORE_PASSWORD__1
    }
}

渠道信息:

productFlavors { //多渠道分发 gradlewassembleFlavorRelease
    xiaomi { //小米
    }
    tencent { //腾讯
    }
 
    productFlavors.all {
        //CHANNEL_VALUE同manifest中meta-data标签(CHANNEL)中的value值保存一致
        flavor ->flavor.manifestPlaceholders = [CHANNEL_VALUE: name]
    }
}

打包配置:

release {
   ...
   //多个 flavor ,指定 flavor 使用指定 签名
   productFlavors.xiaomi.signingConfig signingConfigs.release_xiaomi
   productFlavors.tencent.signingConfig signingConfigs.release_tencent
}
// debug 并不能设置多个签名,如果debug包需要测试诸如微信、地图等第三方 sdk ,则可以指定 debug 包使用 release 包的签名
debug {
   ...
   signingConfig signingConfigs.release 
}

这里再做几点补充:

1) 给某个 flavor指定签名的方法对 debug无效,简单来说,debug签名只能指定一个或者使用默认的debug签名。

2) 多渠道使用独立签名,打包时千万不要使用Android Studio 中 Build 菜单下的 GenerateSigned APK,因为当你使用这个打包的时候, Android Studio 会让你指定使用的签名文件。解决方法就是使用 gradle tasks。传送门:Android GradleBuild Tasks

Gradle相关配置_第3张图片

3) 鉴于第一点中的传送门需要FQ,所以在这里简单介绍一下 Android Gradle Build Tasks 的使用。

6. 打包命令

Terminal中输入命令就可以随心所欲的打出你想要的apk。

基本语法:gradlew  assemble[flavor][buildType]

如:gradlew  assembleFlavor1Release;gradlew  assembleFlavor2Debug

gradle本身支持命令缩写,  如:gradleW  assFlavor1R

拓展:

执行 gradlew build   打全渠道即所有flavor;且含所有buildTypes

执行 gradlew  assembleRelease ,将会打出所有渠道的release包;

执行 gradlew  assembleXiaomi,将会打出小米渠道的release和debug版的包;

执行 gradlew  assembleXiaomiRelease将生成小米的release包。

7. Gradle完整配置

initWith 可以方便我们继承其他的配置,只需要添加需要的部分

//debug的一个扩展
preview{
   initWith  debug     //继承debug的配置
   applicationIdSuffix ".preview"
}

 完整的bulid.gradle配置:

apply plugin: 'com.android.application'
 
android { //此语法只有当你的apply plugin:'com.android.xxx'时才可以用
   compileSdkVersion 23 //开发时采用的sdk版本
   buildToolsVersion '25.0.0' //编译时采用的编译工具版本
 
   defaultConfig { //默认项目配置信息
       applicationId "com.hyj.xxx"
       minSdkVersion 18
        targetSdkVersion 23
       versionCode 14
       versionName "3.4.4"
 
       buildConfigField('String', 'logTag', '"TAG"')    //打印日志输出的TAG标记名
       buildConfigField('boolean', 'crashInfoSaveAsJson', 'false') //崩溃日志保存为JSON,否则直接保存为String
 
        manifestPlaceholders= [CHANNEL_VALUE: "official"] //默认渠道为官网
    }
 
   signingConfigs { //签名信息配置
       release { //正式版本
           keyAlias RELEASE_KEY_ALIAS
           keyPassword RELEASE_KEY_PASSWORD
           storeFile file(RELEASE_STORE_FILE)
            storePassword RELEASE_STORE_PASSWORD
        }
    }
 
    //自定义字段语法buildConfigField('boolean','API_ENV','true')
   buildTypes { //构建的类型方式
       debug {
           debuggable true    //是否为debug状态,也可以不配置,默认为true
           applicationIdSuffix ".debug"   //这里是在applicationId中添加了一个后缀
           buildConfigField('boolean', 'delAttachment', 'false')   //邮件发送成功后,是否删除附件
        }
 
       preview{
           initWith  release     //继承debug的配置
           applicationIdSuffix ".preview"
           debuggable true
        }
 
       release {
           buildConfigField('boolean', 'delAttachment', 'true')    //邮件发送成功后,是否删除附件
 
           zipAlignEnabled true    // 开启ZipAlign优化
           shrinkResources true    //移除无用的资源文件
 
           minifyEnabled true  //编译时是否混淆
           proguardFiles getDefaultProguardFile('proguard-android.txt'),'proguard-rules.pro'
 
           signingConfig signingConfigs.release    //签名信息
 
           applicationVariants.all { variant ->           //批量修改Apk名字
                variant.outputs.each { output ->
                    def outputFile =output.outputFile
                    if (outputFile != null&& outputFile.name.endsWith('.apk') &&'release'.equals(variant.buildType.name)) {
                        def fileName =outputFile.name.replace("${variant.flavorName}","V${defaultConfig.versionName}-${variant.flavorName}")
                        fileName =fileName.replace(".apk", "-${buildTime()}.apk")
                        output.outputFile = newFile(outputFile.parent, fileName)
                    }
               }
           }
        }
    }
 
   productFlavors { //多渠道分发 gradlewassembleFlavorRelease
       xiaomi { //小米
        }
       tencent { //腾讯
        }
       qihu360 { //360
        }
 
       productFlavors.all {
           //CHANNEL_VALUE同manifest中meta-data标签(CHANNEL)中的value值保存一致
           flavor -> flavor.manifestPlaceholders = [CHANNEL_VALUE: name]
        }
    }
}
 
dependencies {
   compile fileTree(include: ['*.jar'], dir: 'libs')
   testCompile'junit:junit:4.12'
   compile 'com.android.support:design:22.2.1'
   compile 'com.android.support:appcompat-v7:23.4.0'
   compile project(':Library')
   compile files('libs/xstream-1.4.7.jar')
   compile files('libs/xpp3_min-1.1.4c.jar')
   compile files('libs/activation.jar')
   compile files('libs/additionnal.jar')
   compile files('libs/commons-email-1.4.jar')
   compile files('libs/mail.jar')
}
 
def buildTime() { //生成时间
   return new Date().format('yyyyMMdd')
}

8. 参考资料

Gradle官方说明:

http://tools.android.com/tech-docs/new-build-system 

http://tools.android.com/tech-docs/new-build-system/user-guide

参数说明:http://www.cnblogs.com/niray/p/5242985.html

多渠道签名成功校验方法:http://www.cnblogs.com/travellife/p/Gradle-shi-xian-Android-duo-qu-dao-ding-zhi-hua-da.html

Gradle基本知识:

http://blog.csdn.net/u010818425/article/details/52268126

http://www.cnblogs.com/dasusu/p/6628099.html

lib项目中无法使用主项目中BuildConfig.DEBUG值问题:http://www.jianshu.com/p/1907bffef0a3

美团Android自动化之旅—生成渠道包:http://tech.meituan.com/mt-apk-packaging.html

美团Android自动化之旅—适配渠道包:http://tech.meituan.com/mt-apk-adaptation.html


Groovy脚本语言:

Gradle中的应用解析:http://www.jianshu.com/p/a3805905a5c7#

语法规范:http://ifeve.com/groovy-syntax/

你可能感兴趣的:(android,android,gradle,打包,buildConfig)