MethodChannel 原理之 Native -> Java

通过上文分析,我们知道FlutterViewHandlePlatformMessage()实际上是通过JNI的方式最终调用了FlutterJNI.java中的handlePlatformMessage()方法,该方法接受三个来自Native层的参数:

  • channel: String类型,表示Channel名称.
  • message: 字节数组,表示方法调用中的数据,如方法名和参数.
  • replyId: int类型,在将此次调用的响应数据从Java层写回到Native层时用到
public class FlutterJNI {
  private PlatformMessageHandler platformMessageHandler;
    
      @UiThread
  public void setPlatformMessageHandler(@Nullable PlatformMessageHandler platformMessageHandler) {
    this.platformMessageHandler = platformMessageHandler;
  }
    
      // Called by native.
  @SuppressWarnings("unused")
  private void handlePlatformMessage(final String channel, byte[] message, final int replyId) {
    if (platformMessageHandler != null) {
      platformMessageHandler.handleMessageFromDart(channel, message, replyId);
    }
  }
}

FlutterJNI类定义了Java层和Flutter C/C++引擎之间的相关接口.此类目前处于实验性质,随着后续的发展可能会被不断的重构和优化,不保证一直存在,不建议开发者调用该类.

为了建立Android应用和Flutter C/C++引擎的连接,需要创建FlutterJNI实例,然后将其attach到Native,常见的使用方法如下:

// 1.创建FlutterJNI实例
FlutterJNI flutterJNI = new FlutterJNI();
// 2.建立和Native层的连接
flutterJNI.attachToNative();
......
// 3.断开和Native层的连接,并释放资源
flutterJNI.detachFromNativeAndReleaseResources();

FlutterJNI中handlePlatformMessage(),在该方法中首先判断platformMessageHandler是否为null,不为null,则调用其handleMessageFromDart()方法.其中platformMessageHandler需要通过FlutterJNI中的setPlatformMessageHandler()方法来设置.在FlutterNativeView中调用的。

public class FlutterNativeView implements BinaryMessenger {

    private final Map mMessageHandlers;
    private int mNextReplyId = 1;
    private final Map mPendingReplies = new HashMap<>();

    private final FlutterPluginRegistry mPluginRegistry;
    private FlutterView mFlutterView;
    private FlutterJNI mFlutterJNI;
    private final Context mContext;
    private boolean applicationIsRunning;

    public FlutterNativeView(Context context, boolean isBackgroundView) {
        mContext = context;
        mPluginRegistry = new FlutterPluginRegistry(this, context);
        // 创建FlutterJNI实例
        mFlutterJNI = new FlutterJNI();
        mFlutterJNI.setRenderSurface(new RenderSurfaceImpl());
        // 将PlatformMessageHandlerImpl实例赋值给FlutterJNI中的platformMessageHandler属性
        mFlutterJNI.setPlatformMessageHandler(new PlatformMessageHandlerImpl());
        mFlutterJNI.addEngineLifecycleListener(new EngineLifecycleListenerImpl());
        attach(this, isBackgroundView);
        assertAttached();
        mMessageHandlers = new HashMap<>();
    }
    
    .......
}

在FlutterNativeView的构造函数中,首先创建FlutterJNI实例mFlutterJNI,然后调用setPlatformMessageHandler()并把PlatformMessageHandlerImpl实例作为参数传入.因此在FlutterJNI的handlePlatformMessage()方法中,最终调用PlatformMessageHandlerImpl实例的handleMessageFromDart()来处理来自Flutter中的消息.

public class FlutterNativeView implements BinaryMessenger {
        private final Map mMessageHandlers;
    
        ......
            
