以下內容均為個人理解,如果有描述不正確的地方,歡迎指正
轉載請注明原文鏈接
Gradle簡介
開始填坑之前,先簡單聊聊gradle,Gradle其實就是一個構建項目的工具,也就是把那一個個文件、文件夾按照一定的規則關聯起來,形成一個項目的工具,它其實不僅僅是用在AndroidStudio上。
我們在AS中用到的Gradle其實應該被叫做 Android Gradle Plugin,也就是安卓項目上的gradle插件;
Gradle插件會有版本號,每個版本號又對應有一個或一些 Gradle發行版本(一般是限定一個最低版本),也就是我們常見的類似gradle-3.1-all.zip這種東西;
如果這兩個版本對應不上了,那你的工程構建的時候就會報錯。
對應關系如下(參考自 https://developer.android.google.cn):
插件版本 | Gradle版本 |
---|---|
1.0.0 - 1.1.3 | 2.2.1 - 2.3 |
1.2.0 - 1.3.1 | 2.2.1 - 2.9 |
1.5.0 | 2.2.1 - 2.13 |
2.0.0 - 2.1.2 | 2.10 - 2.13 |
2.1.3 - 2.2.3 | 2.14.1+ |
2.3.0+ | 3.3+ |
3.0.0+ | 4.1+ |
Android Studio 3.0 之后自動將插件版本升級到3.0.0,所以我們也需要對應地把Gradle升級到4.1才行
另外, Android Gradle Plugin又會跟 Android SDK BuildTool有關聯,因為它還承接著AndroidStudio里的編譯相關的功能,這也是我們要在項目的 local.properties 文件里寫明Android SDK路徑、在build.gradle 里注明 buildToolsVersion 的原因。
所以 Android Gradle Plugin 本質上就是 一個AS的插件,它一邊調用 Gradle本身的代碼和批處理工具來構建項目,一邊調用Android SDK的編譯、打包功能,從而讓我們能夠順暢地在AS上進行開發。
升級Android Gradle Plugin到3.0.1的踩坑之旅
-
把工程目錄下的build.gradle中,將gradle插件版本升級到3.0.1
dependencies { classpath 'com.android.tools.build:gradle:3.0.1' //這里從2.2.2改到了3.0.1 }
-
點擊同步gradle,報錯。
提示gradle-wrapper版本過低,gradle-wrapper的作用,就是設置你的項目工程要對應用那個Gradle發行版本來執行構建,
3.0.1的插件版本必須對應4.1以上的gradle版本,因此需要在../gradle/wrapper/gradle-wrapper.properties文件中把版本號改為4.1distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-all.zip //這里從 3.1 改到了 4.1
然后同步gradle。
通常情況下你會發現速度特別慢,因為沒有翻墻,默認是從國外服務器下載gradle;
這時候就可以強關AS,直接在網上找資源,把gradle-4.1-all.zip這個包,放在C:\Users\你的用戶名.gradle\wrapper\dists\gradle-4.1-all\bzyivzo6n839fup2jbap0tjew
目錄中(最后那個亂碼文件夾名字每臺機器上不一樣),注意不需要手動解壓,然后重啟AS自動同步gradle即可;
-
重啟自動同步之后,又報錯。
提示有一些依賴庫無法正常引用,需要添加google maven 倉庫的依賴;
在工程目錄下的build.gradle 文件加上maven依賴即可,repositories { mavenCentral() jcenter() //加上下面這段 maven { url 'https://maven.google.com/' name 'Google' } }
再同步gradle,又報錯。
這次是提示沒有26.0.2版本的 SDK buildTool ,然后直接在AS報錯彈框里點擊下載就可以了。現在SDK可以不用翻墻直接下載,速度還蠻快的。下載確認解壓之后再次同步gradle。-
同步gradle,此時又會報錯:
Error:The specified Android SDK Build Tools version (25.0.0) is ignored, as it is below the minimum supported version (26.0.2) for Android Gradle Plugin 3.0.1. Android SDK Build Tools 26.0.2 will be used. To suppress this warning, remove "buildToolsVersion '25.0.0'" from your build.gradle file, as each version of the Android Gradle Plugin now has a default version of the build tools.
這個提示,說是需要去掉各個module的build.gradle中的 buildToolsVersion 的設置,因為3.0.1以上的gradle插件會自動用一個默認的BuildTool版本,不需要像以前一樣,在每個build.gradle里寫明buildToolsVersion了。
所以我們把提示到的各個build.gradle中的這行刪掉,再重新同步一下gradle,就不會報這個錯了。 -
再次同步gradle,繼續報錯:
Error:All flavors must now belong to a named flavor dimension. Learn more at https://d.android.com/r/tools/flavorDimensions-missing-error-message.html
需要在app/build.gradle加上默認的dimension;大概就是為了保證各個渠道包要保持某些屬性的一致;總之按照官網上的說法,只要給每個渠道都設置一個“flavorDimensions”就可以了,代碼如下(app/build.gradle)
flavorDimensions "default"http://這個名字貌似隨便取,也可以有多個,總之一定要有.. productFlavors { market { dimension "default" } // other{ // dimension "default" //如果有其他的渠道,也要做類似的聲明 // } }
繼續同步,繼續報錯...
這次的錯誤提示比較接地氣了,說是build/intermediates/xxxx.xml 里的某個值沒有找到,這個簡單,build目錄下的都是編譯期生成的文件,clean下再來一發;或者直接rebuild項目(rebuild = clean + build)-
rebuild項目,仍然報錯
Error:Execution failed for task ':framework:third:xxxModule:javaPreCompileDebug'. Annotation processors must be explicitly declared now. The following dependencies on the compile classpath are found to contain annotation processor. Please add them to the annotationProcessor configuration. xxxxxx.jar (com.xxxx:xxxxx:1.0.5) Alternatively, set android.defaultConfig.javaCompileOptions.annotationProcessorOptions.includeCompileClasspath = true to continue with previous behavior. Note that this option is deprecated and will be removed in the future. See https://developer.android.com/r/tools/annotation-processor-error-message.html for more details.
一時半會兒不知道怎么搞,看看這個開發者文檔鏈接的說明吧,
developer.android.com這個域名不翻墻是進不去的,不過現在已經有了國內的域名,把域名替換成developer.android.google.cn,后面保持不變就可以訪問了;其他類似的官方文檔地址也一樣可以用這個方法去訪問。看了下官方文檔,大意是在說,工程里的某個module依賴了某個jar包,然后jar里面又用到了注解,在新的gradle版本里,需要寫新的groovy代碼來對每個引用注解的地方單獨配置。在以往的版本中,gradle會默認給每個module都依賴一個annotationProcess,導致很多多余的對annotationProcess的依賴,老版本中的默認方法,會在將來版本中被刪除。
按照提示,解決方案大致有兩個:
要么我們需要在依賴于注解的module中,加上“annotationProcessor”這個配置;
要么我們可以設置android.defaultConfig.javaCompileOptions.annotationProcessorOptions.includeCompileClasspath = true,但是要注意這玩法以后會被刪除按照官方推薦的第一種方法:應該是在報錯的build.gradle中修改:
dependencies { compile xxxxx ... //加上類似這些對于注解處理器的的依賴 annotationProcessor 'com.xxxx.xxxxx-1.0.0' }
但是我加上了并沒有什么作用,原因待查..
為了節約時間,還是先用includeCompileClasspath=true的辦法湊合下吧,以后真的被刪除了再說...直接在app/build.gradle(準確的說是每個涉及到注解依賴的module的build.gradle)上加一行
defaultConfig { minSdkVersion rootProject.ext.android.minSdkVersion targetSdkVersion rootProject.ext.android.targetSdkVersion versionCode 1 versionName "1.0" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" javaCompileOptions { annotationProcessorOptions { includeCompileClasspath = true //加上這行即可 } } }
然后再次同步gradle
-
同步gradle,不出意外的又報錯了。
一堆的style屬性未找到的問題,跟第六步里的現象貌似是一樣的Error:(713, 5) error: style attribute '@android:attr/windowExitAnimation' not found. Error:(713, 5) error: style attribute '@android:attr/windowExitAnimation' not found. Error:(713, 5) error: style attribute '@android:attr/windowExitAnimation' not found.
這才發現其實clean是沒有用的,真正的問題原因在一堆錯誤的最后幾行
Error:java.util.concurrent.ExecutionException: java.util.concurrent.ExecutionException: com.android.tools.aapt2.Aapt2Exception: AAPT2 error: check logs for details Error:java.util.concurrent.ExecutionException: com.android.tools.aapt2.Aapt2Exception: AAPT2 error: check logs for com.android.tools.aapt2.Aapt2Exception: AAPT2 error: check logs for details
AAPT2 , 貌似就是aapt的2.0版本?
aapt.exe 是 Android SDK里的一個工具,詳情出門左轉自己查去..
直接說解決方案:
在Project/gradle.properties中添加 android.enableAapt2=false
再次同步... -
嗯,沒錯,又報錯了。
Error:(247, 1) Execution failed for task ':app:processMarketDebugManifest'. Manifest Tasks does not support the manifestOutputFile property any more, please use the manifestOutputDirectory instead. For more information, please check https://developer.android.com/studio/build/gradle-plugin-3-0-0-migration.html
這個錯跟7號有點類似,又是新版本gradle插件不支持某些方法啦,又要換用新的寫法才行啦...然后最后給你貼一個文檔地址自己看去。。
大概就是說:現在不支持manifestOutputFile這個方法,要用processManifest.manifestOutputDirectory()來替換,也就是你app/build.gradle 打包的這一段代碼要重新寫一下;一般我們都會在build.gradle中編寫這樣的代碼,來實現對Manifest文件的修改、以及自定義apk的輸出文件名等。
android.applicationVariants.all { variant -> variant.outputs.each { output -> output.processManifest.doLast { ... def manifestFile = output.processManifest.manifestOutputFile; //這里被廢棄導致報錯 def apkFileName = "_myapp_${android.defaultConfig.versionCode}_${formatedDate}.apk"; manifestFile.write(updatedContent, 'UTF-8') ... } } }
-
改了之后還是報錯,還是這里,連續各種錯
比如
Error:(250, 1) Execution failed for task ':app:processMarketDebugManifest'. No signature of method: java.lang.String.getText() is applicable for argument types: (java.lang.String) values: [UTF-8] Possible solutions: getAt(java.lang.String), getAt(groovy.lang.IntRange), getAt(groovy.lang.Range), getAt(int), getAt(java.util.Collection), getAt(groovy.lang.EmptyRange)
比如
Error:(251, 1) Execution failed for task ':app:processMarketDebugManifest'. No signature of method: java.lang.String.write() is applicable for argument types: (java.lang.String, java.lang.String) values: [H:\GitWorkSpace\MyClient\app\build\intermediates\manifests\full\market\debug/AndroidManifest.xml, ...] Possible solutions: wait(), trim(), size(), size(), toSet(), wait(long)
比如
Error:(258, 1) Execution failed for task ':app:processMarketDebugManifest'. Cannot set the value of read-only property 'outputFile' for ApkVariantOutputImpl_Decorated{apkData=Main{type=MAIN, fullName=marketDebug, filters=[]}} of type com.android.build.gradle.internal.api.ApkVariantOutputImpl.
反正就是各種各樣的groovy語法報錯,然而并不懂groovy語法,現學現賣改一改
我們工程里是既有動態修改manifest文件的需求,也有自定義apk名字的功能,
包括自動修改apk名稱的代碼也有報錯,也要改,最終改成了這樣android.applicationVariants.all { variant -> variant.outputs.each { output -> output.processManifest.doLast { def umengKey = "11111111" //取得manifest路徑 String manifestPath = "$manifestOutputDirectory/AndroidManifest.xml" //取得manifest的文本內容 def manifestContent = file(manifestPath).getText('UTF-8') //替換UMENG_APPKEY的文本 manifestContent = manifestContent.replaceAll("\\{\\{UMENG_APPKEY\\}\\}", umengKey) //重新把內容寫進.xml文件里 file(manifestPath).write(manifestContent, 'UTF-8') } } variant.outputs.all { //定義apk名字 def formatedDate = new Date().format("yyyyMMddHHmm") def apkFileName = "_myapp_${android.defaultConfig.versionCode}_${formatedDate}.apk"; outputFileName = apkFileName } }
至此再次同步gradle,總算是沒有再報錯了,AS上可以正常運行代碼了。
我們的全部修改都只涉及到gradle的配置代碼,所以不會對項目里的業務邏輯產生任何影響。
這時候再打個包,驗證下我們的最后一段打包相關的gradle腳本是否正常運行.打包成功了,也就全部OK了。
參考文獻
谷歌爸爸的文檔:
https://developer.android.google.cn/studio/build/gradle-plugin-3-0-0-migration.html
最后
附一張圖