美文网首页
Flutter 引用AAR包导致的NoSuchMethodErr

Flutter 引用AAR包导致的NoSuchMethodErr

作者: 拿拿guardian | 来源:发表于2021-01-20 19:16 被阅读0次

    背景

    Flutter-Android混合开发,远程引用了jcenter上的第三方aar包。这个第三方aar包内部又依赖了jar包,jar包里有个接口类EglBase,里面有个静态方法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));
        }
    }
    

    运行的时候,提示:

    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工程里,使用远程依赖该第三方aar/本地依赖都运行正常;
    2.将该aar包从jcenter上下载后,放在flutter-android工程的libs目录下,gradle本地依赖使用,运行正常。

    分析

    对比运行正常(本地依赖aar)和运行崩溃(jcenter远程依赖)的apk解压后的EglBase.class文件:

    运行正常.png
    运行crash.png

    可以发现,运行异常的EglBase.class文件里多了报错的静态方法(为什么反而是多了这两个静态方法?没搞明白)。
    说明Flutter-Android工程在远程依赖第三方库和本地直接依赖第三方库两种情况下打包apk的方式是有区别的。
    在一篇文章里 https://github.com/xamarin/xamarin-android/issues/4574 ,有提到类似错误的原因:
    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 脱糖处理会把原本在EglBase里的静态方法挪到EglBase$-CC这个class文件,导致在EglBase里找不到原本属于他的方法。不过这貌似也解释不通?这块知识比较匮乏,目前我也只能探索到这一步了。

    解决方案

    在 gradle.properties 中添加

    android.enableDexingArtifactTransform.desugaring=false
    

    这个解决方案,我前前后后断断续续找了两星期,百度google无果,最后是在Bing上搜索到的。
    造成上述bug的原因,应该是跟Android Studio 3.0+ 新Dex编译器D8 Desugar R8有关,后续有机会继续研究。
    https://blog.csdn.net/jamin0107/article/details/81123154

    相关文章

      网友评论

          本文标题:Flutter 引用AAR包导致的NoSuchMethodErr

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