        private final class PlatformMessageHandlerImpl implements PlatformMessageHandler {
        // Called by native to send us a platform message.
        public void handleMessageFromDart(final String channel, byte[] message, final int replyId) {
       // 1.根据channel名称获取对应的BinaryMessageHandler对象.每个Channel对应一个Handler对象
            BinaryMessageHandler handler = mMessageHandlers.get(channel);
            if (handler != null) {
                try {
                    // 2.将字节数组对象封装为ByteBuffer对象
                    final ByteBuffer buffer = (message == null ? null : ByteBuffer.wrap(message));
                    // 3.调用handler对象的onMessage()方法来分发消息
                    handler.onMessage(buffer, new BinaryReply() {
                        private final AtomicBoolean done = new AtomicBoolean(false);
                        @Override
                        public void reply(ByteBuffer reply) {
                            // 4.根据reply的情况,调用FlutterJNI中invokePlatformMessageXXX()方法将响应数据发送给Flutter层
                            if (reply == null) {
                                mFlutterJNI.invokePlatformMessageEmptyResponseCallback(replyId);
                            } else {
                                mFlutterJNI.invokePlatformMessageResponseCallback(replyId, reply, reply.position());
                            }
                        }
                    });
                } catch (Exception exception) {
                    mFlutterJNI.invokePlatformMessageEmptyResponseCallback(replyId);
                }
                return;
            }
            mFlutterJNI.invokePlatformMessageEmptyResponseCallback(replyId);
        }
}

以Channel名称作为key,以BinaryMessageHandler类型为value.在handleMessageFromDart()方法中,首先根据Channel名称从mMessageHandlers取出对应的二进制消息处理器BinaryMessageHandler,然后将字节数组message封装为ByteBuffer对象,然后调用BinaryMessageHandler实例的onMessage()方法处理ByteBuffer,并进行响应.

BinaryReply是一个接口,主要用来将ByteBuffer类型的响应数据reply从Java层写回到Flutter层.根据reply是否为null,调用FlutterJNI实例不同的方法.

BinaryMessageHandler是如何添加到mMessageHandler中:

public class FlutterNativeView implements BinaryMessenger {
    private final Map mMessageHandlers;
    
    ......
        
    @Override
    public void setMessageHandler(String channel, BinaryMessageHandler handler) {
        if (handler == null) {
            mMessageHandlers.remove(channel);
        } else {
            mMessageHandlers.put(channel, handler);
        }
    }
    .......
}
public class MainActivity extends FlutterActivity {
    // 1.定义Channel的名称,该名称作为Channel的唯一标识符
    private static final String CHANNEL = "samples.flutter.io/battery";

    @Override
    public void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);
        // 2.创建MethodChannel对象channel
        MethodChannel channel = new MethodChannel(getFlutterView(), CHANNEL);
        // 3.调用MethodChannel实例的setMethodCallHandler()方法为当前channel设置Handler
        channel.setMethodCallHandler(
                new MethodCallHandler() {
                    @Override
                    public void onMethodCall(MethodCall call, Result result) {
                        // TODO
                    }
                });
    }
}

接下来是 MethodChannel 定义

public final class MethodChannel {
    // 二进制信使
    private final BinaryMessenger messenger;
    // Channel名称
    private final String name;
    // 方法编码
    private final MethodCodec codec;

    public MethodChannel(BinaryMessenger messenger, String name) {
        this(messenger, name, StandardMethodCodec.INSTANCE);
    }
        
    public MethodChannel(BinaryMessenger messenger, String name, MethodCodec codec) {
        assert messenger != null;
        assert name != null;
        assert codec != null;
        this.messenger = messenger;
        this.name = name;
        this.codec = codec;
    }    
    
    ......
        
    public void setMethodCallHandler(final @Nullable MethodCallHandler handler) {
        messenger.setMessageHandler(name,
            handler == null ? null : new IncomingMethodCallHandler(handler));
    }
    ......
    private final class IncomingMethodCallHandler implements BinaryMessageHandler {
        private final MethodCallHandler handler;

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

