遷移到Android Studio 3.0

首先推薦按照官方版進行,如有疑問,評論中討論;

官方步驟Migrate to Android Plugin for Gradle 3.0.0

https://developer.android.google.cn/studio/build/gradle-plugin-3-0-0-migration.html#known_issues

英文水平高的可直接點擊鏈接查看原文,以防翻譯出錯;

Gradle 3.0.0 的 Android 插件是一個主要的升級, 為大型多項目帶來顯著的性能改進。為了實現這些改進, 在插件行為、DSL 和 api 方面有一些突破性的變化。

對於大多數項目, 在您更新 Gradle 並應用最新版本的 Android 插件后, 您將不會遇到此頁中描述的任何一個或僅有幾個生成錯誤。如果在更新插件后遇到生成錯誤, 只需在該頁中搜索錯誤輸出或導航到相關主題, 然後按照說明解決問題。還可以查看以下視頻以了解遷移步驟的概述。

Advertisements

遷移項目后, 可以從以下性能改進中獲益:

通過細粒度任務圖更好地多項目的并行性。 具有變體意識的依賴性管理。當構建模塊的某個變體時, 該插件現在會自動將本地庫模塊依賴項的變體與您正在構建的模塊的變體相匹配。 在對依賴項進行更改時, Gradle 通過不編譯不能訪問該依賴項 API 的模塊來執行更快的生成。通過使用 Gradle 的新的依賴項配置 (實現、api、compileOnly 和 runtimeOnly), 可以限制哪些依賴項將其 api 泄漏給其他模塊。 由於每級的德興而加快了增量生成速度。每個類現在被編譯成單獨的德克斯文件, 只有被修改的類才編譯。您還應該期待改進的應用程序的構建速度, 將 minSdkVersion 設置為20或更低, 並使用舊式 multi-dex。 有關更新和更改的更完整列表, 請閱讀 Android 插件3.0.0 發行說明。

Advertisements

要了解有關當前正在處理的問題的更多信息, 請參見已知問題。

更新Gradle 版本

Android 插件3.0.0 要求 Gradle 版本4.1 或更高。如果您正在使用 Android Studio 3.0 或更高版本打開現有項目, 請按照提示自動將現有項目更新為兼容的 Gradle。

要手動更新 Gradle, 請在 Gradle 包裝中編輯 URL. 屬性為以下內容:

distributionUrl=\ https\://services.gradle.org/distributions/gradle-4.1-all.zip

應用新的插件

如果您正在使用 android 工作室3.0 或更高版本打開現有項目, 請按照提示自動將您的項目更新為最新版的 android 插件。要手動更新項目, 請包括 maven 回購, 並在項目級生成. gradle 文件中更改插件版本, 如下所示:

