1.Android Gradle插件介绍
我们知道Android起始就是Gradle的一个第三方插件,它是由Google的Android开发团队开发的。但从Android的角度来看,Android插件是基于Gradle构建的,和AndroidStudio完美无缝搭配的新一代构建系统。
2.Android Gradle插件分类
在Android中有3类工程
1.App应用工程,他可以生成一个可运行的apk应用。
App插件id :com.android.application
2.Library库工程,他可以生成AAR包给其他App工程公用,就和我们的Jar一样,但是它包含了Android的资源等信息。
Library插件id :com.android.library
3.Test测试工程,用于对App工程或者Library库工程进行单元测试
Test插件id :com.android.test
3.Android Gradle工程配置介绍
apply plugin: 'com.android.application'
android {
compileSdkVersion 29 //配置我们编译Android工程的SDK,29是AndroidSDK的API Level
buildToolsVersion "29.0.2" //Android构建工具的版本
//默认配置
defaultConfig {
applicationId "com.ych.androidgradle" //包名
minSdkVersion 15 //最低支持的Android系统API
targetSdkVersion 29 //我们基于那个Android版本开发的
versionCode 1 //App应用内部版本号
versionName "1.0" //App应用版本名称
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" //用于配置单元测试时使用的Runner
singingConfig singingConfigs.debug //默认配置签名信息
multiDexEnabled true //是否用于差分多个Dex的功能,也可以单独在buildTypes中进行配置。
}
buildTypes {
release {
minifyEnabled false //是否启用混淆 false不启用 true启用
zipAlignEnabled false //整理优化apk文件工具,提高应用运行效率 false不启用 true启用
shrinkResources false //是否自动移除未使用的资源 false不启用 true启用
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' //混淆,所使用的proguard配置文件。
singingConfig singingConfigs.debug //打包时
}
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test:runner:1.2.0'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
}
Android Gradler工程配置都是在android{}中,这是唯一的一个入口,通过它,可以对Android Gradle工程进行自定义配置。
4.自定义Android Gradle工程
4.1 singingConfigs:配置默认的签名信息,对生成的APP签名。
signingConfigs {
release {
storeFile file('../cartoonapp.jks') //签名证书文件
storePassword "xxxxxx" //签名证书文件的密码
keyAlias "xxxxxx" //签名证书中密钥别名
keyPassword "xxxxxx" //签名证书中密钥密码
}
// 默认情况下debug模式签名已经被配置好;自动生成的debug证书,一般在$HOME/.android/debug.keystore
debug {
storeFile file('../cartoonapp.jks') //签名证书文件
storePassword "xxxxxx" //签名证书文件的密码
keyAlias "xxxxxx" //签名证书中密钥别名
keyPassword "xxxxxx" //签名证书中密钥密码
}
}
5.高级自定义Android Gradle(动态生成版本信息)
如果只有一个application module还好,如果我们有多个module怎么办呢?每次改版本号累不累?
解决方案:就是在root里申明全局变量,可以在单独的gradle里(比如新建一个config.gradle)
注意:申明然后使用apply from引用进来,或者直接定义在root的build.gradle中。
apply plugin: 'com.android.application'
apply from: '../config.gradle' //引入进来 ../表示上一级
android {
...
}
5.1 config.gradle文件配置
rootProject.ext {
android = [
compileSdkVersion : 29,
buildToolsVersion : "29.0.2",
applicationId : "com.ych.mvpadvance",
minSdkVersion : 15,
targetSdkVersion : 29,
versionCode : 1,
versionName : "1.0"
]
//版本号
version = [
androidSupportSdkVersion: "28.0.0",
retrofitSdkVersion : "2.6.0",
dagger2SdkVersion : "2.23.2",
glideSdkVersion : "4.9.0",
butterknifeSdkVersion : "9.0.0",
rxlifecycleSdkVersion : "1.0",
rxlifecycle2SdkVersion : "2.2.2",
espressoSdkVersion : "3.0.1",
canarySdkVersion : "1.6.3"
]
dependencies = [
//support
"appcompat-v7" : "com.android.support:appcompat-v7:${version["androidSupportSdkVersion"]}",
"design" : "com.android.support:design:${version["androidSupportSdkVersion"]}",
"support-v4" : "com.android.support:support-v4:${version["androidSupportSdkVersion"]}",
"cardview-v7" : "com.android.support:cardview-v7:${version["androidSupportSdkVersion"]}",
"annotations" : "com.android.support:support-annotations:${version["androidSupportSdkVersion"]}",
"recyclerview-v7" : "com.android.support:recyclerview-v7:${version["androidSupportSdkVersion"]}",
//network
"retrofit" : "com.squareup.retrofit2:retrofit:${version["retrofitSdkVersion"]}",
"retrofit-converter-gson" : "com.squareup.retrofit2:converter-gson:${version["retrofitSdkVersion"]}",
"retrofit-adapter-rxjava" : "com.squareup.retrofit2:adapter-rxjava:${version["retrofitSdkVersion"]}",
"retrofit-adapter-rxjava2" : "com.squareup.retrofit2:adapter-rxjava2:${version["retrofitSdkVersion"]}",
"okhttp3" : "com.squareup.okhttp3:okhttp:3.5.0",
"okhttp4" : "com.squareup.okhttp3:okhttp:4.0.0",
"okhttp-urlconnection" : "com.squareup.okhttp:okhttp-urlconnection:2.0.0",
"glide" : "com.github.bumptech.glide:glide:${version["glideSdkVersion"]}",
"glide-compiler" : "com.github.bumptech.glide:compiler:${version["glideSdkVersion"]}",
"glide-loader-okhttp3" : "com.github.bumptech.glide:okhttp3-integration:${version["glideSdkVersion"]}",
"picasso" : "com.squareup.picasso:picasso:2.5.2",
//view
"autolayout" : "com.zhy:autolayout:1.4.5",
"butterknife" : "com.jakewharton:butterknife:${version["butterknifeSdkVersion"]}",
"butterknife-compiler" : "com.jakewharton:butterknife-compiler:${version["butterknifeSdkVersion"]}",
"pickerview" : "com.contrarywind:Android-PickerView:3.2.5",
"photoview" : "com.github.chrisbanes.photoview:library:1.2.3",
"numberprogressbar" : "com.daimajia.numberprogressbar:library:1.2@aar",
"nineoldandroids" : "com.nineoldandroids:library:2.4.0",
"paginate" : "com.github.markomilos:paginate:0.5.1",
"vlayout" : "com.alibaba.android:vlayout:1.1.0@aar",
"autosize" : "me.jessyan:autosize:1.1.2",
//rx1
"rxandroid" : "io.reactivex:rxandroid:1.2.1",
"rxjava" : "io.reactivex:rxjava:1.3.0",
"rxlifecycle" : "com.trello:rxlifecycle:${version["rxlifecycleSdkVersion"]}",
"rxlifecycle-components" : "com.trello:rxlifecycle-components:${version["rxlifecycleSdkVersion"]}",
"rxcache" : "com.github.VictorAlbertos.RxCache:runtime:1.7.0-1.x",
"rxcache-jolyglot-gson" : "com.github.VictorAlbertos.Jolyglot:gson:0.0.4",
"rxbinding-recyclerview-v7": "com.jakewharton.rxbinding:rxbinding-recyclerview-v7:1.0.1",
"rxpermissions" : "com.tbruyelle.rxpermissions:rxpermissions:0.9.4@aar",
"rxerrorhandler" : "me.jessyan:rxerrorhandler:1.0.1",
//rx2
"rxandroid2" : "io.reactivex.rxjava2:rxandroid:2.1.1",
"rxjava2" : "io.reactivex.rxjava2:rxjava:2.2.10",
"rxlifecycle2" : "com.trello.rxlifecycle2:rxlifecycle:${version["rxlifecycle2SdkVersion"]}",
"rxlifecycle2-android" : "com.trello.rxlifecycle2:rxlifecycle-android:${version["rxlifecycle2SdkVersion"]}",
"rxlifecycle2-components" : "com.trello.rxlifecycle2:rxlifecycle-components:${version["rxlifecycle2SdkVersion"]}",
"rxcache2" : "com.github.VictorAlbertos.RxCache:runtime:1.8.3-2.x",
"rxpermissions2" : "com.github.tbruyelle:rxpermissions:0.10.2",
"rxerrorhandler2" : "me.jessyan:rxerrorhandler:2.1.1",
//tools
"dagger2" : "com.google.dagger:dagger:${version["dagger2SdkVersion"]}",
"dagger2-android" : "com.google.dagger:dagger-android:${version["dagger2SdkVersion"]}",
"dagger2-android-support" : "com.google.dagger:dagger-android-support:${version["dagger2SdkVersion"]}",
"dagger2-compiler" : "com.google.dagger:dagger-compiler:${version["dagger2SdkVersion"]}",
"dagger2-android-processor": "com.google.dagger:dagger-android-processor:${version["dagger2SdkVersion"]}",
"androideventbus" : "org.simple:androideventbus:1.0.5.1",
"eventbus" : "org.greenrobot:eventbus:3.1.1",
"otto" : "com.squareup:otto:1.3.8",
"gson" : "com.google.code.gson:gson:2.8.5",
"multidex" : "com.android.support:multidex:1.0.3",
"javax.annotation" : "javax.annotation:jsr250-api:1.0",
"arouter" : "com.alibaba:arouter-api:1.3.1",
"arouter-compiler" : "com.alibaba:arouter-compiler:1.1.4",
"progressmanager" : "me.jessyan:progressmanager:1.5.0",
"retrofit-url-manager" : "me.jessyan:retrofit-url-manager:1.4.0",
"lifecyclemodel" : "me.jessyan:lifecyclemodel:1.0.1",
//test
"junit" : "junit:junit:4.12",
"androidJUnitRunner" : "android.support.test.runner.AndroidJUnitRunner",
"runner" : "com.android.support.test:runner:1.0.1",
"espresso-core" : "com.android.support.test.espresso:espresso-core:${version["espressoSdkVersion"]}",
"espresso-contrib" : "com.android.support.test.espresso:espresso-contrib:${version["espressoSdkVersion"]}",
"espresso-intents" : "com.android.support.test.espresso:espresso-intents:${version["espressoSdkVersion"]}",
"mockito-core" : "org.mockito:mockito-core:1.+",
"timber" : "com.jakewharton.timber:timber:4.7.1",
"logger" : "com.orhanobut:logger:2.2.0",
"canary-debug" : "com.squareup.leakcanary:leakcanary-android:${version["canarySdkVersion"]}",
"canary-release" : "com.squareup.leakcanary:leakcanary-android-no-op:${version["canarySdkVersion"]}",
"umeng-analytics" : "com.umeng.analytics:analytics:6.0.1"
]
}
5.2 引用config.gradle文件中配置信息
apply plugin: 'com.android.application'
apply from: '../config.gradle'
android {
compileSdkVersion rootProject.ext.android["compileSdkVersion"]
buildToolsVersion rootProject.ext.android["buildToolsVersion"]
defaultConfig {
applicationId rootProject.ext.android["applicationId"]
minSdkVersion rootProject.ext.android["minSdkVersion"]
targetSdkVersion rootProject.ext.android["targetSdkVersion"]
versionCode rootProject.ext.android["versionCode"]
versionName rootProject.ext.android["versionName"]
testInstrumentationRunner rootProject.ext.dependencies["androidJUnitRunner"]
//设置支持的SO库架构
ndk {
abiFilters 'armeabi', 'armeabi-v7a', 'arm64-v8a' ,'x86' , 'x86_64'
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
debug {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test:runner:1.2.0'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
//引用
implementation rootProject.ext.dependencies.okhttp3
}
6.动态配置AndroidManifest文件
Android Gradle中提供了非常便捷的方法让我们来替换AndroidManifest文件内容,他就是manifestPlaceholder,Manifest占位符,也可以在defaultConfig中配置。
productFlavors {
_xiaomi {
...
manifestPlaceholders = [
JPUSH_PKGNAME: applicationId,
JPUSH_APPKEY : rootProject.ext.apienv == 0 ? rootProject.ext.jpushReleaseKey : rootProject.ext.apienv == 4 ? rootProject.ext.jpushReleaseKey : rootProject.ext.jpushTestKey, //JPush上注册的包名对应的appkey. 正式
JPUSH_CHANNEL: "developer-default", //暂时填写默认值即可.
JPUSH_APPNAME: rootProject.ext.apienv == 0 ? "安路通正式2.1" : rootProject.ext.apienv == 4 ? "天天快车" : "安路通测试2.1",
BAIDU_APPKEY : rootProject.ext.apienv == 0 ? rootProject.ext.baiduReleaseKey : rootProject.ext.apienv == 4 ? rootProject.ext.baiduReleaseKey : rootProject.ext.baiduTestKey,
JPUSH_ICON : rootProject.ext.apienv == 0 ? "@mipmap/ic_launcher": rootProject.ext.apienv == 1 ? "@mipmap/ic_launcher": "@drawable/tianhong",
]
}
}
AndroidManifest中使用:
<application
android:name=".app.SampleApplication"
android:allowBackup="true"
android:icon="${JPUSH_ICON}"
android:label="${JPUSH_APPNAME}"
android:largeHeap="true"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<!-- Required. For publish channel feature -->
<!-- JPUSH_CHANNEL 是为了方便开发者统计APK分发渠道。 -->
<!-- 例如: -->
<!-- 发到 Google Play 的APK可以设置为 google-play; -->
<!-- 发到其他市场的 APK 可以设置为 xxx-market。 -->
<!-- 目前这个渠道统计功能的报表还未开放。 -->
<meta-data
android:name="JPUSH_CHANNEL"
android:value="${JPUSH_CHANNEL}" />
<!-- Required. AppKey copied from Portal -->
<meta-data
android:name="JPUSH_APPKEY"
android:value="${JPUSH_APPKEY}" />
</application>
7.自定义你的BuildConfig
//默认的BuildConfig
public final class BuildConfig {
public static final boolean DEBUG = Boolean.parseBoolean("true");
public static final String APPLICATION_ID = "com.ych.androidgradle";
public static final String BUILD_TYPE = "debug";
public static final String FLAVOR = "";
public static final int VERSION_CODE = 1;
public static final String VERSION_NAME = "1.0";
}
假设我们有 Baidu 和 Google 两个渠道,发布的时候也会有两个渠道。当我们安装Baidu渠道包的时候打开的 是Baidu首页,当安装Google渠道包的时候,打开的是Google的首页。我们只需要添加一个字段(WEB_URL),字段名自己定义。
android {
compileSdkVersion 29
buildToolsVersion "29.0.2"
defaultConfig {
applicationId "com.ych.androidgradle"
minSdkVersion 15
targetSdkVersion 29
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
productFlavors {
google {
buildConfigField "String", "WEB_URL", ' "http://www.google.com " '
buildConfigField "int", "API_ENV", ' "1 " '
buildConfigField "boole", "API_ENV", ' "1 " '
}
baidu {
buildConfigField "String", "WEB_URL", ' "http://www.baidu.com " '
buildConfigField "int", "API_ENV", ' "2" '
}
}
}
8.签名管理(非常重要)
签名是一个很敏感的东西,只要有了签名文件和对应的密码信息,就能轻易反编译修改源码然后再签名进行发布,因此如何保存这些敏感信息是很重要的。
在我的个人实践中,主要做了这么几点:
8.1 在local.properties文件下定义keystore信息文件路径:
sdk.dir=D\:\\Develop\\SDK
keystore.props.file=../keystore.properties
8.2 keystore.properties保存keystore信息:
store=../buildsystem/alt.keystore
alias=xxx
pass=xxx
storePass=xxx
8.3 buildsystem下保存了:
文件加下放入我们的签名文件 xxx.keystore/ xxx.jks
debug.keystore
release.keystore
**8.4 application module的signingConfigs:
signingConfigs {
def Properties localProps = new Properties()
localProps.load(new FileInputStream(file('../local.properties')))
def Properties keyProps = new Properties()
// 如果读取不到'keystore.props.file'属性,就使用debug keystore
if (localProps['keystore.props.file']) {
keyProps.load(new FileInputStream(file(localProps['keystore.props.file'])))
} else {
keyProps["store"] = '../buildsystem/debug.keystore'
keyProps["alias"] = 'android'
keyProps["storePass"] = 'androiddebugkey'
keyProps["pass"] = 'android'
}
debug {
storeFile file(keyProps["store"])
keyAlias keyProps["alias"]
storePassword keyProps["storePass"]
keyPassword keyProps["pass"]
}
release {
// release版本使用assert确保存在该属性否则报错,避免错误打包
assert localProps['keystore.props.file'];
storeFile file(keyProps["store"])
keyAlias keyProps["alias"]
storePassword keyProps["storePass"]
keyPassword keyProps["pass"]
}
}
9.总结
本篇主要讲了开发阶段gradle的各种实践,希望可以帮到大家。
作者:如愿以偿丶
链接:https://www.jianshu.com/p/6c1fcf251623
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。