现在大多数开发都使用android studio开发app,那么我们就要学会使用gradle脚本打包apk(抛砖引玉^-^)
翻译自 链接http://blog.csdn.net/u012124438/article/details/72835893,感觉这篇文章写的不错,我这里摘取了gradle的打包技巧。
第一步:
你需要去下载安卓gradle(这里附上下载链接http://www.androiddevtools.cn/),个人感觉这个网站挺好用的。
第二步:
你需要去环境变量path目录下配置下gradle(gradle所在目录\bin)就可以了,来测试下是否配置成功
出现以上图片的显示信息,说明你的配置没有问题.
第三步:
接下来进入正题
替换AndroidManifest下的相关字段
把配置中的${app_label}替换为@string/app_name
android{
defaultConfig{
manifestPlaceholders = [app_label:"@string/app_name"]
}
}
如果只想替换debug版本:
android{
buildTypes {
debug {
manifestPlaceholders = [app_label:"@string/app_name_debug"]
}
release {
}
}
}
更多的需求是替换渠道编号:
android{
productFlavors {
// 把dev产品型号的apk的AndroidManifest中的channel替换dev
"dev"{
manifestPlaceholders = [channel:"dev"]
}
}
}
独立配置签名信息
对于签名相关的信息,直接写在gradle当然不好,特别是一些开源项目,可以添加到gradle.properties:
RELEASE_KEY_PASSWORD=xxxx
RELEASE_KEY_ALIAS=xxx
RELEASE_STORE_PASSWORD=xxx
RELEASE_STORE_FILE=G\:\\..\\XX.jks
这里要注意jks文件的目录要使用\\
然后在build.gradle中引用即可,上面相当于定义全局的配置信息:
android {
signingConfigs {
release {
storeFile file(RELEASE_STORE_FILE)
storePassword RELEASE_STORE_PASSWORD
keyAlias RELEASE_KEY_ALIAS
keyPassword RELEASE_KEY_PASSWORD
}
}
}
如果不想提交到版本库,可以添加到local.properties中,然后在build.gradle中读取。
多渠道打包
多渠道打包的关键之处在于,定义不同的product flavor, 并把AndroiManifest中的channel渠道编号替换为对应的flavor标识:
android {
productFlavors {
dev{
manifestPlaceholders = [channel:"dev"]
}
official{
manifestPlaceholders = [channel:"official"]
}
// ... ...
wandoujia{
manifestPlaceholders = [channel:"wandoujia"]
}
xiaomi{
manifestPlaceholders = [channel:"xiaomi"]
}
"360"{
manifestPlaceholders = [channel:"360"]
}
}
注意一点,这里的flavor名如果是数字开头,必须用引号引起来。
自定义Build Type
前面说到默认的build type有两种debug和release,区别如下:
// release版本生成的BuildConfig特性信息
public final class BuildConfig {
public static final boolean DEBUG = false;
public static final String BUILD_TYPE = "release";
}
// debug版本生成的BuildConfig特性信息
public final class BuildConfig {
public static final boolean DEBUG = true;
public static final String BUILD_TYPE = "debug";
}
现在有一种需求,增加一种build type,介于debug和release之间,就是和release版本一样,但是要保留debug状态(如果做过rom开发的话,类似于user debug版本),我们称为preview版本吧。
其实很简单:
android {
signingConfigs {
debug {
storeFile file(RELEASE_STORE_FILE)
storePassword RELEASE_STORE_PASSWORD
keyAlias RELEASE_KEY_ALIAS
keyPassword RELEASE_KEY_PASSWORD
}
preview {
storeFile file(RELEASE_STORE_FILE)
storePassword RELEASE_STORE_PASSWORD
keyAlias RELEASE_KEY_ALIAS
keyPassword RELEASE_KEY_PASSWORD
}
release {
storeFile file(RELEASE_STORE_FILE)
storePassword RELEASE_STORE_PASSWORD
keyAlias RELEASE_KEY_ALIAS
keyPassword RELEASE_KEY_PASSWORD
}
}
buildTypes {
debug {
manifestPlaceholders = [app_label:"@string/app_name_debug"]
}
release {
manifestPlaceholders = [app_label:"@string/app_name"]
}
preview{
manifestPlaceholders = [app_label:"@string/app_name_preview"]
}
}
}
另外,build type还有一个好处,如果想要一次性生成所有的preview版本,执行assemblePreview即可,debug和releae版本同理。如果想生成所有的apk直接执行gradle assemble即可
build type中的定制参数
上面我们在不同的build type替换${app_label}为不同的字符串,这样安装到手机上就能明显的区分出不同build type的版本。
除此之外,可能还可以配置一些参数,列几个在工作中用到的:
android {
debug {
manifestPlaceholders = [app_label:"@string/app_name_debug"]
applicationIdSuffix ".debug"
minifyEnabled false
signingConfig signingConfigs.debug
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
release {
manifestPlaceholders = [app_label:"@string/app_name"]
minifyEnabled true
shrinkResources true
signingConfig signingConfigs.release
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
preview{
manifestPlaceholders = [app_label:"@string/app_name_preview"]
applicationIdSuffix ".preview"
debuggable true // 保留debug信息
minifyEnabled true
shrinkResources true
signingConfig signingConfigs.preview
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
这里解释一下相关配置说明:
// minifyEnabled 混淆处理
// shrinkResources 去除无用资源
// signingConfig 签名
// proguardFiles 混淆配置
// applicationIdSuffix 增加APP ID的后缀
// debuggable 是否保留调试信息
当升级sdk、build tool、target sdk等,几个module都要更改,非常的麻烦。最重要的是,很容易忘记,最终导致app module之间的差异不统一,也不可控。
强大的gradle插件在1.1.0支持全局变量设定,一举解决了这个问题。
先在project的根目录下的build.gradle定义ext全局变量:
ext {
compileSdkVersion = 22
buildToolsVersion = "23.0.1"
minSdkVersion = 10
targetSdkVersion = 22
versionCode = 34
versionName = "v2.6.1"
}
然后在各module的build.gradle中引用如下:
Android {
compileSdkVersion rootProject.ext.compileSdkVersion
buildToolsVersion rootProject.ext.buildToolsVersion
defaultConfig {
applicationId "com.xxx.xxx"
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
versionCode rootProject.ext.versionCode
versionName rootProject.ext.versionName
}
}
然后每次修改project级别的build.gradle即可实现全局统一配置。
自定义导出的APK名称
默认android studio生成的apk名称为app-debug.apk或者app-release.apk,当有多个渠道的时候,需要同时编出50个渠道包的时候,就麻烦了,不知道谁是谁了。
这个时候,就需要自定义导出的APK名称了,不同的渠道编出的APK的文件名应该是不一样的。这里的导出目录是默认的工程下的outputs目录
android {
// rename the apk with the version name
applicationVariants.all { variant ->
variant.outputs.each { output ->
output.outputFile = new File(
output.outputFile.parent,
"lol-${variant.buildType.name}-${variant.versionName}-${variant.productFlavors[0].name}.apk".toLowerCase())
}
}
}
当apk太多时,如果能把apk按debug,release,preview分一下类就更好了(事实上,对于我这样经常发版的人,一编往往就要编四五十个版本的人,debug和release版本全混在一起没法看,必须分类),简单:
android {
// rename the apk with the version name
// add output file sub folder by build type
applicationVariants.all { variant ->
variant.outputs.each { output ->
output.outputFile = new File(
output.outputFile.parent + "/${variant.buildType.name}",
"lol-${variant.buildType.name}-${variant.versionName}-${variant.productFlavors[0].name}.apk".toLowerCase())
}
}
}
现在生成了类似于lol-dev-preview-v2.4.0.0.apk这样格式的包了,preview的包自然就放在preview的文件夹下,清晰明了。我们也可以指定目录保存生成的apk,直接保存到g盘下apk目录。
applicationVariants.all { variant ->
variant.outputs.each { output ->
output.outputFile = new File(
"F:\\ddz",
"lz-${variant.buildType.name}-${variant.versionName}-${variant.productFlavors[0].name}.apk".toLowerCase())
}
}
接下来最后一步查看apk是否签名成功,解压apk在inf文件下输入keystore命令keytool -printcert -file META-INF/CERT.RSA,显示所有者,有效日期...信息,即签名成功。
(0920插入)最经遇到过打包时,会导致一些配置错误,现在把他放到了res/values/string.xml下了。只需要在android打包的版本控制中加入以下代码
resValue("string", "test_str", "lztest") //在res/value/string下插入test_str字段
(0924插入)gradle中获取时间的方法+在BuildConfig.java文件中插入全局常量
//获取时间戳
def getDate() {
def date = new Date()
def formattedDate = date.format('yyyy-MM-dd HH-mm')
return formattedDate
}
//第一个int表示内型,可以是(int,boolean,String),第二个是字段名,第三个是字段的值
buildConfigField "int", "lz_test", "1"
//Tips:如果是String内型,值必须是 ‘“值”’ 这样紫的。代码中直接用就好,列:BuildConfig.lz_test
gradle之打jar包的方法
//修改jar名字+指定jar生成的地方
task makeJar(type:Copy){
//删除存在的jar
delete 'build/outputs/test.jar'
//设置拷贝的文件
from('build/intermediates/bundles/release/')
//打完jar包后的文件目录
into('libs/')
//只关心classes.jar
include('classes.jar')
rename('classes.jar','test.jar')
}
makeJar.dependsOn(build)
Tips:有一点大家需要注意build/intermediates/bundles/release/可能没有,这时候你需要去build.gradle的android下去配置publishNonDefault = true属性就ok了。
Tips:(0924加),最近使用gradle3.0.1发现build/intermediates/bundles这个路径不存在了,3.0.1以后路径发生了变换新的jar路径:build/intermediates/packaged-classes/release/
打完收工,感谢前面博客的博主