1.配置签名信息
对于签名相关的信息,直接写在gradle当然不好,特别是一些开源项目,可以添加到local.properties,然后从中读取需要的信息:
key.file=../androidkey.keystore
storePassword=xxx
keyAlias=xxx
keyPassword=xxx
然后在build.gradle中引用即可:
android {
signingConfigs {
debug{
//读取文件
def sdkDir = properties.getProperty('key.file')
storeFile file( sdkDir )
//读取字段
def key_storePassword = properties.getProperty( 'storePassword' )
def key_keyAlias = properties.getProperty( 'keyAlias' )
def key_keyPassword = properties.getProperty( 'keyPassword' )
storePassword key_storePassword
keyAlias key_keyAlias
keyPassword key_keyPassword
}
}
}
2.使用 gradle 在编译时动态设置 Android BuildConfig
在你的 gradle 文件 buildTypes 或者 productFlavors 下面,如 release 体内写上类似:
buildConfigField "String", "APP_HOST ", "\"http://example.com/\""
buildConfigField "boolean", "LOG_DEBUG", "false"
gradle sync 一下后,BuildConfig.APP_HOST 就会被赋值为 http://example.com 就可以供 Java 代码调用了。使用例子:
public static final String MY_URL= BuildConfig.APP_HOST + "xxx";//显示http://example.com/xxx
if (BuildConfig.LOG_DEBUG) {
//不打日志
}else{
//打日志
}
3.使用 gradle 在编译时动态设置 Android Manifest
在AndroidManifest中定义一个变量,在build.gradle中动态的替换掉,十分方便,语法也十分简单。 例子: 在AndroidManifest中定义一个变量
接着,我们在build.gradle文件中根据不同的环境,生成不同appkey的apk。
buildTypes {
debug {
/*一博客里看到的可以这样用,记下备忘:
manifestPlaceholders = [app_label:"@string/app_name_debug"]*/
manifestPlaceholders = [
umeng_app_key: "你替代的内容",
umeng_app_secret:"你要替换的内容"]
}
release {
manifestPlaceholders = [
umeng_app_key: "你替代的内容",
umeng_app_secret:"你要替换的内容"]
}
develop {
manifestPlaceholders = [
umeng_app_key: "你替代的内容",
umeng_app_secret:"你要替换的内容"]
}
}
注意:这里的“你替代的内容”,不能为特殊关键词,比如:TRUE,否则在Java代码中获取不到meta-data中的值
4多工程全局配置(一博客里复制的)
随着产品渠道的铺开,往往一套代码需要支持多个产品形态,这就需要抽象出主要代码到一个Library,然后基于Library扩展几个App Module。 相信每个module的build.gradle都会有这个代码:
android {
compileSdkVersion 22
buildToolsVersion "23.0.1"
defaultConfig {
minSdkVersion 10
targetSdkVersion 22
versionCode 34
versionName "v2.6.1"
}
}
当升级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即可实现全局统一配置。
5.自定义导出的APK名称
//不同的打包生成自定义的名称
applicationVariants.all { variant ->
variant.outputs.each { output ->
def outputFile = output.outputFile
if (outputFile != null && outputFile.name.endsWith('.apk')) {
def huanJing;
if (variant.buildType.name.equals('release')) {
huanJing = "s";
} else if (variant.buildType.name.equals('debug')) {
huanJing = "c";
} else {
huanJing = "${variant.buildType.name}";
}
def apkName = huanJing + "${releaseTime()}${variant.productFlavors[0].name}${variant.versionName}.apk"/*名字示例:s1222yqb4.1.3.apk*/
output.outputFile = new File(outputFile.parent, apkName)
}
}
}
其中:releaseTime(写在gradle最外层,和gradle里面的“android“同一层级)
def releaseTime() {
return new Date().format("MMdd", TimeZone.getTimeZone("UTC"))
}
6.多渠道打包不同版本资源不同
多渠道打包的时候不同的版本可能有一部分代码不同或布局或资源文件,下面是一个示意图,自己体会:
说了这么多,不够直观,分享下我项目中的gradle供大家参考(有删减)
apply plugin: 'com.android.application'
def releaseTime() {
return new Date().format("MMdd", TimeZone.getTimeZone("UTC"))
}
android {
compileSdkVersion 24
buildToolsVersion '24.0.1'
/*上传图片时报错org.apache.http.client.methods.HttpRequestBase,
android 6.0(api 23) SDK,Android的网络请求强制使用HttpUrlConnection,并且SDK中也已经移除了HttpClient。
加上这一句useLibrary 'org.apache.http.legacy'*/
useLibrary 'org.apache.http.legacy'
defaultConfig {
minSdkVersion 14
targetSdkVersion 21
multiDexEnabled true/*防止编译报错*/
//个推配置so库
ndk {
//abiFilters "armeabi", "armeabi-v7a", "arm64-v8a", "mips", "mips64", "x86", "x86_64"
//为了和拍照的保持一致去掉了几个
abiFilters "armeabi", "armeabi-v7a", "mips", "x86"
}
return true
}
signingConfigs {
debug {
//加载资源
Properties properties = new Properties()
InputStream inputStream = project.rootProject.file('local.properties').newDataInputStream() ;
properties.load( inputStream )
/**
* 密码从本地local.properties读取,不上传到svn上了
*/
//读取文件
def sdkDir = properties.getProperty('key.file')
storeFile file( sdkDir )
//读取字段
def key_storePassword = properties.getProperty( 'storePassword' )
def key_keyAlias = properties.getProperty( 'keyAlias' )
def key_keyPassword = properties.getProperty( 'keyPassword' )
storePassword key_storePassword
keyAlias key_keyAlias
keyPassword key_keyPassword
}
}
productFlavors {
yqb {
applicationId "你的包名1"
versionCode 32
versionName "4.1.3"
//个推配置参数
manifestPlaceholders = [
//个推
GETUI_APP_ID : "xxxxxxxx",
GETUI_APP_KEY : "xxxxxxxx",
GETUI_APP_SECRET : "xxxxxxxx",
PACKAGE_NAME : applicationId,
//百度
BAIDU_API_KEY : "xxxxxxxx",
//qq的APPID
QQ_APP_ID : "xxxxxxxx",
]
//个推的GETUI_APP_ID,代码里面用的
buildConfigField "String", "GETUI_APP_ID", "\"" + manifestPlaceholders.GETUI_APP_ID + "\""
return true
}
gat {
applicationId "你的包名2"
versionCode 7
versionName "1.1.1"
manifestPlaceholders = [
GETUI_APP_ID : "xxxxxxxxxx",
GETUI_APP_KEY : "xxxxx",
GETUI_APP_SECRET : "xxxx",
PACKAGE_NAME : applicationId,
BAIDU_API_KEY : "xxxx",
QQ_APP_ID : "xxx",
]
//个推的GETUI_APP_ID,代码里面用的
buildConfigField "String", "GETUI_APP_ID", "\"" + manifestPlaceholders.GETUI_APP_ID + "\""
return true
}
rbjk {
applicationId "你的包名3"
versionCode 1
versionName "1.0.0"
manifestPlaceholders = [
GETUI_APP_ID : "xxxxx",
GETUI_APP_KEY : "xxxxxx",
GETUI_APP_SECRET : "xxxx",
PACKAGE_NAME : applicationId,
BAIDU_API_KEY : "xxxx",
QQ_APP_ID : "xxx",
]
//个推的GETUI_APP_ID,代码里面用的
buildConfigField "String", "GETUI_APP_ID", "\"" + manifestPlaceholders.GETUI_APP_ID + "\""
return true
}
}
buildTypes {
//生产版本
release {
// 不显示Log
buildConfigField "boolean", "LOG_DEBUG", "false"
//服务器host
buildConfigField "String", "APP_HOST", "\"http://xxx.xxx.xxx/\""
//是否清理无用资源
shrinkResources false
minifyEnabled false//把false改成true 就打开了混淆的开关
//签名
signingConfig signingConfigs.debug
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
//开发版本
k {
// 显示Log
buildConfigField "boolean", "LOG_DEBUG", "true"
buildConfigField "String", "APP_HOST", "\"http://xxx.xxx.xxx/\""
//是否清理无用资源
shrinkResources false
minifyEnabled false//把false改成true 就打开了混淆的开关
//签名
signingConfig signingConfigs.debug
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
//测试版本
debug {
// 显示Log
buildConfigField "boolean", "LOG_DEBUG", "true"
buildConfigField "String", "APP_HOST", "\"http://xxx.xxx.xxx/\""
//是否清理无用资源
shrinkResources false
minifyEnabled false//把false改成true 就打开了混淆的开关
//签名
signingConfig signingConfigs.debug
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
//不同的打包生成自定义的名称
applicationVariants.all { variant ->
variant.outputs.each { output ->
def outputFile = output.outputFile
if (outputFile != null && outputFile.name.endsWith('.apk')) {
def huanJing;
if (variant.buildType.name.equals('release')) {
huanJing = "s";
} else if (variant.buildType.name.equals('debug')) {
huanJing = "c";
} else {
huanJing = "${variant.buildType.name}";
}
def apkName = huanJing + "${releaseTime()}${variant.productFlavors[0].name}${variant.versionName}.apk"
output.outputFile = new File(outputFile.parent, apkName)
}
}
}
dexOptions {
javaMaxHeapSize "4g"
}
}
repositories {
jcenter()
maven { url "https://jitpack.io" }
}
dependencies {
testCompile 'junit:junit:4.12'
compile fileTree(include: ['*.jar'], dir: 'libs')
//glide依赖库
compile 'com.github.bumptech.glide:glide:3.7.0'
......
}