为什么你的gradle还在can not resolve???

1,967 阅读3分钟

gradle如何下载sdk

gradle开始构建之前,会先确定需要参与构建的sdk以及他们的版本,并且下载到本地(当然也有可能使用缓存,本文不讨论这种情况),gradle的这个操作简单来说分为两个步骤:

1.确定sdk的版本号

  • 静态版本号:

    对于静态的版本号,gradle直接选择版本号最高的那个参与构建

    image-20200928180749588

  • 动态版本号,形如:com.xxx:sdk:1.1+,com.xxx:sdk:latest_version:

    对于动态版本号,gradle将会遍历我们在build.gradle文件中定义的仓库,读取仓库中对应sdk的maven-matedata.xml文件,这个文件保存了当前仓库所拥有的该sdk的所有版本记录;不同的仓库类型获取版本信息的方式可能不同。本文仅讨论maven

    build.gradle文件中定义的repositories:

    buildscript {
        repositories {
            google()
            jcenter()
        }
    }
    

    ​ 这里很容易出现问题:由于gradle在确定动态版本号的时候,需要遍历所有的远程仓库,综合确定一个实际要使用的版本号,就会导致gradle在初始配置依赖的时候,非常的消耗时间(如果你本地没有缓存或者缓存过期了又或者你添加了新的仓库),像我们公司的项目经常会配置7+仓库,而一旦某一个仓库无法访问,gradle就会停止构建,导致打包经常失败(can not resolve);因为不同的仓库保存的SDK版本号可能不一致,所以gradle不可以忽略这种错误。

2.下载sdk

  • 确定了需要参与构建的sdk以及他们的版本之后,下一步就是下载这些sdk了。

    • 按照我们在build.gradle中配置的仓库,从第一个开始,按顺序查找;
    • 如果在这个仓库中找到了所需要版本的sdk的pom文件,停止查找,开始下载,如果下载失败,则构建失败;如果当前仓库没有找到这个版本的pom文件,去下一个仓库查找;
    • 如果在所有的仓库中都没有找到对应的pom文件,构建失败

如何优化

  • 使用静态的版本号:个人不建议在项目中使用动态版本号,这就是一个炸弹,你不知道它什么时候突然升了个级,然后出现一些莫名其妙的问题。

不知道项目中哪个sdk的版本号是动态的?在项目的根目录运行下面的命令:

./gradlew app:dependencies > depts.txt

这个命令生成项目的依赖树并保存在depts.txt文件中,在依赖树中可以看到哪些sdk的版本号是动态的:

image-20200929175050521

这里动态依赖已经被固定为一个精确的版本了。如何固定版本?在app/build.gradle中配置,与android的配置同级

configurations.all { Configuration configuration ->
    configuration.resolutionStrategy { ResolutionStrategy resolutionStrategy ->
        resolutionStrategy.force "com.amap.api:location:5.1.0"
        resolutionStrategy.force "com.amap.api:map2d:6.0.0"
        resolutionStrategy.force "com.amap.api:search:7.4.0"
    }
}
  • 减少仓库配置,去掉一些无用的仓库配置,对仓库进行一个排序,把使用几率比较高,稳定的,速度高的排在前面。

额外扩展

  • ContraintLayout的maven-metadata.xml文件,当我们使用动态版本号的时候,gradle会读取这个文件
image-20200929165346087
  • ContraintLayout 2.0.1版本的pom文件,gradle下载sdk之前会先读取这个文件

    可以看到,ContraintLayout还依赖其他的sdk,这些被依赖进来的sdk版本在我们项目构建的时候也会参与sdk的版本号竞争中。如果我们想要排除掉(不依赖)这个sdk中的某个依赖项,可以在implementation的时候配置exclude。

<?xml version="1.0" encoding="UTF-8"?>
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <modelVersion>4.0.0</modelVersion>
  <groupId>androidx.constraintlayout</groupId>
  <artifactId>constraintlayout</artifactId>
  <version>2.0.1</version>
  <packaging>aar</packaging>
  <name>Android ConstraintLayout</name>
  <description>ConstraintLayout for Android</description>
  <url>http://tools.android.com</url>
  <inceptionYear>2007</inceptionYear>
  <licenses>
    <license>
      <name>The Apache Software License, Version 2.0</name>
      <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
      <distribution>repo</distribution>
    </license>
  </licenses>
  <developers>
    <developer>
      <name>The Android Open Source Project</name>
    </developer>
  </developers>
  <scm>
    <connection>git://android.googlesource.com/platform/tools/sherpa.git</connection>
    <url>https://android.googlesource.com/platform/tools/sherpa</url>
  </scm>
  <dependencies>
    <dependency>
      <groupId>androidx.appcompat</groupId>
      <artifactId>appcompat</artifactId>
      <version>1.2.0</version>
      <scope>compile</scope>
    </dependency>
    <dependency>
      <groupId>androidx.core</groupId>
      <artifactId>core</artifactId>
      <version>1.3.1</version>
      <scope>compile</scope>
    </dependency>
    <dependency>
      <groupId>androidx.constraintlayout</groupId>
      <artifactId>constraintlayout-solver</artifactId>
      <version>2.0.1</version>
      <scope>compile</scope>
    </dependency>
  </dependencies>
</project>

使用exclude排除掉constraintlayout中依赖的appcompat

implementation("androidx.constraintlayout:constraintlayout:2.0.1") {
	      exclude group: 'androidx.appcompat', module: 'appcompat'
 }

参考文档: