一、配置签名信息:
1.签名文件:签名文件放在项目的根目录下
2.签名信息:普通方式是写死在build.gradle中,但这种硬编码的方式不便管理,所以提供两个地方可以编写
一个是添加到gradle.properties中,这种会同时添加到版本库中
还有一个是添加到local.properties中,这种不会添加到版本库中
按需选择,然后在build.gradle中的signingConfigs引用刚刚配置好的key信息
RELEASE_KEY_PASSWORD=xxxx
RELEASE_KEY_ALIAS=xxx
RELEASE_STORE_PASSWORD=xxx
RELEASE_STORE_FILE=../.keystore/xxx.jks
signingConfigs {
release {
storeFile file(RELEASE_STORE_FILE)
storePassword RELEASE_STORE_PASSWORD
keyAlias RELEASE_KEY_ALIAS
keyPassword RELEASE_KEY_PASSWORD
}
}
二、修改appName:
1.首先在AndroidManifest清单文件中使用占位符 ,如
android:label="${application_app_name}"
如果不在清单文件中操作,也可以直接在build.gradle中替换,如
defaultConfig{
manifestPlaceholders = [app_label:"@string/app_name"]
}
但以上会替换所有版本的app_name,可能不符合我们的项目需要,我们一般会根据版本还有渠道分别设置
2.如果是根据版本debug、release或者自定义的,我们只需要在buildTypes不同版本中各自设置就好,如
buildTypes {
debug {
manifestPlaceholders = [app_label:"@string/app_name_debug"]
}
release { manifestPlaceholders = [app_label:"@string/app_name_release"]
}
}
3.如果需要按照不同渠道来设置,那么我们可以遍历配置的productFlavors中所有flavor,每一个都设置,如
productFlavors.findAll().each { flavor -> String flavorName = flavor.name.toString(); if (flavorName.equalsIgnoreCase("qihoo_360")) flavor.manifestPlaceholders = [application_app_name: "操盘侠股票基金理财", gmf_channel_id: flavor.name.toString()] else if (flavorName.equalsIgnoreCase("xiaomi")) flavor.manifestPlaceholders = [application_app_name: "操盘侠-基金炒股票", gmf_channel_id: flavor.name.toString()] else if (flavorName.equalsIgnoreCase("baidu") || flavorName.equalsIgnoreCase("oppo") || flavorName.equalsIgnoreCase("meizu") || flavorName.equalsIgnoreCase("vivo") || flavorName.equalsIgnoreCase("sougou") || flavorName.equalsIgnoreCase("pp") || flavorName.equalsIgnoreCase("smartisan")) flavor.manifestPlaceholders = [application_app_name: "操盘侠-股票基金理财", gmf_channel_id: flavor.name.toString()] else flavor.manifestPlaceholders = [application_app_name: "操盘侠", gmf_channel_id: flavor.name.toString()] }
注:配置渠道号flavor的名称时,如果是数字开头必须用引号引起来
productFlavors { dev { minSdkVersion 21 } official { } // qihoo_360 { // } // wandoujia { // } // yingyongbao { // } // baidu { // } // play { // } // gfan { // } // xiaomi { // } // huawei { // } // meizu { // } // oppo { // } // vivo { // } // lenovo { // } // pp { // } // samsung { // } // sougou { // } // smartisan { // } “360“{ } }
以上配置方式优先级依次从高到低,按需配置
三、构建版本及依赖库版本管理:
和配置签名信息同理,我们不再把版本号写死在build.gradle中,而是添加到build.gradle中
四、自定义build type
AndroidStudio默认的build type有两种release和debug,实际项目我们可能还会有其他版本比如预发布版本pre,或者专业版pro,那我们该如何设置呢,其实原理同release和debug是一样的,并且有一个更方便的操作是可以基于现有的任一种方式进行拓展,类似于继承,使用
pro { initWith(android.buildTypes.release) applicationIdSuffix ".GMFundPro" }
就相当于基于了release版设置,不相同的信息如包名等重新覆写久可以了
五、build type中参数设置
minifyEnable 是否混淆处理
proguardFiles 混淆文件配置
applicationSuffix 增加APP ID的后缀
signingConfig 签名配置
shrinkResources 去除无用资源
debuggable 是否保留调试信息
buildTypes { release { minifyEnabled true applicationIdSuffix ".GMFund" proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' signingConfig signingConfigs.release } pro { initWith(android.buildTypes.release) applicationIdSuffix ".GMFundPro" } debug { applicationIdSuffix ".GMFund" proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' // signingConfig signingConfigs.release minifyEnabled false } }
六、多工程全局配置信息
当我们的module引用了工程下的其他library时,然后基于library拓展几个app module,那么每个module下的build.gradle都会有一块相同的配置信息,如果没有配置在build.properties中,我们可以在工程下的build.gralde中设置全局定义
1 2 3 4 5 6 7 8 |
ext { compileSdkVersion = 22 buildToolsVersion = "23.0.1" minSdkVersion = 10 targetSdkVersion = 22 versionCode = 34 versionName = "v2.6.1" } |
然后在各个module中的build.gradle中引用
1 2 3 4 5 6 7 8 9 10 11 12 |
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 } } |
如果已经配置在build.properties中,我们就不需要这样做直接引用就好。
七、导出不同版本的apk名称
androidStudio默认生成的apk名称每次打包都是一样,这肯定是不行的,我们必须根据版本号还有版本名称来生成不同的apk,所以需要遍历applicationVariants,创建包含不同版本不同版本号版本名称的apk,如
applicationVariants.all { item -> item.outputs.each { variant -> File file = variant.outputFile; if (file.getName().endsWith("release.apk")) { variant.outputFile = new File(file.parent, "cpman" + "-v" + defaultConfig.versionName + "." + defaultConfig.versionCode + "-" + variant.name.replaceAll("Release", "") + ".apk"); } else if (file.getName().endsWith("pro.apk")) { variant.outputFile = new File(file.parent, "cpman-pro" + "-v" + defaultConfig.versionName + "." + defaultConfig.versionCode + "-" + variant.name.replaceAll("Pro", "") + ".apk"); } } }
八、混淆配置
除了默认的配置外,我们肯定还需要配置我们自己需要混淆的文件,主要是引用库的混淆
手动添加:
-keep enum com.facebook.** -keepattributes Exceptions,InnerClasses,Signature -keepattributes *Annotation* -keepattributes SourceFile,LineNumberTable
使用第三方反编译工具(比如jadx:https://github.com/skylot/jadx ),打开apk后能看到所有引用库的包名,把所有想混淆或者不确定能不能混淆的全部添加
-dontshrink -dontoptimize -dontwarn com.google.android.maps.** -dontwarn android.webkit.** -dontwarn com.umeng.** -dontwarn com.tencent.weibo.sdk.** -dontwarn com.facebook.** -dontwarn javax.** -dontnote com.google.android.maps.** -dontnote android.webkit.** -dontnote com.umeng.** -dontnote com.tencent.weibo.sdk.** -dontnote com.facebook.** -dontnote javax.** -keep enum com.facebook.** -keepattributes Exceptions,InnerClasses,Signature -keepattributes *Annotation* -keepattributes SourceFile,LineNumberTable -keep public interface com.facebook.** -keep public interface com.tencent.** -keep public interface com.umeng.socialize.** -keep public interface com.umeng.socialize.sensor.** -keep public interface com.umeng.scrshot.**
如果release混淆后友盟统计有崩溃异常,我们每次都必须在友盟上上传mapping文件进行错误定位(并且目前友盟统计的mapping文件大小限制在10M以内),其实,我们可以在proguard-rules.pro中添加
-keepattributes SourceFile,LineNumberTable
代价就是apk会增大200k左右,不过我想这点应该还是可以接受的
九、动态设置或者build.gradle信息
在build.gradle中定义的一些编译时间,编译机器,最新版本(不想写在代码里),我们可以像字符串获取一样动态获取,如
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
android {
defaultConfig {
resValue "string", "build_time", buildTime()
resValue "string", "build_host", hostName()
resValue "string", "build_revision", revision()
}
}
def buildTime() {
return new Date().format("yyyy-MM-dd HH:mm:ss")
}
def hostName() {
return System.getProperty("user.name") + "@" + InetAddress.localHost.hostName
}
def revision() {
def code = new ByteArrayOutputStream()
exec {
commandLine 'git', 'rev-parse', '--short', 'HEAD'
standardOutput = code
}
return code.toString()
}
|