相信大家的項(xiàng)目用上gradle都已經(jīng)很久了,但用得如何呢?這里分享一下我的gradle腳本,大部分都是去年6月左右就開始用上的,有一部分比如簽名的安全保存則是最近才自己動手,做了令自己覺得還不錯(cuò)的方案。
module類型的區(qū)分 科普小結(jié),可能有些同學(xué)不太明白Java library module和Android library module是怎么區(qū)分的,其實(shí)就是個(gè)plugin的區(qū)別,在module的build.gradle中:
Android application module:
1 apply plugin: 'com.android.application'
Android library module:
1 apply plugin: 'com.android.library'
Java library module:
版本號管理 如果只有一個(gè)application module還好,如果我們有多個(gè)module怎么辦呢?每次改版本號累不累?
解決方案就是在root里申明全局變量,可以在單獨(dú)的gradle里(比如新建一個(gè)dependency.gradle)申明然后apply from引用進(jìn)來,或者直接定義在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去進(jìn)行引用:
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' } ... }
依賴管理 那么多第三方庫的引用,在多個(gè)module里引用,修改起版本號來好辛苦,萬一有一個(gè)漏改了(比如gson)結(jié)果導(dǎo)致了異常行為,搞不好查原因查個(gè)半天,結(jié)果摔鍵盤竟然是版本號導(dǎo)致的。
so,和上節(jié)類似,我們需要統(tǒng)一定義依賴:
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}' , ] }
這里也可以根據(jù)個(gè)人喜好把版本號也全都抽出去,我個(gè)人的實(shí)踐原則是除非引用超出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個(gè)map,見leakCanary和blockCanary引用。
簽名管理 簽名是一個(gè)很敏感的東西,只要有了簽名文件和對應(yīng)的密碼信息,就能輕易反編譯修改源碼然后再簽名進(jìn)行發(fā)布,因此如何保存這些敏感信息是很重要的。
在我的個(gè)人實(shí)踐中,主要做了這么幾點(diǎn):
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確保存在該屬性否則報(bào)錯(cuò),避免錯(cuò)誤打包 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 詳細(xì)的可以看看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 } }
大致來說,就是可以根據(jù)腳本的配置,將apk以abi、density進(jìn)行分包。再也不用為了縮小包的體積而專門去只留下一個(gè)arm的jni文件夾了,想怎么分怎么分,搞不定哪天就要傳一個(gè)x86的包了,而且有的模擬器也只支持x86。
當(dāng)然如果市場能支持這些配置,那就更好了,用戶下載apk的流量就小多了。
Module aar依賴 怎么能在使用aar依賴提升編譯速度的同時(shí),又能兼顧靈活性,隨時(shí)可以修改源碼呢?
解決方案就是module式aar依賴。
在你的library module目錄下, 打開build/outputs/aar,是不是有aar文件(編譯過后就會生成)?把它放到module目錄下面,然后在build.gradle里面:
1 2 configurations.maybeCreate('default' ) artifacts.add('default' , file('lib_authorize-debug.aar' ))
再把原來那些腳本給注釋了,就搞定了。是不是特別簡單?如果想再使用源碼依賴,反注釋一下就好了。
總結(jié) 本篇主要講了開發(fā)階段gradle的各種實(shí)踐,下一篇是什么暫時(shí)我也沒有想法,哈哈。