美文网首页
查看依赖库和隐含依赖导致的问题

查看依赖库和隐含依赖导致的问题

作者: RoFF | 来源:发表于2016-09-07 17:51 被阅读1661次

    Android Studio使用gradle来管理项目,使用依赖库也很简单,在build.gradle中配置一下就可以了。但是这么方便的工具也隐含很多坑,隐含依赖问题就是其中之一。

    例如如果同一个jar包却有两个版本,导致ClassLoader加载出错,或者干脆生成dex的时候就报错,让你编译都不过。就是说这类错误可能发生在编译期,也可能发生在运行期(例如加载多个dex)。错误提示也是多种多样。

    查看依赖库的命令行工具

    $gradle <host_module_name>:dependencies 可以看到指定module的所有的间接依赖库,也就是依赖库的依赖库

    $gradle showAllCache 可以看到所在module的所有依赖库的路径

    前提是在module的build.gradle中加入showAllCache的task,如下

    task showAllCache << {
       configurations.compile.each { println it }
    }
    

    遇到版本依赖问题总是很烦,需要仔细看log,有了查看依赖的方法就能省很多时间。

    怎么定位是依赖库的问题?

    错误提示多种多样,没有统一的log。如果是没见过的错误,可以google一下,一般都会有人遇到,然后说这是依赖库的版本冲突或干脆就说是依赖库的问题,但是也就到这里为止了(可能因为错误一般都是自己项目特有的,不好写总结)。

    下边举两个例子,都是我遇到的。

    错误举例

    1 隐含依赖导致混淆出错 :app:transformClassesWithMultidexlistForDebug

    在打包过程中报错,详细的log见我在stackoverflow上的问题

    看log里有提示

    “Error:Uncaught translation error: com.android.dex.util.ExceptionWithContext: name already added: string{"a"}”
    

    这是我在注音输入法里遇到的,build.gradle中加上使用

    minifyEnabled = false
    

    打包成功;

    minifyEnabled = true
    

    打包失败。很显然跟混淆有关。

    问题是怎么定位到具体是哪个库没做混淆或者不应该混淆呢?
    build.gradle中用到的所有库我都在proguard中加了keep,为啥还有问题?

    我当时用了笨办法,一个个排除。结果花了很长时间才找到出问题的依赖库。根本原因就是com.squareup.retrofit2依赖fastxml,后者没在proguard中被keep

    后来在网上找到上边查看间接依赖的方法,试了一下,果然很好使。早知道这个方法的话我就能省很多时间了:-(

    2 隐含依赖导致版本冲突
    W/art: Incompatible structural change detected: Structural change of android.support.v4.app.FragmentActivity is hazardous (/data/user/0/<package_name>/files/dexOpt/com.tugele.expression.odex/plugin_doutu-debug.dex at compile time, /data/app/<package_name>-1/oat/arm/base.odex at runtime): Virtual method count off: 45 vs 46
    W/art: Landroid/support/v4/app/FragmentActivity; (Compile time):
    

    这个错误是在通过输入法启动图个乐插件(单独的apk包)时发生的。排除各种错误后把问题定位到android.support.v4的版本上,host和plugin使用了不同版本的support-v4版本上。

    分析过程

    第一步:验证一下错误原因是否属实。分别把host(主工程)和plugin(插件)的dex反编译成jar,然后用jd-gui查看FragmentActivity.class,发现确实不一样。

    那问题就来了,host和plugin中指定的android-support-v4.jar的版本是一样的,build.gradle中写的都是“compile 'com.android.support:support-v4:23.1.1'”,版本一样为啥看到的代码不一样呢?

    第二步:验证一下项目实际依赖的库。

    怎么验证?

    到host和plugin目录下,分别在命令行下执行 $gradle
    host的依赖输出:

    ...................
    <SDK_PATH>/extras/android/m2repository/com/android/support/support-v4/23.2.1/support-v4-23.2.1.aar
    ....................
    

    plugin的依赖输出:

    ...................
    <SDK_PATH>/extras/android/m2repository/com/android/support/support-v4/23.1.1/support-v4-23.1.1.aar
    ....................
    

    发现问题木有?
    host和plugin实际依赖的版本不一样!!!

    为什么会这样?host为什么不用指定的版本23.1.1 ?

    原因就是其它依赖库间接的依赖android-support-v4-23.2.1。那么是谁间接依赖它呢?

    要查明原因就要用这个命令:$gradle <host_module_name>:dependencies
    它能把所有库的依赖关系都展示给你。

    看我的结果:

    +--- project :zhushou_sdk
    | +--- com.android.support:recyclerview-v7:23.2.1
    | | +--- com.android.support:support-v4:23.2.1 (*)
    | | --- com.android.support:support-annotations:23.2.1
    

    看到了吗?com.android.support:recyclerview间接依赖到com.android.support:support-v4:23.2.1

    再多看一点:

    +--- project :explore_base_module
    | --- com.android.support:support-v4:23.1.1 -> 23.2.1 (*)
    

    这个module本来是依赖23.1.1的,gradle要照顾到版本兼容问题,所以就该成了23.2.1

    这就是问题的根本原因。

    相关文章

      网友评论

          本文标题:查看依赖库和隐含依赖导致的问题

          本文链接:https://www.haomeiwen.com/subject/kinjettx.html