美文网首页
Flutter MethodChannel 源码解析

Flutter MethodChannel 源码解析

作者: Lupy_ | 来源:发表于2020-04-16 23:01 被阅读0次

MethodChannel实现原理

从android端分析MethodChannel的实现原理,入口选在使用MethodChannel的使用的地方是最合适的。

首先看一下如果使用

//1、注册通道
    MethodChannel channel = new MethodChannel(getFlutterView(),"flutter/channel");

//2、设置回调,被call回调
    channel.setMethodCallHandler(new MethodChannel.MethodCallHandler() {
      @Override
      public void onMethodCall(MethodCall call, MethodChannel.Result result) {

      }
    });
    
//3、主动call flutter的方法
    channel.invokeMethod("callFlutter", "params", new MethodChannel.Result() {
      @Override
      public void success(Object result) {
        //呼叫成功
      }

      @Override
      public void error(String errorCode, String errorMessage, Object errorDetails) {
        //呼叫出现异常
      }

      @Override
      public void notImplemented() {
        //flutter没有对应的实现方法
      }
    });

Android原生端和flutter端实现通讯完全靠上面的方法。

看一下MethodChannel的构造函数

    public MethodChannel(BinaryMessenger messenger, String name) {
        this(messenger, name, StandardMethodCodec.INSTANCE);
    }

入参是一个通讯BinaryMessenger , 这是一个接口,我们使用的时候通常是传入一个FlutterView,因为FlutterView实现了这个接口。

先看一下消息发送的过程:

    public void invokeMethod(String method, @Nullable Object arguments, Result callback) {
        messenger.send(name, codec.encodeMethodCall(new MethodCall(method, arguments)),
            callback == null ? null : new IncomingResultHandler(callback));
    }

最终是使用构造函数传入的BinaryMessenger实现类来发送消息,发送的信息有三个,

  1. 通道的名字
  2. 方法名字加上参数经过编码转化为一个bytebuff
  3. 方法回调 IncomingResultHandler()后面会讲这个方法回调;

然后看一下FlutterView的发送方法。

  public void send(String channel, ByteBuffer message, BinaryReply callback) {
        if (!isAttached()) {
            Log.d(TAG, "FlutterView.send called on a detached view, channel=" + channel);
            return;
        }
        mNativeView.send(channel, message, callback);
    }

他是调用了变量mNativeView的发送方法,mNativeView是一个FlutterNativeView,继续跟进

 public void send(String channel, ByteBuffer message, BinaryReply callback) {
        if (!isAttached()) {
            Log.d(TAG, "FlutterView.send called on a detached view, channel=" + channel);
            return;
        }

        dartExecutor.getBinaryMessenger().send(channel, message, callback);
    }

他从dartExecutor中获取到一个BinaryMessager,然后调用了他的发送方法。要看一下获取到的到底是一个什么东西

//DartExecutor.java
//摘取了关键信息
 @NonNull
  private final BinaryMessenger binaryMessenger;
  
  
  public DartExecutor(@NonNull FlutterJNI flutterJNI, @NonNull AssetManager assetManager) {
    this.flutterJNI = flutterJNI;
    this.assetManager = assetManager;
    this.dartMessenger = new DartMessenger(flutterJNI);
    dartMessenger.setMessageHandler("flutter/isolate", isolateChannelMessageHandler);
    this.binaryMessenger = new DefaultBinaryMessenger(dartMessenger);
  }
  
public BinaryMessenger getBinaryMessenger() {
    return binaryMessenger;
  }

很明显是调用了DefaultBinaryMessenger的发送方法,看一下DefaultBinaryMessenger

private static class DefaultBinaryMessenger implements BinaryMessenger {
    private final DartMessenger messenger;

    private DefaultBinaryMessenger(@NonNull DartMessenger messenger) {
      this.messenger = messenger;
    }

    public void send(@NonNull String channel, @Nullable ByteBuffer message) {
      messenger.send(channel, message, null);
    }

 
    public void send(@NonNull String channel, @Nullable ByteBuffer message, @Nullable BinaryMessenger.BinaryReply callback) {
      messenger.send(channel, message, callback);
    }

