看到标题时大家可能第一反应是“混淆问题”,可Proguard表示这个锅我不背
问题背景
最近在开发一个音视频项目,打包编译Release包后出现了一个必现的BUG,错误堆栈如下:
java.lang.AbstractMethodError: abstract method "void org.webrtc.PeerConnection$Observer.onTrack(org.webrtc.RtpTransceiver)" E/rtc: Fatal error in: gen/sdk/android/generated_base_jni/jni/../../../../../../../third_party/webrtc/sdk/android/src/jni/jni_generator_helper.h, line 38 A/libc: Fatal signal 6 (SIGABRT), code -6 in tid 16744 (signaling_threa)
点进去源码一看,就是一个平平无奇的接口方法... 反复确认debug包没问题,百番尝试后无疾而终,最后在StackOverFlow上找到一个方法测试后竟然没有出现了!
在gradle.properties中添加 “android.enableDexingArtifactTransform.desugaring=false”
问题背后
问题是解决了但还不是真解决,这句话是什么意思?问题的本质是什么?想要彻底的弄明白这个问题的前因后果得从下面两方面开始说起:
APK的编译流程
老生常谈话题,我直接贴一张图再画个重点:
APK包里是没有.class文件的,所有的.class文件都会经过Dex Compiler转换为*.dex文件
Java与Android的关系
- Android 在4.4版本中支持了Java 7。
- 然后从Android 4.4版本开始算起,一直到Android N(7.0)共4个Android版本,才在Jack/Jill工具链勉强支持了Java 8。但由于Jack/Jill工具链在构建流程中舍弃了原有Java字节码的体系,导致大量既有的技术沉淀无法应用,致使许多App工程放弃了接入。
- 最后直到Android P(9.0)版本, Google 才在Android Studio 3.x中通过新增的D8 dex编译器正式支持了Java 8,但部分API并不能全版本支持。 Android支持Java的情况,如何做到支持Java的高级特性?这里做一个扩展(需要从字节码指令解释),大家可以去看相关文章,这里我们需要知道Android不能直接支持,只能间接支持。此外助于大家理解,这里我也贴一张图再划个重点
.class->.dex中间有一个desugar流程,这就是Android支持Java的部分高级特性的秘密所在
问题总结
最后我在Google的issuetracker找到解释: issuetracker.google.com/issues/1405…
As a workaround you can add "android.enableDexingArtifactTransform.desugaring=false" to gradle.properties. In Android Gradle Plugin 3.5 we started dexing and desugaring using Gradle artifact transforms. This allows us to use Gradle caching and parallelism. The way we set up desugaring classpath is by using dependencies information from the POM file. In this case, "video-android-4.2.0" packages libwebrtc.jar inside the AAR and we fail to add those files to desugaring classpath. D8 is unable to resolve types and to rewrite invocation to the generated companion class.
简单翻译一下:aar里的jar包他没没有加入到"脱糖"路径,导致没有进行脱糖,以至于Dalvik/ART不认识他。综上问题才算真正解决。