Android Studio 升级到3.0后的gradle迁移(bing译文)

首先推荐按照官方版进行,若有疑问,评论中讨论;html

官方步骤Migrate to Android Plugin for Gradle 3.0.0java

英文水平高的可直接点击连接查看原文,以防翻译出错;android

Gradle 3.0.0 的 Android 插件是一个主要的升级, 为大型多项目带来显著的性能改进。为了实现这些改进, 在插件行为、DSL 和 api 方面有一些突破性的变化。api

对于大多数项目, 在您更新 Gradle 并应用最新版本的 Android 插件后, 您将不会遇到此页中描述的任何一个或仅有几个生成错误。若是在更新插件后遇到生成错误, 只需在该页中搜索错误输出或导航到相关主题, 而后按照说明解决问题。还能够查看如下视频以了解迁移步骤的概述。app

迁移项目后, 能够从如下性能改进中获益:maven

经过细粒度任务图更好地多项目的并行性。 具备变体意识的依赖性管理。当构建模块的某个变体时, 该插件如今会自动将本地库模块依赖项的变体与您正在构建的模块的变体相匹配。 在对依赖项进行更改时, Gradle 经过不编译不能访问该依赖项 API 的模块来执行更快的生成。经过使用 Gradle 的新的依赖项配置 (实现、api、compileOnly 和 runtimeOnly), 能够限制哪些依赖项将其 api 泄漏给其余模块。 因为每级的德兴而加快了增量生成速度。每一个类如今被编译成单独的德克斯文件, 只有被修改的类才编译。您还应该期待改进的应用程序的构建速度, 将 minSdkVersion 设置为20或更低, 并使用旧式 multi-dex。 有关更新和更改的更完整列表, 请阅读 Android 插件3.0.0 发行说明。ide

要了解有关当前正在处理的问题的更多信息, 请参见已知问题。性能

更新Gradle 版本

Android 插件3.0.0 要求 Gradle 版本4.1 或更高。若是您正在使用 Android Studio 3.0 或更高版本打开现有项目, 请按照提示自动将现有项目更新为兼容的 Gradle。测试

要手动更新 Gradle, 请在 Gradle 包装中编辑 URL. 属性为如下内容:gradle

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)。
相关文章
相关标签/搜索