    public void setMessageHandler(@NonNull String channel, @Nullable BinaryMessenger.BinaryMessageHandler handler) {
      messenger.setMessageHandler(channel, handler);
    }
  }

DefaultBinaryMessenger就是对DartMessenger的一个封装,啥都没有做。不知道这个类存在有什么意义,那就接着看DartMessager的发送方法

 @Override
  @UiThread
  public void send(@NonNull String channel, @NonNull ByteBuffer message) {
    Log.v(TAG, "Sending message over channel '" + channel + "'");
    send(channel, message, null);
  }

  @Override
  public void send(
      @NonNull String channel,
      @Nullable ByteBuffer message,
      @Nullable BinaryMessenger.BinaryReply callback
  ) {
    Log.v(TAG, "Sending message with callback over channel '" + channel + "'");
    int replyId = 0;
    if (callback != null) {
      replyId = nextReplyId++;
      pendingReplies.put(replyId, callback);
    }
    if (message == null) {
      flutterJNI.dispatchEmptyPlatformMessage(channel, replyId);
    } else {
      flutterJNI.dispatchPlatformMessage(channel, message, message.position(), replyId);
    }
  }

如果有方法回调callback,就会生成一个replyId,然后把方法回调和replyId加入到一个map,如果没有就直接发送消息了。
如果消息体为空,就发送一个空消息,如果有消息内容,就把消息发送过去。还会携带一个replyId,这个会在回调的时候有用。

最终走到了flutterJni的分发方法。

//FlutterJni.java

 public void dispatchPlatformMessage(@NonNull String channel, @Nullable ByteBuffer message, int position, int responseId) {
    ensureRunningOnMainThread();
    if (isAttached()) {
      nativeDispatchPlatformMessage(
          nativePlatformViewId,
          channel,
          message,
          position,
          responseId
      );
    } else {
      Log.w(TAG, "Tried to send a platform message to Flutter, but FlutterJNI was detached from native C++. Could not send. Channel: " + channel + ". Response ID: " + responseId);
    }
  }

// Send a data-carrying platform message to Dart.
  private native void nativeDispatchPlatformMessage(
      long nativePlatformViewId,
      @NonNull String channel,
      @Nullable ByteBuffer message,
      int position,
      int responseId
  );

//最终调到了c++层面,通过c++的dart虚拟机,把消息传递给了flutter。

消息如何从flutter传递过来?

到现在我们已经确定了我的消息是通过c++层面的虚拟机,发送到flutter,那么flutter的消息肯定也是要从c++层面的虚拟机发送过来,c++虚拟机就是原生与flutter通讯的桥梁。

android与c++的沟通肯定是通过FlutterJni这个类。

//FlutterJni讲自己绑定到了c++,
  public void attachToNative(boolean isBackgroundView) {
    ensureRunningOnMainThread();
    ensureNotAttachedToNative();
    nativePlatformViewId = nativeAttach(this, isBackgroundView);
  }

  private native long nativeAttach(@NonNull FlutterJNI flutterJNI, boolean isBackgroundView);

如果了解jni的知识,我们就能知道,把java类传入jni就是为了调用java类中的 方法。找了一下,

//用来处理从flutter主动call过来的消息
  private void handlePlatformMessage(@NonNull final String channel, byte[] message, final int replyId) {
    if (platformMessageHandler != null) {
      platformMessageHandler.handleMessageFromDart(channel, message, replyId);
    }

  }

//用来处理方法调用到flutter以后的回应。
  private void handlePlatformMessageResponse(int replyId, byte[] reply) {
    if (platformMessageHandler != null) {
      platformMessageHandler.handlePlatformMessageResponse(replyId, reply);
    }
   
  }

最终调动的了platformMessageHandler的分发的方法;

//通过这个方法绑定了一个方法的回调;
 public void setPlatformMessageHandler(@Nullable PlatformMessageHandler platformMessageHandler) {
    ensureRunningOnMainThread();
    this.platformMessageHandler = platformMessageHandler;
  }

PlatformMessageHandler是一个接口,找到他的实现类就找到了处理的地方;

