记一次Gradle依赖相关问题

2022-12-05 14:14:29 浏览数 (2)

‍最近对之前项目里面依赖的Flutter模块进行了一次升级。因为从1.x升级的时候3.0的flutter需要安卓原生适配compilesdkversion,所以我们APP使用的Flutter版本为2.8.1,现在app的构建版本升上来了,于是对之前的Flutter进行了升级。

Flutter开发的页面从2.8升级到3.3.8倒没有遇到什么问题。但是最后把Flutter模块打包成 aar 以及依赖到安卓工程里面的时候遇到了问题。

问题描述

flutter升级到 v3.3.8 之后,使用 flutter build aar--no-profile--no-debug打出来的aar结构如下图:

代码语言:javascript复制
├── flutter
│   ├── 1.34.1.6-bae-SNAPSHOT
│   │   ├── flutter-1.34.1.6-bae-20221125.160600-1-debug.aar
│   │   ├── flutter-1.34.1.6-bae-20221125.160600-1-profile.aar
│   │   ├── flutter-1.34.1.6-bae-20221125.160600-1-release.aar
│   │   ├── maven-metadata.xml
│   │   ├── flutter-1.34.1.6-bae-20221125.160600-1.module
│   ├── maven-metadata.xml
│   ├── maven-metadata.xml.md5
│   ├── maven-metadata.xml.sha1
├── flutter_debug
│   ├── 1.34.1.6-bae-SNAPSHOT
├── flutter_profile
│   ├── 1.34.1.6-bae-SNAPSHOT
└── flutter_release
    ├── 1.34.1.6-bae-SNAPSHOT

并且命令行里面会提示:

代码语言:javascript复制
dependencies {
  releaseImplementation 'com.netease.bae.flutter.baeflutter:flutter:1.34.1.6-bae-SNAPSHOT:release'
}

这里和 2.x 相比,打包产物其实有了变化。之前用 2.x 打包的时候,生成的 flutter module 产物只有 flutter_release 文件夹下面的内容。

并且命令行里面的提示也只是:

代码语言:javascript复制
releaseImplementation 'com.netease.bae.flutter.baeflutter:flutter_release:1.34.1.6-bae-SNAPSHOT'

这里我们把依赖替换成 3.3.8 提示的内容,暂时忽略这里的 :release

当我们依赖好aar后,编译正式版本的时候会出现编译错误:

代码语言:javascript复制
Could not determine the dependencies of task ':app:compileAReleaseTestRenderscript'.
> Could not resolve all task dependencies for configuration ':app:AReleaseTestCompileClasspath'.
   > Could not resolve com.netease.bae.flutter.baeflutter:flutter:xxxx.
     Required by:
         project :app > project :appservice
      > No matching variant of com.netease.bae.flutter.baeflutter:flutter:xxxx:20221122.043716-1 was found. The consumer was configured to find an API of a component, as well as attribute 'com.android.build.api.attributes.BuildTypeAttr' with value 'releaseTest', attribute 'product' with value 'A', attribute 'org.jetbrains.kotlin.platform.type' with value 'androidJvm' but:
          - Variant 'debugVariantAllApiPublication' capability com.netease.bae.flutter.baeflutter:flutter:xxxx declares an API of a component:
              - Incompatible because this component declares a component, as well as attribute 'com.android.build.api.attributes.BuildTypeAttr' with value 'debug' and the consumer needed a component, as well as attribute 'com.android.build.api.attributes.BuildTypeAttr' with value 'releaseTest'
              - Other compatible attributes:
                  - Doesn't say anything about org.jetbrains.kotlin.platform.type (required 'androidJvm')
                  - Doesn't say anything about product (required 'A')
          - Variant 'debugVariantAllRuntimePublication' capability com.netease.bae.flutter.baeflutter:flutter:xxxx declares a runtime of a component:
              - Incompatible because this component declares a component, as well as attribute 'com.android.build.api.attributes.BuildTypeAttr' with value 'debug' and the consumer needed a component, as well as attribute 'com.android.build.api.attributes.BuildTypeAttr' with value 'releaseTest'
              - Other compatible attributes:
                  - Doesn't say anything about org.jetbrains.kotlin.platform.type (required 'androidJvm')
                  - Doesn't say anything about product (required 'A')
          - Variant 'profileVariantAllApiPublication' capability com.netease.bae.flutter.baeflutter:flutter:xxxx declares an API of a component:
              - Incompatible because this component declares a component, as well as attribute 'com.android.build.api.attributes.BuildTypeAttr' with value 'profile' and the consumer needed a component, as well as attribute 'com.android.build.api.attributes.BuildTypeAttr' with value 'releaseTest'
              - Other compatible attributes:
                  - Doesn't say anything about org.jetbrains.kotlin.platform.type (required 'androidJvm')
                  - Doesn't say anything about product (required 'A')
          - Variant 'profileVariantAllRuntimePublication' capability com.netease.bae.flutter.baeflutter:flutter:xxxx declares a runtime of a component:
              - Incompatible because this component declares a component, as well as attribute 'com.android.build.api.attributes.BuildTypeAttr' with value 'profile' and the consumer needed a component, as well as attribute 'com.android.build.api.attributes.BuildTypeAttr' with value 'releaseTest'
              - Other compatible attributes:
                  - Doesn't say anything about org.jetbrains.kotlin.platform.type (required 'androidJvm')
                  - Doesn't say anything about product (required 'A')
          - Variant 'releaseVariantAllApiPublication' capability com.netease.bae.flutter.baeflutter:flutter:xxxx declares an API of a component:
              - Incompatible because this component declares a component, as well as attribute 'com.android.build.api.attributes.BuildTypeAttr' with value 'release' and the consumer needed a component, as well as attribute 'com.android.build.api.attributes.BuildTypeAttr' with value 'releaseTest'
              - Other compatible attributes:
                  - Doesn't say anything about org.jetbrains.kotlin.platform.type (required 'androidJvm')
                  - Doesn't say anything about product (required 'A')
          - Variant 'releaseVariantAllRuntimePublication' capability com.netease.bae.flutter.baeflutter:flutter:xxxx declares a runtime of a component:
              - Incompatible because this component declares a component, as well as attribute 'com.android.build.api.attributes.BuildTypeAttr' with value 'release' and the consumer needed a component, as well as attribute 'com.android.build.api.attributes.BuildTypeAttr' with value 'releaseTest'
              - Other compatible attributes:
                  - Doesn't say anything about org.jetbrains.kotlin.platform.type (required 'androidJvm')
                  - Doesn't say anything about product (required 'A')
   > Could not resolve com.netease.cloudmusic.look.flutterhybrid:flutterhybrid:xxxx.

