學無止境,有一技旁身,至少不至于孤陋寡聞。
隨著我們工作閱歷的提升,除了基本的業務開發,也需要提升我們自身在開發效能方面的一些儲備與筆記。
Android開發日常之gradle
Android開發日常之adb
Android開發日常之git
Android開發日常之shell alias
在Android開發中在項目根目錄、app或者其他module中我們都能看到build.gradle
這個文件,我們也知道Android項目的編譯和運行都是通過gradle來實現,需要引入第三方庫時就找到對應項目的build.gradle
中按照集成文檔修修改改引入即可,有可能也不會過多的去關注,這里簡單介紹下關于在Android開發中gradle的使用。
-
調整gradle的編譯參數(gradle.properties文件中配置)
內存配置:org.gradle.jvmargs=-Xmx4096m -XX:MaxPermSize=1024m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
- 堆的內存分配用-Xms和-Xmx
- Xms分配堆最小內存,默認為物理內存的1/64;
- Xmx分配最大內存,默認為物理內存的1/4。
- 非堆內存分配用-XX:PermSize和-XX:MaxPermSize
- XX:PermSize分配非堆最小內存,默認為物理內存的1/64;
- XX:MaxPermSize分配最大內存,默認為物理內存的1/4。
守護進程
org.gradle.daemon=true
并行編譯
org.gradle.parallel=true
開啟緩存
android.enableBuildCache=true
開啟孵化模式
org.gradle.configureondemand=true
更多配置信息,移步Gradle官方文檔 - 堆的內存分配用-Xms和-Xmx
-
推薦引用固定版本依賴庫
dependencies { compile 'com.google.code.gson:gson:2.2.1' //推薦寫法 // compile 'com.google.code.gson:gson:2.+' // 不推薦寫法 }
雖然帶+號的引用可以保證庫是最新的,但更新的新庫有沒有更改庫邏輯而帶來的bug是未知的。
-
module、jar及aar的依賴方式
implementation project(':commonlibrary') implementation files('libs/alipaysdk.jar') implementation(name: 'xpay-1.0.1', ext: 'aar')
- module生成jar
def ccLibName = 'cc-1.0.1.jar' task makeJar(type: Copy) { //刪除存在的 delete 'build/libs/'+ccLibName //設置拷貝的文件 from('build/intermediates/packaged-classes/release/') //打進jar包后的文件目錄 into('build/libs/') //將classes.jar放入build/libs/目錄下 //include ,exclude參數來設置過濾 include('classes.jar') rename ('classes.jar',ccLibName) } makeJar.dependsOn(build)
- module生成aar(默認編譯會生成aar,此處更改aar生成名稱)
buildTypes { release { ... ... android.libraryVariants.all { variant -> if(variant.name.equalsIgnoreCase("release")) { variant.outputs.all { output -> def f = output.outputFileName if (f != null && f.endsWith('.aar')) { def fileName = "cc-v${defaultConfig.versionName}.aar" output.outputFileName = fileName } } } } } }
- module生成jar
-
用exclude關鍵字解決依賴庫沖突問題
如我們在Android項目中集成某個第三方庫時,可能第三方庫也會引入某個本地已經引入的庫,所以就會存在引入多版本的依賴庫。- 移除整個組織的庫
compile ('com.facebook.fresco:animated-webp:0.13.0') { exclude group: 'com.android.support' // 僅僅寫組織名稱 }
- 精確移除某個指定庫
compile('com.android.support:appcompat-v7:23.2.0') { exclude group: 'com.android.support', module: 'support-annotations' // 寫全稱 exclude group: 'com.android.support', module: 'support-compat' exclude group: 'com.android.support', module: 'support-v4' exclude group: 'com.android.support', module: 'support-vector-drawable' }
如何產看項目中的第三方庫的依賴關系?
執行以下命令行:(如何你想查看某個module的依賴關系,此處的app使用你的module名來替換即可
)-
Windows:
gradlew :app:dependencies > dependencis.txt
-
MAC:
./gradlew :app:dependencies > dependencis.txt
- 移除整個組織的庫
-
設置java版本
- 如果是在某個module中設置,那么就在對應module的build.gradle文件中配置:
android { compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 } }
- 如果想要做全局配置,那么就在根目錄的build.gradle中配置:
allprojects { repositories { jcenter() } tasks.withType(JavaCompile) { sourceCompatibility = JavaVersion.VERSION_1_8 targetCompatibility = JavaVersion.VERSION_1_8 } }
- 如果是在某個module中設置,那么就在對應module的build.gradle文件中配置:
-
在build.gradle中設置productFlavors
android { productFlavors { baidu { manifestPlaceholders = [UMENG_CHANNEL_VALUE: "baidu"] } xiaomi { manifestPlaceholders = [UMENG_CHANNEL_VALUE: "xiaomi"] } } }
-
assemble是Gradle中的編譯打包命令
- 打包baidu渠道的release版本
gradlew assembleBaiduRelease
- 打包baidu渠道的debug版本
gradlew assembleBaiduDebug
- 生成baidu渠道的Release和Debug版本
gradlew assembleBaidu
- 打包全部渠道Release版本
gradlew assembleRelease
- 打包baidu渠道的release版本
-
為各渠道設置各自的配置信息
android { productFlavors { baidu { applicationId "com.liujc.demo.baidu" manifestPlaceholders = [UMENG_CHANNEL_VALUE: "baidu", APP_NAME : "app應用01", //app名稱 ] buildConfigField "String", "API_APP_ID", "\"10001\"" } xiaomi { applicationId "com.liujc.demo.xiaomi" manifestPlaceholders = [UMENG_CHANNEL_VALUE: "xiaomi", APP_NAME : "app應用02", //app名稱 ] buildConfigField "String", "API_APP_ID", "\"10002\"" } } }
如何使用?
如上的applicationId
和manifestPlaceholders
中信息在AndroidManifest
中使用如下:android:label="${APP_NAME}" <uses-permission android:name="${applicationId}.permission.JPUSH_MESSAGE" />
而
buildConfigField
中的參數在代碼中使用BuildConfig.API_APP_ID
。 -
Android Studio 為多渠道執行自定義名稱打包命令:
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')) { // 計劃輸出apk名稱為App_V1.0.0_baidu.apk def fileName = "App_V${variant.productFlavors.versionName}_${variant.productFlavors.name}.apk" output.outputFile = new File(outputFile.parent, fileName) } } }
下面是多渠道配置:
android { productFlavors { baidu { applicationId "com.liujc.demo.baidu" versionCode 1 versionName "1.0.0" manifestPlaceholders = [UMENG_CHANNEL_VALUE: "baidu", APP_NAME : "app應用01", //app名稱 ] buildConfigField "String", "API_APP_ID", "\"10001\"" } xiaomi { versionCode 2 versionName "1.0.1" applicationId "com.liujc.demo.xiaomi" manifestPlaceholders = [UMENG_CHANNEL_VALUE: "xiaomi", APP_NAME : "app應用02", //app名稱 ] buildConfigField "String", "API_APP_ID", "\"10002\"" } } }
打包成功后你會發現包名為:
App_V[1.0.0]_[baidu].apk
,這不是我想要的啊,怎么都多了個中括號呢,修改打包代碼: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')) { // 計劃輸出apk名稱為App_V1.0.0_baidu.apk def fileName = "App_V${variant.productFlavors[0].versionName}_${variant.productFlavors[0].name}.apk" output.outputFile = new File(outputFile.parent, fileName) } } }
再重新打包,成功后發現包名為:
App_V1.0.0_baidu.apk
OK了。 -
打包時相關屬性介紹
name:build type的名字
applicationIdSuffix:應用id后綴
versionNameSuffix:版本名稱后綴
debuggable:是否生成一個debug的apk
minifyEnabled:是否混淆
proguardFiles:混淆文件
signingConfig:簽名配置
manifestPlaceholders:清單占位符
shrinkResources:是否去除未利用的資源,默認false,表示不去除。
zipAlignEnable:是否使用zipalign工具壓縮。
multiDexEnabled:是否拆成多個Dex
multiDexKeepFile:指定文本文件編譯進主Dex文件中
multiDexKeepProguard:指定混淆文件編譯進主Dex文件中
以下開發中開發中常用的gradle命令
生成Android項目的依賴文件并導出
gradlew :app:dependencies > dependencis.txt
查看編譯日志詳細信息
gradlew compileDebugSource --stacktrace -info
輸出項目debug編譯日志
gradlew assembleDebug --info>log2.txt
獲取構建報告,以HTML的形式展示。
gradle build -profile
gradle build -x lint
在Task Execution(任務執行)中去掉lint任務,節省Gradle構建時間。
Tips:使用Android Studio任務欄直接點擊運行按鈕是不能去掉lint任務的,所以為了方便構建后安裝應用,可以使用gradle installDebug -x lint
命令。-
Clean命令
mac: ./gradlew clean build --info > cleanlog.log windows: gradlew.bat clean build --info > cleanlog.log
使用help
./gradlew --help
-
build 某個指定 module
AS 推薦的結構是multiple project
結構,即一個 project 下,管理多個 module,如果每次都要 build 全部的 project 的話,有點浪費時間,則可以使用-p module
參數,其中 module 是你要 build 的 module:$ ./gradlew -p app clean build $ ./gradlew -p app/app_module assembledebug
-
明確指定不執行某個 task
Gradle 的命令存在依賴,例如 build task,是依賴于一系列的其他的 task,如果想要指定不執行某個 task,則可以使用-x task
參數,其中 task 是要忽略的那個,這個參數可以傳遞多次。$ ./gradlew build -x test -x lint
-
執行多模塊任務
當你在工程根目錄下通過命令行窗口運行任務時,Gradle會找出所有模塊中的同名任務,并運行它們。比如,你有一個app模塊和一個Android Wear模塊,運行./gradlew assembleDebug
將會為app模塊和Android Wear模塊都構建一個debug版本。如果你切換到模塊的目錄下,Gradle將只會運行該模塊的任務,即使你在工程根目錄中運行Gradle Wrapper。比如,在Android Wear模塊的目錄運行./gradlew assembleDebug
,只會構建Android Wear模塊。切換目錄的方式來運行模塊的任務是比較繁瑣的。另一個方式是可以使用模塊名稱來預處理任務名稱,使運行任務只在那個模塊上運行。比如只想構建Android Wear模塊,可以使用如下命令:
./gradlew :wear:assembleDebug ./gradlew -p app/app_module assembledebug