DartMessenger是他的实现类,再看一下DartExecutor的一些方法;

public DartExecutor(@NonNull FlutterJNI flutterJNI, @NonNull AssetManager assetManager) {
    this.flutterJNI = flutterJNI;
    this.assetManager = assetManager;
    this.dartMessenger = new DartMessenger(flutterJNI);
    dartMessenger.setMessageHandler("flutter/isolate", isolateChannelMessageHandler);
    this.binaryMessenger = new DefaultBinaryMessenger(dartMessenger);
  }

  public void onAttachedToJNI() {
    Log.v(TAG, "Attached to JNI. Registering the platform message handler for this Dart execution context.");
    flutterJNI.setPlatformMessageHandler(dartMessenger);
  }

在构造函数里面,出啊建了DartMessager的对象,然后在调动onAttachToJNI的时候,注册给了FlutterJNI类。所以方法的处理是在DartMessager这个类中



  @Override
  public void handlePlatformMessageResponse(int replyId, @Nullable byte[] reply) {
    Log.v(TAG, "Received message reply from Dart.");
    BinaryMessenger.BinaryReply callback = pendingReplies.remove(replyId);
    if (callback != null) {
      try {
        Log.v(TAG, "Invoking registered callback for reply from Dart.");
        callback.reply(reply == null ? null : ByteBuffer.wrap(reply));
      } catch (Exception ex) {
        Log.e(TAG, "Uncaught exception in binary message reply handler", ex);
      }
    }
  }

先看下面那个方法,这个是原生调用flutter以后的回复。里面有一个replayId,和reply字节数组。

  1. 首先根据replyid找到刚才发送消息时保存的callback,
  2. 如果找到了,就把reply转化为bytebuff调用出去。
  3. 根据上面的分析可知道, BinaryReply的实现类为IncomingResultHandler
 private final class IncomingResultHandler implements BinaryReply {
        private final Result callback;

        IncomingResultHandler(Result callback) {
            this.callback = callback;
        }

        @Override
        @UiThread
        public void reply(ByteBuffer reply) {
            try {
                if (reply == null) {
                    callback.notImplemented();
                } else {
                    try {
                        callback.success(codec.decodeEnvelope(reply));
                    } catch (FlutterException e) {
                        callback.error(e.code, e.getMessage(), e.details);
                    }
                }
            } catch (RuntimeException e) {
                Log.e(TAG + name, "Failed to handle method call result", e);
            }
        }
    }

而IncomingResultHandler包装了我们的Result,最终消息在IncomingResultHandler#reply中解码后,传给了callback。我们从原生调用一个方法,然后获得结果的整个过程就是这样子。

如果是从flutter主动调动的消息,则是另一个线路。在DartMessage#handleMessageFromDart这个方法中,处理了flutter主动的消息。

@Override


//三个参数,通道名字,消息的字节,从flutter端传递过来的replyId,
  public void handleMessageFromDart(
      @NonNull final String channel,
      @Nullable byte[] message,
      final int replyId
  ) {
    Log.v(TAG, "Received message from Dart over channel '" + channel + "'");
    
    "1、根据通道名字找到对象的处理类"
    BinaryMessenger.BinaryMessageHandler handler = messageHandlers.get(channel);
    if (handler != null) {
      try {
        Log.v(TAG, "Deferring to registered handler to process message.");
        
        "2、解码数据并调用onMessage传递消息 ,注意一下这个Reply,下面会讲到"
        final ByteBuffer buffer = (message == null ? null : ByteBuffer.wrap(message));
        handler.onMessage(buffer, new Reply(flutterJNI, replyId));
      } catch (Exception ex) {
        Log.e(TAG, "Uncaught exception in binary message listener", ex);
        "异常处理"
        flutterJNI.invokePlatformMessageEmptyResponseCallback(replyId);
      }
    } else {
      Log.v(TAG, "No registered handler for message. Responding to Dart with empty reply message.");
      "未实现通道处理"
      flutterJNI.invokePlatformMessageEmptyResponseCallback(replyId);
    }
  }

处理类如何添加到messageHandlers中?