这里看起来是 variant 发生了冲突。第一反应对这个报错是比较奇怪的,因为不理解为什么一个aar被依赖的时候,还会存在 variant

但是经过对比,2.8.1 和 3.3.8 打包产物比起来,3.3.8 多出了一个 .module 文件,这个文件的内容是 json 格式的,其中包括了variants 的定义,

为了方便阅读,我只留了name和一些关键的key,内容如下:

代码语言:javascript复制
"variants": [
  {
    "name":"debugVariantAllApiPublication",
    "attributes":{},
    "dependencies":[
      {
        "group":"io.flutter",
        "module":"flutter_embedding_debug",
        "version":{
          "requires":"1.0.0-857bd6b74c5eb56151bfafe91e7fa6a82b6fee25"
        }
      }
    ],
    "files": [
      {
        "name":"",
        "url":"",
        "size":36580,
        "sha512":"",
        "sha256":"",
        "sha1":"",
        "md5":""
      }
    ]
  },
  {
    "name":"releaseVariantAllApiPublication",
    "attributes":{},
    "dependencies":[],
    "files": []
  }
  //....
]

这个文件里面定义了 debugVariantAllApiPublicationprofileVariantAllApiPublicationreleaseVariantAllApiPublication 三个 variant,

里面分别定义了自己依赖的其他 aar 以及当前文件的名称、url、大小和签名。

到这里我们大概能明白依赖的时候 :release 的含义了,它会帮我们选择需要的 aar 文件。而上面的编译错误,就是因为我们的 APP 里面定义了 buildType 为 releaseTest ,所以导致编译失败。

警告不断努力的 Google 和 文档翻阅,找到了 2 个解决方案。

添加 matchingFallbacks

在 gradle 的配置里,我们可以通过 matchingFallbacks 来处理应用包含依赖项不包含的 build 类型。

在我们应用的 build.gradle 里面都需要在 releaseTest 下面添加:

代码语言:javascript复制
releaseTest {
  matchingFallbacks = ['debug', 'release']
}

经过实践,我们需要把所有的业务 module 的 build.gradle 都添加上这个配置,否则就会不生效,这个对一个业务 module 比较多的 APP 来说还是比较麻烦的。

自定义 ComponentMetadataRule

通过阅读 gradle 文档,可以发现一种解决方案:https://docs.gradle.org/current/userguide/component_metadata_rules.html

我们可以定义我们自己的 ComponentMetadataRule 修改元数据。给对应的依赖项添加我们自己的 variant。

代码语言:javascript复制
@CacheableRule
class FlutterRule implements ComponentMetadataRule {
  @Override
  void execute(ComponentMetadataContext componentMetadataContext) {
    componentMetadataContext.details.addVariant("releaseTestVariantAllApiPublication", "debugVariantAllRuntimePublication") {
            attributes {
                def ret = it.keySet().find {
                    it.name == "com.android.build.api.attributes.BuildTypeAttr"
                }
                if (ret != null) {
                    attribute(ret, "releaseTest")
                }
            }
        }
  }
}

代码如上图所示,通过 ComponentMetadataContext#addVariant ,我们可以以现有的 variant 为基础,定义并添加一个新的 variant。

这里我们根据 debugVariantAllRuntimePublication 创建了 releaseTestVariantAllApiPublication,并且把 BuildTypeAttr 属性设置为当前的 buildType。

接下来就是让这个规则全局对 Flutter 相关的依赖生效,我们可以使用 dependencyResolutionManagementsetting.gradle 里面定义。

代码语言:javascript复制
dependencyResolutionManagement {
    rulesMode.set(RulesMode.PREFER_SETTINGS)
    components {
        withModule("com.netease.bae.flutter.baeflutter:flutter", FlutterRule)
    }
}

withModule 里面添加依赖项的 group:module 即可。因为项目内的 gradle 设置默认情况下覆盖这里的设置,使用需要添加 RulesMode.PREFER_SETTINGS ,否则不会生效。

需要注意的是,网上很多文档说 dependencyResolutionManagement 是 AGP7 开始的 api, 其实这里是有点误解的。Gralde api 文档里面这个方法标记的是 since 6.8,所以即使你使用的 AGP 版本是4.x,也只是需要修改 gradle-wrapper.properties 里面的 gradle 版本即可:

代码语言:javascript复制
distributionUrl=https://services.gradle.org/distributions/gradle-6.8-all.zip

通过自定义 ComponentMetadataRule,此问题可以完美解

0 人点赞