buildscript { repositories { ... // You need to add the following repository to download the // new plugin. google() } dependencies { classpath 'com.android.tools.build:gradle:3.0.0' }}

注意: 對於多和複合生成, 如果 Android 插件在每個版本中載入一次以上, 則可能會出現生成錯誤。要了解更多內容, 請閱讀已知問題

使用具有變體意識的依賴關係管理

Android 插件3.0.0 和更高的包括一個新的依賴機制, 自動匹配的變體時, 使用庫。這意味著應用程序的調試變體會自動消耗庫的調試變體, 等等。它也工作時, 使用的味道-一個應用程序的 freeDebug 變體將消耗一個庫的 freeDebug 變體。

為了使插件準確地匹配變體, 您需要聲明所有產品口味的風味尺寸, 並為無法直接匹配的實例提供匹配的退。

聲明變體緯度(dimention)

該插件現在要求所有的口味屬於一個命名的味道維度-即使你打算只使用一個單一的維度。否則, 您將得到以下生成錯誤:

Error:All flavors must now belong to a named flavor dimension.The flavor 'flavor_name' is not assigned to a flavor dimension.

要解決此錯誤, 您需要首先使用 flavorDimensions 屬性聲明一個或多個維度。然後, 將每個味道分配給您聲明的一個維度, 如下面的示例所示。由於插件自動匹配您的依賴項, 因此應仔細命名您的風味尺寸。這樣做使您可以更好地控制來自本地依賴項的代碼和資源與應用程序的每個版本相匹配。

// Specifies two flavor dimensions.flavorDimensions "tier", "minApi"productFlavors { free { // Assigns this product flavor to the "tier" flavor dimension. Specifying // this property is optional if you are using only one dimension. dimension "tier" ... } paid { dimension "tier" ... } minApi23 { dimension "minApi" ... } minApi18 { dimension "minApi" ... }}

解決與依賴項匹配相關的生成錯誤

請考慮您的應用程序是否配置了稱為 "暫存" 的生成類型, 但它的一個庫依賴項不。當插件嘗試構建應用程序的 "暫存" 版本時, 它將不知道要使用哪個版本的庫, 並且您會看到類似於以下內容的錯誤消息:

Error:Failed to resolve: Could not resolve project :mylibrary.Required by: project :app

該插件包括 DSL 元素, 幫助您控制 Gradle 應該如何解決應用程序和依賴項之間的直接變體匹配的情況。請參考下表, 以確定應使用哪種 DSL 屬性來解決與 variant 識別依賴項匹配相關的某些生成錯誤。

遷移本地模塊的依賴項配置

使用具有變體意識的依賴項解決方案, 您不再需要使用特定於變體的配置 (如 freeDebugImplementation) 來進行本地模塊依賴性-插件會為您處理此問題。

使用特定於變體的配置是可選的, 不會破壞您的構建。但是, 針對本地模塊依賴項的特定變體 (例如, 使用配置: "debug") 會導致以下生成錯誤:

Error:Unable to resolve dependency for ':app@debug/compileClasspath': Could not resolve project :library.Error:Unable to resolve dependency for ':app@release/compileClasspath': Could not resolve project :library.

相反, 應按如下方式配置依賴項:

dependencies { // This is the old method and no longer works for local // library modules: // debugImplementation project(path: ':library', configuration: 'debug') // releaseImplementation project(path: ':library', configuration: 'release') // Instead, simply use the following to take advantage of // variant-aware dependency resolution. You can learn more about // the 'implementation' configuration in the section about // new dependency configurations. implementation project(':library') // You can, however, keep using variant-specific configurations when // targeting external dependencies. The following line adds 'app-magic' // as a dependency to only the "debug" version of your module. debugImplementation 'com.example.android:app-magic:12.3'}

注意: 儘管手動依賴關係的 Gradle API 仍然可用, 但建議您不要使用它。提供給項目 () DSL 的配置現在需要在構建類型和口味 (以及其他屬性) 上與使用者相匹配。例如, 不可能通過這種機制使 "debug" 變體消耗 "釋放" 變體, 因為生產者和消費者的變體不匹配。(在這種情況下, 名稱 "debug" 指的是有關發布依賴項的部分中提到的已發布的配置對象。因為插件現在發布兩個配置, 一個用於編譯, 一個用於運行時, 這種選擇一個配置的舊方法不再有效。

使用新的依賴項配置

Gradle 3.4 引入了新的 Java 庫插件配置, 允許您控制是否將依賴項發布到使用該庫的項目的編譯和運行時路徑。Android 插件正在採用這些新的依賴配置, 遷移大型項目來使用它們可以大大縮短構建時間。下表幫助您了解應該使用哪些配置。

類似於以前版本的 Android 插件的依賴配置, 上述配置可用於特定口味或構建類型的依賴性。例如, 可以使用實現使依賴項可用於所有變體, 也可以使用 debugImplementation 使其僅用於模塊的調試變體。

注意: 編譯、提供和 apk 目前仍然可用。然而, 他們將被刪除在下一個主要版本的 Android 插件

發布依賴

以下配置保存了庫的可傳遞依賴性, 供其使用者使用:

  • variant_nameApiElements

  • variant_nameRuntimeElements 在以前版本的插件中, 曾經有一個單一的配置每個變種稱為: variant_name。由於庫現在可以控制其用戶在編譯時可訪問的依賴項, 因此, 使用前一節中描述的新的依賴項配置, 現在有兩種配置: 一個用於編譯使用者, 另一個用於運行時。

要了解有關不同配置之間的關係的更多信息, 請轉到 Java 庫插件配置。

遷移自定義依賴項解決策略

該插件使用以下配置來解決變數的所有依賴項:

variant_nameCompileClasspath (_variant_nameCompile 不再工作) variant_nameRuntimeClasspath (_variant_nameApk 不再工作) 如果您仍在使用舊的配置, 將會出現類似於以下內容的生成錯誤:

Error:Configuration with old name _debugCompile found.Use new name debugCompileClasspath instead.

在已解決的配置上設置解決策略的插件和生成文件需要適應新名稱。由於新的生成模型延遲了依賴項解析, 因此現在可以在使用變體 API 時設置解析度策略, 如下面的示例所示。(Android 插件現在包括了訪問變數的配置對象的 getter。

// Previously, you had to apply a custom resolution strategy during the// configuration phase, rather than in the execution phase. That's// because, by the time the variant was created and the Variant API was// called, the dependencies were already resolved.// But now these configurations DO NOT WORK with the 3.0.0 Gradle plugin:// configurations {// _debugCompile// _debugApk// }//// configurations._debugCompile.resolutionStrategy {// ...// }//// configurations.all {// resolutionStrategy {// ...// }// }// Instead, because the new build model delays dependency resolution, you// should query and modify the resolution strategy using the Variant API:android { applicationVariants.all { variant -> variant.getCompileConfiguration().resolutionStrategy { ... } variant.runtimeConfiguration.resolutionStrategy { ... } variant.getAnnotationProcessorConfiguration().resolutionStrategy { ... } }}

從測試配置中排除應用程序依賴項

在以前版本的 Android 插件中, 您可以使用 "排除" 關鍵字從測試中排除應用程序的某些可傳遞依賴性。但是, 使用新的依賴項配置, 以下不再有效:

dependencies { implementation "com.jakewharton.threetenabp:threetenabp:1.0.5" // Note: You can still use the exclude keyword to omit certain artifacts of // dependencies you add only to your test configurations. androidTestImplementation("org.threeten:threetenbp:1.3.3") { exclude group: 'com.jakewharton.threetenabp', module: 'threetenabp' } }

這是因為 androidTestImplementation 和 androidTestApi 擴展了模塊的實現和 api 配置。即, 當 Gradle 解析配置時, 它們繼承應用程序的實現和 api 依賴性。要從測試配置中排除某些應用程序依賴項, 必須在執行時使用變體 API 進行操作:

android.testVariants.all { variant -> variant.getCompileConfiguration().exclude group: 'com.jakewharton.threetenabp', module: 'threetenabp' variant.getRuntimeConfiguration().exclude group: 'com.jakewharton.threetenabp', module: 'threetenabp'}

API 更改

Android 插件3.0.0 引入 API 的改變, 刪除某些功能, 並可能打破您現有的構建。該插件的最新版本可能會引入新的公共 api 來替換損壞的功能。

在生成時修改變數輸出可能不起作用

使用變體 API 操作變體輸出是用新插件中斷的。它仍然適用於簡單的任務, 如在構建時更改 APK 名稱, 如下所示:

// If you use each() to iterate through the variant objects, // you need to start using all(). That's because each() iterates // through only the objects that already exist during configuration time— // but those object don't exist at configuration time with the new model. // However, all() adapts to the new model by picking up object as they are // added during execution. android.applicationVariants.all { variant -> variant.outputs.all { outputFileName = "${variant.name}-${variant.versionName}.apk" } }

但是, 涉及訪問文件對象的更複雜的任務不再起作用。這是因為在配置階段中不再創建特定於變體的任務。這導致插件不知道其所有的輸出前, 但它也意味著更快的配置時間。

manifestOutputFile 不再可用

processManifest () manifestOutputFile () 方法不再可用, 在調用它時會出現以下錯誤:

A problem occurred configuring project ':myapp'. Could not get unknown property 'manifestOutputFile' for task ':myapp:processDebugManifest' of type com.android.build.gradle.tasks.ProcessManifest.

您可以調用 processManifest. manifestOutputDirectory () 來返回包含所有生成的清單的目錄的路徑, 而不是調用 manifestOutputFile () 來獲取每個變數的清單文件。然後, 您可以找到一個清單, 並將您的邏輯應用於它。下面的示例動態更改清單中的版本代碼:

android.applicationVariants.all { variant -> variant.outputs.all { output -> output.processManifest.doLast { // Stores the path to the maifest. String manifestPath = "$manifestOutputDirectory/AndroidManifest.xml" // Stores the contents of the manifest. def manifestContent = file(manifestPath).getText() // Changes the version code in the stored text. manifestContent = manifestContent.replace('android:versionCode="1"', String.format('android:versionCode="%s"', generatedCode)) // Overwrites the manifest with the new text. file(manifestPath).write(manifestContent) } }}

配置 Wear 應用程序依賴性

為了支持針對 Android 應用的變型識別依賴性解決方案, 該插件現在將所有的圖表結合起來, 然後再解決它們, 類似於它如何處理其他依賴關係。在以前的版本中, 插件單獨解析 componentWearApp 依賴關係圖。因此, 例如, 您以前可以執行類似下面的操作, 而 "自由" 變體將使用: wear2 和所有其他變體將使用: wear1:

dependencies { // This is the old way of configuring Wear App dependencies. wearApp project(':wear1') freeWearApp project(':wear2')}

上面的配置不再適用於新插件。對於簡單的項目, 沒有超過一個磨損應用模塊, 如果你的應用模塊配置與你的主應用程序相同的變體, 你不再需要使用 flavorWearApp 配置。只需指定 wearApp 配置和主應用程序的每個變體都將使用 "磨損" 應用程序模塊中的匹配變體:

dependencies { // If the main and Wear app modules have the same variants, // the following configuration uses automatic dependency matching. wearApp project(':wearable')}

如果你有多個磨損應用程序模塊, 你想指定一個不同的磨損應用程序模塊的每一個應用程序的味道, 你可以繼續使用 flavorWearApp 配置如下 (但是, 你不能結合它與 wearApp 配置):

dependencies { paidWearApp project(':wear1') demoWearApp project(':wear1') freeWearApp project(':wear2')}

使用批註處理器依賴項配置

在以前版本的插件中, 編譯類路徑上的依賴項被自動添加到處理器類路徑中。即, 您可以將註釋處理器添加到編譯類路徑中, 並按預期方式工作。但是, 通過向處理器添加大量不必要的依賴關係, 這將對性能產生重大影響。

使用 Android 插件3.0.0 時, 您必須使用 annotationProcessor 依賴項配置將標註處理器添加到處理器類路徑中, 如下所示:

dependencies { ... annotationProcessor 'com.google.dagger:dagger-compiler:<version-number>'}

如果該插件的 JAR 文件包含以下文件, 則假定依賴項是註釋處理器: 元 INF/服務/javax. 處理. 處理器。如果插件在編譯類路徑上檢測到標註處理器, 則生成將失敗, 並會收到一條錯誤消息, 列出編譯類路徑上的每個標註處理程序。要修復該錯誤, 只需更改這些依賴項的配置即可使用 annotationProcessor。如果依賴項包括也需要在編譯類路徑上的組件, 請再次聲明該依賴項並使用編譯依賴項配置。

android-apt 插件用戶: 這種行為改變目前並不影響 android 的插件。然而, 該插件將不兼容未來版本的 Android 插件的 Gradle。

禁用批註處理器錯誤檢查

如果您對包含不需要的註釋處理器的編譯類路徑具有依賴性, 則可以通過將以下內容添加到生成. gradle 文件中來禁用錯誤檢查。請記住, 添加到編譯類路徑中的註釋處理器仍未添加到處理器類路徑中。

android { ... defaultConfig { ... javaCompileOptions { annotationProcessorOptions { includeCompileClasspath false } } }}

如果您遇到遷移到新的依賴項解決策略的問題, 則可以通過設置 includeCompileClasspath true 將行為恢復為 Android 插件2.3.0。但是, 建議不要將行為還原到版本 2.3.0, 這樣做的選項將在將來的更新中刪除。為了幫助我們提高與您所使用的依賴關係的兼容性, 請提交一個 bug。

使用單獨的測試模塊

不同的測試模塊現在是可識別的。這意味著不再需要指定 targetVariant。

測試模塊中的每個變體都將嘗試在目標項目中測試匹配的變體。默認情況下, 測試模塊只包含一個調試變數, 但您可以創建新的生成類型和新的口味來創建新的變體以匹配已測試的應用程序項目。為每個變體創建一個 connectedCheck 任務。

要使測試模塊只測試不同的生成類型, 而不是調試一個, 請使用 VariantFilter 在測試項目中禁用調試變體, 如下所示:

android { variantFilter { variant -> if (variant.buildType.name.equals('debug') { variant.setIgnore(true); } }}

如果希望測試模塊只針對某個應用程序的特定口味或生成類型, 則可以使用 matchingFallbacks 屬性只針對要測試的變體。這還可以防止測試模塊為自身配置這些變體。

庫中的本地 jar 現在可傳遞

以前, 庫模塊將以非標準方式處理本地 jar 的依賴關係, 並將它們打包到 AAR 中。即使在多項目的建設, AAR 的消費者將看到這些 JAR 文件通過包裝的版本。

Android 插件3.0.0 和更高的使用新的 Gradle api, 允許消費項目看到本地 jar 作為常規的可傳遞依賴性, 類似於基於 maven 坐標的依賴關係。為了適應新的 Gradle api, 插件改變了它處理本地 JAR 文件的幾個方面。

項目間發布

庫模塊不再處理本地 jar。這是為了加速由對庫模塊代碼的更改而導致的增量生成。 現在, 對庫模塊的轉換隻會影響項目範圍。使用 PROJECT_LOCAL_DEPS 應用轉換將失敗, 因為此範圍現在已被棄用。 對於其本地 jar 是外部流的一部分的 app 模塊, PROJECT_LOCAL_DEPS 和 SUB_PROJECT_LOCAL_DEPS 流現在總是空的。 為本地庫模塊啟用混淆不再影響庫的代碼。相反, 您應該在使用該庫的 app 模塊上運行混淆。 以前, 必須在庫模塊中解析庫模塊與其本地 JAR 依賴項之間的 Java 資源衝突。由於庫模塊不再處理本地 jar, 因此必須解決使用該庫的應用程序模塊中的衝突。 發布到 Maven 回購

在發布到 Maven 回購方面, 沒有任何變化。將本地 jar 捆綁在一起, 並將其類資源合併到 AAR 的主 JAR 文件中。如果模塊啟用混淆, 則所有 jar 都將合併到主 jar 文件中。 使用 AAPT2 時的行為更改 為了改進增量資源處理, Android 插件3.0.0 在默認情況下啟用 AAPT2。雖然 AAPT2 應立即處理較舊的項目, 但本節將介紹您應該注意的一些行為更改。

Android 清單中的元素層次結構

在早期版本的 AAPT 中, 嵌套在 Android 清單中不正確節點中的元素要麼被忽略, 要麼導致警告。例如, 請考慮以下示例:

<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.myname.myapplication"> <application ... <activity android:name=".MainActivity"><intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> <action android:name="android.intent.action.CUSTOM" /> </activity> </application> </manifest>

早期版本的 AAPT 只會忽略錯位的 <action> 標記。但是, 使用 AAPT2, 您會得到以下錯誤:

AndroidManifest.xml:15: error: unknown element <action> found.

要解決此問題, 請確保您的清單元素嵌套正確。有關詳細信息, 請閱讀清單文件結構。

資源申報

不能再從 name 屬性中指示資源的類型。例如, 下面的示例錯誤地聲明了一個 attr 資源項:

<style name="foo" parent="bar"> <item name="attr/my_attr">@color/pink</item></style>

以這種方式聲明資源類型會導致以下生成錯誤:

Error: style attribute 'attr/attr/my_attr (aka my.package:attr/attr/my_attr)' not found.

要解決此錯誤, 請使用 type = "attr" 顯式聲明該類型:

<style name="foo" parent="bar"> <item type="attr" name="my_attr">@color/pink</item></style>

此外, 在聲明 <style> 元素時, 其父級也必須是樣式資源類型。否則, 會出現類似以下的錯誤:

Error: (...) invalid resource type 'attr' for parent of style

ForegroundLinearLayout 的 Android 命名空間

ForegroundLinearLayout 包括三屬性: foregroundInsidePadding, android: 前景, 和 android: foregroundGravity。請注意, foregroundInsidePadding 不包括在 android 名稱空間中, 與其他兩個屬性不同。

在早期版本的 AAPT 中, 當您使用 android 命名空間定義它時, 編譯器會默默地忽略 foregroundInsidePadding 屬性。在使用 AAPT2 時, 編譯器會提前捕獲此錯誤, 並引發下面的生成出錯:

Error: (...) resource android:attr/foregroundInsidePadding is private

要解決這個問題, 只需替換 android: foregroundInsidePadding 與 foregroundInsidePadding。

Incorrect use of @ resource reference symbols

當省略或錯誤地放置資源引用符號 (@) 時, AAPT2 現在會引發生成錯誤。例如, 在指定樣式屬性時, 請考慮是否省略該符號, 如下所示:

<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar"> ... <!-- Note the missing '@' symbol when specifying the resource type. --> <item name="colorPrimary">color/colorPrimary</item></style>

生成模塊時, AAPT2 現在拋出以下生成錯誤:

ERROR: expected color but got (raw string) color/colorPrimary

此外, 請考慮在從 android 名稱空間訪問資源時是否錯誤地包含了該符號, 如下所示:

...<!-- When referencing resources from the 'android' namespace, omit the '@' symbol. --><item name="@android:windowEnterAnimation"/>

生成模塊時, AAPT2 現在拋出以下生成錯誤:

Error: style attribute '@android:attr/windowEnterAnimation' not found

已知問題

  • 在單個生成中多次載入 Android 插件會導致項目同步錯誤。當您有多個子項目時, 這可能會發生, 每個子項都包括在其 buildscript 類路徑中的 Android 插件。這是 Gradle 新的具有變體意識的依賴關係管理的一個限制, 它無法處理來自不同類的匹配屬性。要解決多生成的此問題, 請確保只將 Android 插件添加到 top-level 生成. gradle 文件的生成類路徑中, 如下所示:

// Additionally, make sure that you don't wrap this in a// subprojects block.buildscript { ... dependencies { classpath 'com.android.tools.build:gradle:3.0.0' }}

要解決複合生成問題, 您還需要確保對於主項目和使用 Android 插件的每個包含的項目, buildscript 路徑是相同的。這也需要您添加到 buildscript 塊的路徑的順序相同。例如, 請考慮主項目的生成. gradle 文件中包括的下列類路徑依賴項:

buildscript { ... dependencies { classpath "com.android.tools.build:gradle:3.0.0" classpath "me.tatarka:gradle-retrolambda:3.7.0" }}

現在, 請考慮複合生成中包含的其他項目的以下生成. gradle 文件:

buildscript { dependencies { // Note that the order of plugins differs from that // of the main project's build.gradle file. This results // in a build error because Gradle registers this as a // different classloader. classpath "me.tatarka:gradle-retrolambda:3.7.0" classpath "com.android.tools.build:gradle:3.0.0" }}

重新訪問此頁以檢查 Gradle 的新版本是否已修復此問題。

  • Firebase 插件版本1.1.0 可能導致番石榴依賴性不匹配, 導致以下錯誤:

    Error:Execution failed for task ':app:packageInstantRunResourcesDebug'.com.google.common.util.concurrent.MoreExecutors.directExecutor()Ljava/util/concurrent/Executor;

    若要繞過此生成錯誤, 請將以下內容添加到項目級生成的依賴項塊中. gradle 文件

    dependencies { classpath ('com.google.firebase:firebase-plugins:1.1.0') { exclude group: 'com.google.guava', module: 'guava-jdk5' } ...}

    有關詳細信息, 請參閱問題 [)#63180002](https://issuetracker.google.com/issues/63180002。

  • 要使用 Protobufs, 您必須將 Protobuf 插件升級到0.8.2 或更高版本。

  • 第三方安卓 apt 插件不再受支持。您應該切換到內置的 "註釋處理器" 支持, 它已得到改進, 以處理惰性地解決依賴關係。

  • JAR 簽名 (v1 方案) 不支持包含回車符 (CR) 字元的文件名。(請參見問題 #63885809)。

Advertisements

你可能會喜歡