        @Override
        public void onMessage(ByteBuffer message, final BinaryReply reply) {
            // 1.使用codec对来自Flutter方法调用数据进行解码,并将其封装为MethodCall对象.
            // MethodCall中包含两部分数据:method表示要调用的方法;arguments表示方法所需参数
            final MethodCall call = codec.decodeMethodCall(message);
            try {
                // 2.调用自定义MethodCallHandler中的onMethodCall方法继续处理方法调用
                handler.onMethodCall(call, new Result() {
                    @Override
                    public void success(Object result) {
                        // 调用成功时,需要回传数据给Flutter层时,使用codec对回传数据result
                        // 进行编码
                        reply.reply(codec.encodeSuccessEnvelope(result));
                    }

                    @Override
                    public void error(String errorCode, String errorMessage, Object errorDetails) {
                        // 调用失败时,需要回传错误数据给Flutter层时,使用codec对errorCode,
                        // errorMessage,errorDetails进行编码
                        reply.reply(codec.encodeErrorEnvelope(errorCode, errorMessage, errorDetails));
                    }

                    @Override
                    public void notImplemented() {
                        // 方法没有实现时,调用该方法后,flutter将会受到相应的错误消息
                        reply.reply(null);
                    }
                });
            } catch (RuntimeException e) {
                Log.e(TAG + name, "Failed to handle method call", e);
                reply.reply(codec.encodeErrorEnvelope("error", e.getMessage(), null));
            }
        }
    }
}

在上述代码中,首先使用codec对来自Flutter层的二进制数据进行解码,并将其封装为MethodCall对象,然后调用MethodCallHandler.onMethodCall()方法.

调用过程

Java->Native

public class FlutterJNI {
  private Long nativePlatformViewId;
    
  ......  
  @UiThread
  public void invokePlatformMessageResponseCallback(int responseId, ByteBuffer message, int position) {
    // 1.检查FlutterJNI是否已经attach到Native层,如若没有则抛出异常  
    ensureAttachedToNative();
    // 2.继续调用nativeInvokePlatformMessageResponseCallback()  
    nativeInvokePlatformMessageResponseCallback(
        nativePlatformViewId,
        responseId,
        message,
        position
    );
  }
    
  private native void nativeInvokePlatformMessageResponseCallback(
     long nativePlatformViewId,
     int responseId,
     ByteBuffer message,
     int position
  );   
    
  ......  
      
  private void ensureAttachedToNative() {
    // FlutterJNI attach到Native层后,会返回一个long类型的值用来初始化nativePlatformViewId  
    if (nativePlatformViewId == null) {
      throw new RuntimeException("Cannot execute operation because FlutterJNI is not attached to native.");
    }
  }

}

当数据需要写回时,数据首先通过codec被编码成ByteBuffer类型,然后调用reply的reply()方法.在reply()方法中,对于非null类型的ByteBuffer,会调用FlutterJNI中的invokePlatformMessageResponseCallback().
在上述invokePlatformMessageResponseCallback()方法中,首先检查当前FlutterJNI实例是否已经attach到Native层,然后调用Native方法nativeInvokePlatformMessageResponseCallback()向JNI层写入数据

void PlatformViewAndroid::InvokePlatformMessageResponseCallback(
    JNIEnv* env,
    jint response_id,
    jobject java_response_data,
    jint java_response_position) {
  if (!response_id)
    return;
  // 1.通过response_id从pending_responses_中取出response  
  auto it = pending_responses_.find(response_id);
  if (it == pending_responses_.end())
    return;
  // 2.GetDirectBufferAddress函数返回一个指向被传入的ByteBuffer对象的地址指针  
  uint8_t* response_data =
      static_cast(env->GetDirectBufferAddress(java_response_data));
  std::vector response = std::vector(
      response_data, response_data + java_response_position);
  auto message_response = std::move(it->second);
  // 3.从pending_responses_中移除该response  
  pending_responses_.erase(it);
  // 4.调用response的Complete()方法将二进制结果返回
  message_response->Complete(
      std::make_unique(std::move(response)));
}

Native -> Dart

void PlatformMessageResponseDart::Complete(std::unique_ptr data) {
  if (callback_.is_empty())
    return;
  FML_DCHECK(!is_complete_);
  is_complete_ = true;
  ui_task_runner_->PostTask(fml::MakeCopyable(
      [callback = std::move(callback_), data = std::move(data)]() mutable {
        std::shared_ptr dart_state =
            callback.dart_state().lock();
        if (!dart_state)
          return;
        tonic::DartState::Scope scope(dart_state);
        // 将Native层的二进制数据data转为Dart中的二进制数据byte_buffer
        Dart_Handle byte_buffer = WrapByteData(std::move(data));
        tonic::DartInvoke(callback.Release(), {byte_buffer});
      }));
}

你可能感兴趣的:(MethodChannel 原理之 Native -> Java)