频道栏目
首页 > 资讯 > Android > 正文

Android - Understanding and dominating gradle dependencies

18-06-20        来源:[db:作者]  
收藏   我要投稿

Android - Understanding and dominating gradle dependencies

From

https://www.devsbedevin.com/android-understanding-gradle-dependencies-and-resolving-conflicts/

My latest post discussed gradle'sdependencyInsighttask. let's dive deeper into dependencies, direct and transitive, and gradle's dependency tools.

Direct VS. Transitive

Transitive dependency is an implied dependency, allowing your project to depend on libraries that depend on other libraries. The result is a dependency tree. These trees tend to get complex as your project requires more and more libraries to compile.
A direct, or "first level" dependency is one that you the developer explicitly import.

Exploring the dependency tree

We'll get back to transitive dependencies in a second. For now let's look at a project's entire dependency tree.
Invokinggradle dependencies --configuration compileresults in something like this:

Already we can learn that this project has a lot of dependency conflicts. Those are marked by
{library name}:{required version} -> {actual version}

Conflicts

It is very common for for different modules and libraries to share the same dependencies. Who doesn't useapache-commonsandGSon Huh folks Am I right This guy knows what I'm talking about.

A problem arises when the dependency is the same, but each module or library expects a different version. This causes the project to contain multiple versions of the same class, and in turn causes the Dex tool to fail with the following error:

com.android.build.api.transform.TransformException: java.util.zip.ZipException: duplicate entry:

Resolving conflicts

If we didn't have gradle's transient dependency management, we would have to manually keep track of each dependency and resolve version conflicts by hand. This becomes harder the larger your project is. Lucky us we have gradle to handle the headache in one of several ways:

  1. The default behaviour is to settle on the newest version of the requested dependency. Please mind the wordnewestas opposed tohighest version requested. This is fine as long as the versions are backward compatible with the lowest version your project expects.
  2. Second most popular resolution is to fail the build. You, the developer, would have to resolve the conflicts yourself.
  3. Configuring a first level dependency as forced is useful in cases where the conflicted transient dependency is already a direct (=first level) dependency.
  4. You may also configure a transient dependency as forced, thus forcing your entire project to settle on a specific version.
  5. If your build contains custom forks of the conflicted dependency, you may force gradle to use your own modules.
  6. You may tell gradle to not resolve transient dependencies of a specific library at all. Of course you would need to rely instead on manually added direct dependencies and/or existing transient ones.
  7. You may as well exclude specific transient dependencies referenced by a direct one.

    Configuring build.gradle

    The aforementioned strategies do not always translate directly to configuration switches.
    Let's go over the basic techniques in achieving what we want:

    Controlling dependencies project wide

    This is achieved via theresolutionStrategyartifact.

    Failing on version conflict

    Add the following to your main project'sbuild.gradlefile.

    configurations.all {
      resolutionStrategy {
     failOnVersionConflict()
      }
    }
    
    Forcing a specific dependency

    The following example forcesasm-all 3.3.1,commomns-io 1.4, and latestboltswhere the major version number is 1 (i.e. bolts 1.x):

    configurations.all {
      resolutionStrategy {
     force 'asm:asm-all:3.3.1', 'commons-io:commons-io:1.4', 'com.parse.bolts:bolts-android:1.+'
      }
    }
    
    Preferring own modules

    Always prefer own modules:

    configurations.all {
      resolutionStrategy {
     preferProjectModules()
      }
    }
    

    Replace all instances ofcommons-iowith a custom modulemy-commons-io:

    configurations.all {
      resolutionStrategy {
     dependencySubstitution {
    substitute module('commons-io:commons-io:2.4') with project(':my-commons-io')
     }
      }
    }
    
    Controlling specific dependencies

    You may also fine grain your settings to a specific dependency on a specific project.

    Excluding transient dependencies

    Adding this to your dependencies tag would add the libraryappcompat-v7but none of its own transient dependencies. You will have to make sure that all of the libraries needed dependencies are added either by adding direct dependencies yourself or by relying on transient dependencies referenced by other modules:

    dependencies {
     compile('com.android.support:appcompat-v7:23.1.0') {
      transitive = false
     }
    }
    

    The default fortransitiveistrue.

    You can also exclude specific transient dependencies. The following example excludes theboltslibrary from being added, if needed byappcompat:

    dependencies {
     compile('com.android.support:appcompat-v7:23.1.0') {
      exclude group: 'com.parse.bolts'
     }
    }
    
    Forcing a specific version

    This forces your project to settle onboltsversion 1.1:

    dependencies {
     compile('com.parse.bolts:bolts-android:1.+') {
      force = true
     }
    }
    

    TL;DR

    Controlling dependencies project wide

    Example taken from gradle'sofficial docs:

    configurations.all {
      resolutionStrategy {
     // fail eagerly on version conflict (includes transitive dependencies)
     // e.g. multiple different versions of the same dependency (group and name are equal)
     failOnVersionConflict()
    
     // prefer modules that are part of this build (multi-project or composite build) over external modules
     preferProjectModules()
    
     // force certain versions of dependencies (including transitive)
     //  *append new forced modules:
     force 'asm:asm-all:3.3.1', 'commons-io:commons-io:1.4'
     //  *replace existing forced modules with new ones:
     forcedModules = ['asm:asm-all:3.3.1']
    
     // add dependency substitution rules
     dependencySubstitution {
    substitute module('org.gradle:api') with project(':api')
    substitute project(':util') with module('org.gradle:util:3.0')
     }
    
     // cache dynamic versions for 10 minutes
     cacheDynamicVersionsFor 10*60, 'seconds'
     // don't cache changing modules at all
     cacheChangingModulesFor 0, 'seconds'
      }
    }
    
    Controlling specific dependencies
    dependencies {
    
     // We load commons-io but none of its transient dependencies
     compile('commons-io:commons-io:2.4') {
      transitive = false
     }
    
     // We exclude bolts altogether from appcompat's transient dependencies
     compile('com.android.support:appcompat-v7:23.1.0') {
      exclude group: 'com.parse.bolts'
     }
    
     // Force a specific version
     compile('com.parse.bolts:bolts-android:1.+') {
      force = true
     }
    }
    
    Exploring dependencies

    To review all of your project's dependencies:
    gradle dependencies --configuration CONFIGURATION_NAME

    To inspect a specific dependency (more on this inthis post):
    gradle -q dependencyInsight --configuration CONFIGURATION_NAME --dependency DEPENDENCY_NAME

相关TAG标签
上一篇:Android Studio 通过Shadow+proxifier快速下载gradle
下一篇:昨天,A站受黑客攻击千万条用户数据外泄,量子加密能救得了吗?
相关文章
图文推荐

关于我们 | 联系我们 | 广告服务 | 投资合作 | 版权申明 | 在线帮助 | 网站地图 | 作品发布 | Vip技术培训 | 举报中心

版权所有: 红黑联盟--致力于做实用的IT技术学习网站