相信大家的專案用上gradle都已經很久了,但用得如何呢?這裡分享一下我的gradle指令碼,大部分都是去年6月左右就開始用上的,有一部分比如簽名的安全儲存則是最近才自己動手,做了令自己覺得還不錯的方案。
module型別的區分
科普小結,可能有些同學不太明白Java library module和Android library module是怎麼區分的,其實就是個plugin的區別,在module的build.gradle中:
Android application module:
1 |
apply plugin: 'com.android.application' |
Android library module:
1 |
apply plugin: 'com.android.library' |
Java library module:
1 |
apply plugin: 'java' |
版本號管理
如果只有一個application module還好,如果我們有多個module怎麼辦呢?每次改版本號累不累?
解決方案就是在root裡申明全域性變數,可以在單獨的gradle裡(比如新建一個dependency.gradle)申明然後apply from引用進來,或者直接定義在root的build.gradle中。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
project.ext { applicationId = "com.xxx" buildToolsVersion = "23.0.2" compileSdkVersion = 23 minSdkVersion = 14 targetSdkVersion = 23 versionCode = 1 versionName = "1.0.0" abortOnLintError = false checkLintRelease = false useJack = false abortOnLintError = false javaVersion = JavaVersion.VERSION_1_8 ... } |
在子module裡面則使用rootProject.ext去進行引用:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
android { compileSdkVersion rootProject.ext.compileSdkVersion buildToolsVersion rootProject.ext.buildToolsVersion defaultConfig { applicationId rootProject.ext.applicationId minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion versionCode rootProject.ext.versionCode versionName rootProject.ext.versionName multiDexEnabled true } compileOptions { sourceCompatibility rootProject.ext.javaVersion sourceCompatibility rootProject.ext.javaVersion } packagingOptions { exclude 'LICENSE.txt' exclude 'META-INF/DEPENDENCIES' exclude 'META-INF/ASL2.0' exclude 'META-INF/NOTICE' exclude 'META-INF/LICENSE' } lintOptions { abortOnError rootProject.ext.abortOnLintError checkReleaseBuilds rootProject.ext.checkLintRelease quiet true ignoreWarnings true // Some libraries have issues with this. disable 'InvalidPackage' // Lint gives this warning but SDK 20 would be Android L Beta. disable 'OldTargetApi' } ... } |
依賴管理
那麼多第三方庫的引用,在多個module裡引用,修改起版本號來好辛苦,萬一有一個漏改了(比如gson)結果導致了異常行為,搞不好查原因查個半天,結果摔鍵盤竟然是版本號導致的。
so,和上節類似,我們需要統一定義依賴:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
def daggerVersion = "2.0.2" def retrofitVersion = "2.0.0-beta4" def supportVersion = "23.2.1" def rxBindingVersion = '0.4.0' def leakCanaryVersion = "1.3.1" def blockCanaryVersion = '1.1.4' project.ext { ... libSupportAppcompat = "com.android.support:appcompat-v7:${supportVersion}" libSupportDesign = "com.android.support:design:${supportVersion}" libSupportRecyclerview = "com.android.support:recyclerview-v7:${supportVersion}" libSupportV4 = "com.android.support:support-v4:${supportVersion}" libRxAndroid = "io.reactivex:rxandroid:1.1.0" libRxJava = "io.reactivex:rxjava:1.1.1" libEventBus = "org.greenrobot:eventbus:3.0.0" libJavaxAnnotation = "javax.annotation:jsr250-api:1.0" libGson = "com.google.code.gson:gson:2.4" libRetrofit = "com.squareup.retrofit2:retrofit:${retrofitVersion}" libRetrofitConverterGson = "com.squareup.retrofit2:converter-gson:${retrofitVersion}" libRetrofitAdapterRxJava = "com.squareup.retrofit2:adapter-rxjava:${retrofitVersion}" libOkHttpLoggingInterceptor = "com.squareup.okhttp3:logging-interceptor:3.0.0-RC1" libDagger = "com.google.dagger:dagger:${daggerVersion}" libDaggerCompiler = "com.google.dagger:dagger-compiler:${daggerVersion}" libGlide = "com.github.bumptech.glide:glide:3.7.0" libRxBinding = "com.jakewharton.rxbinding:rxbinding:${rxBindingVersion}" libRxBindingSupportV4 = "com.jakewharton.rxbinding:rxbinding-support-v4:${rxBindingVersion}" libRxBindingAppcompatV7 = "com.jakewharton.rxbinding:rxbinding-appcompat-v7:${rxBindingVersion}" libRxBindingDesign = "com.jakewharton.rxbinding:rxbinding-design:${rxBindingVersion}" libRxBindingRecyclerview = "com.jakewharton.rxbinding:rxbinding-recyclerview-v7:${rxBindingVersion}" libRealm = "io.realm:realm-android:0.87.5" debugDependencies = [ leakCanary: "com.squareup.leakcanary:leakcanary-android:${leakCanaryVersion}", blockcanary: "com.github.moduth:blockcanary-ui:${blockCanaryVersion}", ] releaseDependencies = [ leakCanary: "com.squareup.leakcanary:leakcanary-android-no-op:${leakCanaryVersion}", blockcanary: "com.github.moduth:blockcanary-no-op:${blockCanaryVersion}", ] } |
這裡也可以根據個人喜好把版本號也全都抽出去,我個人的實踐原則是除非引用超出1處,否則還是定義在一起。
module中使用:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
dependencies { compile fileTree(include: ['*.jar'], dir: 'libs') ... apt rootProject.ext.libDaggerCompiler compile rootProject.ext.libDagger compile rootProject.ext.libRxJava compile rootProject.ext.libRxAndroid compile rootProject.ext.libRxBinding compile rootProject.ext.libGlide provided rootProject.ext.libJavaxAnnotation compile rootProject.ext.libSupportAppcompat compile rootProject.ext.libSupportDesign compile rootProject.ext.libSupportRecyclerview compile rootProject.ext.libSupportV4 debugCompile rootProject.ext.debugDependencies.leakCanary releaseCompile rootProject.ext.releaseDependencies.leakCanary debugCompile rootProject.ext.debugDependencies.blockCanary releaseCompile rootProject.ext.releaseDependencies.blockCanary } |
這裡我還特地為一些debug和release compile不同包的定義了2個map,見leakCanary和blockCanary引用。
簽名管理
簽名是一個很敏感的東西,只要有了簽名檔案和對應的密碼資訊,就能輕易反編譯修改原始碼然後再簽名進行釋出,因此如何儲存這些敏感資訊是很重要的。
在我的個人實踐中,主要做了這麼幾點:
local.properties定義keystore資訊檔案路徑:
1 |
keystore.props.file=../keystore.properties |
keystore.properties儲存keystore資訊:
1 2 3 4 |
store=../buildsystem/release.jks alias=xxx storePass=xxx pass=xxx |
buildsystem下儲存了:
1 2 3 4 |
$ ls ci.gradle debug.keystore release.jks |
application module的signingConfigs:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
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"] } } |
Java8支援
對Android的module
1 2 3 4 5 6 7 8 |
apply plugin: 'me.tatarka.retrolambda' android { compileOptions { sourceCompatibility rootProject.ext.javaVersion sourceCompatibility rootProject.ext.javaVersion } } |
對Java的module:
1 2 |
sourceCompatibility = 1.8 targetCompatibility = 1.8 |
Split APK
詳細的可以看看Google的官方文件Apk Splits
我的使用:
1 2 3 4 5 6 7 8 |
splits { abi { enable true reset() include 'armeabi', 'x86' //, 'x86', 'armeabi-v7a', 'mips' universalApk false } } |
大致來說,就是可以根據指令碼的配置,將apk以abi、density進行分包。再也不用為了縮小包的體積而專門去只留下一個arm的jni資料夾了,想怎麼分怎麼分,搞不定哪天就要傳一個x86的包了,而且有的模擬器也只支援x86。
當然如果市場能支援這些配置,那就更好了,使用者下載apk的流量就小多了。
Module aar依賴
怎麼能在使用aar依賴提升編譯速度的同時,又能兼顧靈活性,隨時可以修改原始碼呢?
解決方案就是module式aar依賴。
在你的library module目錄下, 開啟build/outputs/aar,是不是有aar檔案(編譯過後就會生成)?把它放到module目錄下面,然後在build.gradle裡面:
1 2 |
configurations.maybeCreate("default") artifacts.add("default", file('lib_authorize-debug.aar')) |
再把原來那些指令碼給註釋了,就搞定了。是不是特別簡單?如果想再使用原始碼依賴,反註釋一下就好了。
總結
本篇主要講了開發階段gradle的各種實踐,下一篇講一講MVPVM的實踐。
打賞支援我寫出更多好文章,謝謝!
打賞作者
打賞支援我寫出更多好文章,謝謝!
任選一種支付方式