// DartMessage.java
public void setMessageHandler(@NonNull String channel, @Nullable BinaryMessenger.BinaryMessageHandler handler) {
    if (handler == null) {
      Log.v(TAG, "Removing handler for channel '" + channel + "'");
      messageHandlers.remove(channel);
    } else {
      Log.v(TAG, "Setting handler for channel '" + channel + "'");
      messageHandlers.put(channel, handler);
    }
  }

我们正向的在看一下代码。从MethodChannel中的注册来看。

//MethodChannel
 public void setMethodCallHandler(final @Nullable MethodCallHandler handler) {
        //这个messager是flutterView
        messenger.setMessageHandler(name,
            handler == null ? null : new IncomingMethodCallHandler(handler));
    }
    
   //FlutterView.java
   public void setMessageHandler(String channel, BinaryMessageHandler handler) {
        //mNativeView 是FlutterNativeView
        mNativeView.setMessageHandler(channel, handler);
    }
    //FlutterNativeView.java
    public void setMessageHandler(String channel, BinaryMessageHandler handler) {
        dartExecutor.getBinaryMessenger().setMessageHandler(channel, handler);
    }

最终又到了DartExecutor中,从上面的分析可以知道, dartExecutor.getBinaryMessenger()获得的是一个 DefaultBinaryMessenger;而DefaultBinaryMessenger中持有了DartMessager.所以setMessageHandler最终被设置到DartMessage中。所以从c++层面来了消息以后,就会回调到MethodChannel中;

在MethodChannel中设置的是一个MethodCallHandler,最后被包装为实现了BinaryMessageHandler的IncomingMethodCallHandler,,

private final class IncomingMethodCallHandler implements BinaryMessageHandler {
        private final MethodCallHandler handler;

        IncomingMethodCallHandler(MethodCallHandler handler) {
            this.handler = handler;
        }


        "DartMessage 调用这个方法把消息传递过来"
        @Override
        @UiThread
        public void onMessage(ByteBuffer message, final BinaryReply reply) {
        
            "解码信息 MethodCall中包含了方法名字 和 参数"
            final MethodCall call = codec.decodeMethodCall(message);
            try {
            
                "调用回调处理,如果需要回传结果,就调用Result的success方法。"
                handler.onMethodCall(call, new Result() {
                    @Override
                    public void success(Object result) {
                    
                        "这里面调用BinaryReply的reply方法传递给c++"
                        reply.reply(codec.encodeSuccessEnvelope(result));
                    }

                    @Override
                    public void error(String errorCode, String errorMessage, Object errorDetails) {
                        reply.reply(codec.encodeErrorEnvelope(errorCode, errorMessage, errorDetails));
                    }

                    @Override
                    public void notImplemented() {
                        reply.reply(null);
                    }
                });
            } catch (RuntimeException e) {
                Log.e(TAG + name, "Failed to handle method call", e);
                reply.reply(codec.encodeErrorEnvelope("error", e.getMessage(), null));
            }
        }
    }

BinaryReply的一个实现类为Reply,最终通过这个把结果回传回去。看源码!!!!

private static class Reply implements BinaryMessenger.BinaryReply {
    @NonNull
    private final FlutterJNI flutterJNI;
    private final int replyId;
    private final AtomicBoolean done = new AtomicBoolean(false);

    Reply(@NonNull FlutterJNI flutterJNI, int replyId) {
      this.flutterJNI = flutterJNI;
      this.replyId = replyId;
    }

    @Override
    public void reply(@Nullable ByteBuffer reply) {
      if (done.getAndSet(true)) {
        throw new IllegalStateException("Reply already submitted");
      }
      if (reply == null) {
        //如果结果没有信息,直接调用,并回传replyId
        flutterJNI.invokePlatformMessageEmptyResponseCallback(replyId);
      } else {
        //如果有信息,调用jni的这个方法,,把信息和replyid一起传回去。
        flutterJNI.invokePlatformMessageResponseCallback(replyId, reply, reply.position());
      }
    }
  }

到此为止。android端的消息机制已经分析完毕,关键的两个核心类,FlutterJni.java DartMessager.java

相关文章

网友评论

      本文标题:Flutter MethodChannel 源码解析

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