luckybilly / CC

业界首个支持渐进式组件化改造的Android组件化开源框架,支持跨进程调用。Componentize your android project gradually.
https://luckybilly.github.io/CC-website/
Apache License 2.0
4.05k stars 635 forks source link

升级gson到2.8.6后编译报错 #161

Closed luckybilly closed 4 years ago

luckybilly commented 4 years ago

如题

luckybilly commented 4 years ago

先给出解决办法


  1. 当前gradle插件版本不低于(classpath 'com.android.tools.build:gradle:3.2.0'
    • 可通过使用cc-register最新版本来解决(1.1.2版解决了这个问题)
  2. 如果当前gradle插件版本低于3.2.0
    • 要么升级gradle插件到3.2.0或更高版本,并使用cc-register的最新版
    • 要么将gson版本降到2.8.6以下

下面是分析过程


编译报错日志如下:

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':demo:transformClassesWithCc-registerForDebug'.
> java.lang.IllegalArgumentException (no error message)

* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.

按照提示使用--stacktrace参数后详细日志中可以看到关键信息:

Caused by: java.lang.IllegalArgumentException
        at org.objectweb.asm.ClassReader.<init>(Unknown Source)
        at org.objectweb.asm.ClassReader.<init>(Unknown Source)
        at org.objectweb.asm.ClassReader.<init>(Unknown Source)

通过查看源码可知:这个问题的原因是由于ASM5不支持大于1.8的jdk所编译的class导致的

    public ClassReader(final byte[] b, final int off, final int len) {
        this.b = b;
        // checks the class version
        if (readShort(off + 6) > Opcodes.V1_8) {
            throw new IllegalArgumentException();
        }
        //其它代码...
    }

在ASM6.0中ClassReader构造方法的版本判断逻辑如下(可支持JDK9):

    public ClassReader(final byte[] b, final int off, final int len) {
        this.b = b;
        // checks the class version
        if (readShort(off + 6) > Opcodes.V9) {
            throw new IllegalArgumentException();
        }
        //其它代码...
    }

通过查看ASM各版本源码得知,ASM版本所支持的JDK版本对应关系如下表:

ASM版本号 最高支持的JDK版本
超过就报错
5.0 8
5.1 8
5.2 8
6.0 9
6.1 10
6.2 11
6.2.1 12
7.0 12
7.1 13
7.2 14

而ASM的版本又是根据gradle插件的版本而定的: image

通过一步步排查确定,android gradle插件3.2.0版本才将ASM升级到6.0

目前的最新版3.5.3对应的ASM版本也是6.0,所以不能支持JDK10及以上的版本

ASM源码中,将当前支持的API版本信息记录到了Opcodes接口类中:

public interface Opcodes {

    // ASM API versions

    int ASM4 = 4 << 16 | 0 << 8 | 0;
    int ASM5 = 5 << 16 | 0 << 8 | 0;
    int ASM6 = 6 << 16 | 0 << 8 | 0;

    //.......
}

ASM官网上看到,目前最新的ASM版本是7.2,在cc-register 1.1.2版中通过这种方式暂时兼容到ASM10以下:

private static int ASM_LEVEL = 0
static int getAsmApiLevel() {
    if (ASM_LEVEL > 0) return ASM_LEVEL
    int api = Opcodes.ASM5
    for (i in (10..5)) {
        try {
            def field = Opcodes.class.getDeclaredField("ASM" + i)
            if (field != null) {
                api = field.get(null)
                break
            }
        } catch (Throwable ignored) {
        }
    }
    ASM_LEVEL = api
    return ASM_LEVEL
}
Ccixyj commented 4 years ago

终于解决了。之前遇到了这个问题,原来是gson导致的。