背景
Flutter-Android混合開(kāi)發(fā),遠(yuǎn)程引用了jcenter上的第三方aar包。這個(gè)第三方aar包內(nèi)部又依賴了jar包,jar包里有個(gè)接口類EglBase,里面有個(gè)靜態(tài)方法create:
public interface EglBase {
static EglBase create(@Nullable EglBase.Context sharedContext, int[] configAttributes) {
return (EglBase)(!EglBase14.isEGL14Supported() || sharedContext != null && !(sharedContext instanceof video.pano.EglBase14.Context) ? new EglBase10((video.pano.EglBase10.Context)sharedContext, configAttributes) : new EglBase14((video.pano.EglBase14.Context)sharedContext, configAttributes));
}
}
運(yùn)行的時(shí)候,提示:
W/System.err( 6150): Caused by: java.lang.NoSuchMethodError: No static method create()Lvideo/pano/EglBase; in class Lvideo/pano/EglBase; or its super classes (declaration of 'video.pano.EglBase' appears in /data/app/xxx-c7mnoReovPKpIyPmc2_R4g==/base.apk)
另外:
1.在純android工程里,使用遠(yuǎn)程依賴該第三方aar/本地依賴都運(yùn)行正常;
2.將該aar包從jcenter上下載后,放在flutter-android工程的libs目錄下,gradle本地依賴使用,運(yùn)行正常。
分析
對(duì)比運(yùn)行正常(本地依賴aar)和運(yùn)行崩潰(jcenter遠(yuǎn)程依賴)的apk解壓后的EglBase.class文件:


可以發(fā)現(xiàn),運(yùn)行異常的EglBase.class文件里多了報(bào)錯(cuò)的靜態(tài)方法(為什么反而是多了這兩個(gè)靜態(tài)方法?沒(méi)搞明白)。
說(shuō)明Flutter-Android工程在遠(yuǎn)程依賴第三方庫(kù)和本地直接依賴第三方庫(kù)兩種情況下打包apk的方式是有區(qū)別的。
在一篇文章里 https://github.com/xamarin/xamarin-android/issues/4574 ,有提到類似錯(cuò)誤的原因:
The problem is caused by "desugaring", which "moves things around." In particular, if you run dexdump classes.dex on the classes.dex contained within the .apk, the only create method with a "type" of ()Lorg/webrtc/EglBase; is declared in Lorg/webrtc/EglBase$-CC;:
$ $HOME/android-toolchain/sdk/build-tools/29.0.2/dexdump classes.dex
…
Class #1481 -
Class descriptor : 'Lorg/webrtc/EglBase$-CC;'
Access flags : 0x1011 (PUBLIC FINAL SYNTHETIC)
Superclass : 'Ljava/lang/Object;'
Interfaces -
Static fields -
Instance fields -
Direct methods -
…
#1 : (in Lorg/webrtc/EglBase$-CC;)
name : 'create'
type : '()Lorg/webrtc/EglBase;'
access : 0x0009 (PUBLIC STATIC)
code -
registers : 2
ins : 0
outs : 2
insns size : 8 16-bit code units
catches : (none)
positions :
0x0000 line=170
locals :
EglBase$-CC is not a class present within the original classes.jar. Equally important, our code is looking for the create method on org/webrtc/EglBase, not org/webrtc/EglBase$-CC;, and while org/webrtc/EglBase exists in classes.dex, it does not contain the static create method.
This is why the Java.Lang.NoSuchMethodError is thrown.
Disabling desugar allow the app to run, but requires -- as you note in step (2) -- that the Minimum Android version to API Level be 24 or higher. 26 in this case, actually, to avoid a different build error:
D8 : error : Invoke-customs are only supported starting with Android O (--min-api 26)
I'm not entirely sure how to address this on our end. We could skip binding static interface methods/etc. unless building against Mono.Android.dll v7.0, which would avoid the NoSuchMethodException… by removing the method entirely. (This isn't a "fix.") I'm also not sure it would actually work, because all Mono.Android.dlls have an assembly version of 0.0.0.0, so we'd have to "somehow" ensure that the v7.0 bit makes it into the NuGet package? (I don't understand how that process works.)
The only other fix I can think of is to IL-rewrite the binding assembly to replace appropriate instances of Lorg/webrtc/EglBase; with Lorg/webrtc/EglBase$-CC;, which could be done but could be "brittle".
這里就不再翻譯了,大意是desuagaring 脫糖處理會(huì)把原本在EglBase里的靜態(tài)方法挪到EglBase$-CC這個(gè)class文件,導(dǎo)致在EglBase里找不到原本屬于他的方法。不過(guò)這貌似也解釋不通?這塊知識(shí)比較匱乏,目前我也只能探索到這一步了。
解決方案
在 gradle.properties 中添加
android.enableDexingArtifactTransform.desugaring=false
這個(gè)解決方案,我前前后后斷斷續(xù)續(xù)找了兩星期,百度google無(wú)果,最后是在Bing上搜索到的。
造成上述bug的原因,應(yīng)該是跟Android Studio 3.0+ 新Dex編譯器D8 Desugar R8有關(guān),后續(xù)有機(jī)會(huì)繼續(xù)研究。
https://blog.csdn.net/jamin0107/article/details/81123154