flutter通信機(jī)制-MethodChannel

流程圖如下:


流程圖

1晚唇、發(fā)送和接收

1.1 flutter端發(fā)送消息方式是:

class InteractUtil {
    static const platform = const MethodChannel("com.yourname.yourname/method");
      
    factory InteractUtil() => _getInstance();
    
    static InteractUtil get instance => _getInstance();
    static InteractUtil _instance;
    
    InteractUtil._internal();
  
    static InteractUtil _getInstance() {
        if (_instance == null) {
        _instance = new InteractUtil._internal();
        }
        return _instance;
    }
    
    Future<String> customMethodName(
    String parameter1, String parameter2) async {
        Future<String> result;
        try {
            print("customMethodName $parameter1 and $parameter2");
            result = await platform.invokeMethod("customMethodName", {
                "parameter1": parameter1,
                "parameter2": parameter2,
            });
        } on PlatformException catch (e) {
            print(e.toString());
        }
        return result;
    }
}

1.2 Android端接收消息的方式是:

class MainActivity : FlutterActivity() {
    val METHOD_CHANNEL = "com.yourname.yourname/method"
    override fun onCreate(savedInstanceState: Bundle?) {
        FlutterMain.startInitialization(this)
        super.onCreate(savedInstanceState)
        GeneratedPluginRegistrant.registerWith(this)

        MethodChannel(flutterView, METHOD_CHANNEL).setMethodCallHandler { p0, p1 ->
        Log.d(TAG, "method is ${p0.method}")
            when (p0.method) {
                "customMethodName" -> {
                    val parameter1 = p0.argument<String>("parameter1") as String
                    val parameter2 = p0.argument<String>("parameter2") as String
                }
            }
        }
    }
}

p0是MethodCall類型,p1是Result類型

兩端的MethodChannel name必須一致癣缅,另外flutter端調(diào)用invokeMethod 的方法名稱要在Android或iOS端有定義。

2、flutter端

2.1 MethodChannel初始化

MethodChannel構(gòu)造函數(shù)如下:

const MethodChannel(this.name, [this.codec = const StandardMethodCodec(), BinaryMessenger binaryMessenger ])
    : assert(name != null),assert(codec != null),
    _binaryMessenger = binaryMessenger;

先初始化了一個StandardMethodCodec對象李滴,看看構(gòu)造函數(shù)突硝,如下:

const StandardMethodCodec([this.messageCodec = const StandardMessageCodec()]);

StandardMethodCodec實現(xiàn)了MethodCodec接口

構(gòu)造函數(shù)中又初始化了一個StandardMessageCodec對象测摔,StandardMessageCodec實現(xiàn)了MessageCodec接口。

2.2 _binaryMessenger初始化

MethodChannel初始化成員變量的時候解恰,會初始化_binaryMessenger參數(shù)锋八,也就是set,看看定義:

BinaryMessenger get binaryMessenger => _binaryMessenger ?? defaultBinaryMessenger; // ignore: deprecated_member_use_from_same_package
final BinaryMessenger _binaryMessenger;

此處的binaryMessenger是null护盈,但是下次當(dāng)需要get的時候會走defaultBinaryMessenger參數(shù)挟纱,這個參數(shù)來自哪里呢?在src\services\binary_messenger.dart文件中定義了get方法:

BinaryMessenger get defaultBinaryMessenger {
  return ServicesBinding.instance.defaultBinaryMessenger;
}

看看ServicesBinding的defaultBinaryMessenger怎么初始化的:

packages\flutter\lib\src\services\binding.dart\ServicesBinding

mixin ServicesBinding on BindingBase {
    @override
    void initInstances() {
        _instance = this;
        _defaultBinaryMessenger = createBinaryMessenger();
        window.onPlatformMessage = defaultBinaryMessenger.handlePlatformMessage;
        SystemChannels.system.setMessageHandler(handleSystemMessage);
    }
    BinaryMessenger get defaultBinaryMessenger =>  _defaultBinaryMessenger;
    BinaryMessenger _defaultBinaryMessenger;
}

同一個文件中看看createBinaryMessenger方法:

BinaryMessenger createBinaryMessenger() {
    return const _DefaultBinaryMessenger._();
}

創(chuàng)建了_DefaultBinaryMessenger對象腐宋,其繼承自BinaryMessenger紊服。

2.3 window.onPlatformMessage

將defaultBinaryMessenger.handlePlatformMessage方法設(shè)置給window.onPlatformMessage。也就是_DefaultBinaryMessenger的handlePlatformMessage方法胸竞。

看看onPlatformMessage的定義:

lib\ui\window.dart\Window

PlatformMessageCallback get onPlatformMessage => _onPlatformMessage;
PlatformMessageCallback _onPlatformMessage;
Zone _onPlatformMessageZone;
set onPlatformMessage(PlatformMessageCallback callback) {
    _onPlatformMessage = callback;
    _onPlatformMessageZone = Zone.current;
}

這里的callback就是_DefaultBinaryMessenger的handlePlatformMessage方法欺嗤。

看看這個方法的定義:

packages\flutter\lib\src\services\binding.dart\_DefaultBinaryMessenger

@override
Future<void> handlePlatformMessage(String channel,ByteData data,ui.PlatformMessageResponseCallback callback,) async {
    ByteData response;
    try {
      final MessageHandler handler = _handlers[channel];
      if (handler != null) {
        response = await handler(data);
      } else {
        ui.channelBuffers.push(channel, data, callback);
        callback = null;
      }
    } catch (exception, stack) {
    } finally {
      if (callback != null) {
        callback(response);
      }
    }
}

onPlatformMessage接收到特定平臺的消息時,就會調(diào)用到handlePlatformMessage方法卫枝。window.onPlatformMessage是一個全局的變量煎饼,在很多消息傳遞的地方都可以調(diào)用。

2.4 setMessageHandler

handleSystemMessage在ServicesBinding中校赤,可以被其他Binding重載腺占,如下:

Future<void> handleSystemMessage(Object systemMessage) async { }

看看system變量:

packages\flutter\lib\src\services\system_channels.dart\SystemChannels

static const BasicMessageChannel<dynamic> system = BasicMessageChannel<dynamic>(
  'flutter/system',
  JSONMessageCodec(),
);

通過JSON來編解碼消息。JSONMessageCodec實現(xiàn)了MessageCodec接口痒谴。

2.5 MethodChannel.invokeMethod

我們自己的dart調(diào)用invokeMethod方法發(fā)送消息衰伯,如下:

Future<T> invokeMethod<T>(String method, [ dynamic arguments ]) async {
    assert(method != null);
    final ByteData result = await binaryMessenger.send(name,codec.encodeMethodCall(MethodCall(method, arguments)),);
    if (result == null) {
      throw MissingPluginException('No implementation found for method $method on channel $name');
    }
    final T typedResult = codec.decodeEnvelope(result);
    return typedResult;
}

其實還有invokeListMethod和invokeMapMethod方法,最終都是執(zhí)行到invokeMethod方法积蔚。

binaryMessenger對應(yīng)的類是_DefaultBinaryMessenger意鲸,codec對應(yīng)的是StandardMethodCodec類。

2.5.1 數(shù)據(jù)編碼

此處先將方法和參數(shù)通過MethodCall封裝,然后在StandardMethodCodec中編碼怎顾,看看具體怎么編碼的:

StandardMethodCodec

@override
ByteData encodeMethodCall(MethodCall call) {
    final WriteBuffer buffer = WriteBuffer();
    messageCodec.writeValue(buffer, call.method);
    messageCodec.writeValue(buffer, call.arguments);
    return buffer.done();
}

看看WriteBuffer的構(gòu)造函數(shù):

packages\flutter\lib\src\foundation\serialization.dart\WriteBuffer

WriteBuffer() {
    _buffer = Uint8Buffer();
    _eightBytes = ByteData(8);
    _eightBytesAsList = _eightBytes.buffer.asUint8List();
}

WriteBuffer構(gòu)造函數(shù)中初始化的Uint8Buffer類型读慎,可以看做是一個List<int>,而ByteData可以看做是一個byte數(shù)組槐雾,長度為8夭委。

messageCodec是一個StandardMessageCodec類型,看看他的writeValue方法:

void writeValue(WriteBuffer buffer, dynamic value) {
    writeSize(buffer, value.length);
    buffer.putxxx(_valueFloat64);
}

根據(jù)value的不同類型募强,put到不同的集合中株灸。如果value是int類型,就放到_buffer中擎值;如果是float類型慌烧,占8位,放到_eightBytes中鸠儿;而我們的method是String類型屹蚊,將其轉(zhuǎn)換為utf-8之后,轉(zhuǎn)成byte數(shù)組放到_buffer中进每。對于value占位大于1的汹粤,先寫占用長度,再寫占用值田晚。不同的長度對應(yīng)不同的數(shù)字嘱兼,如下:

static const int _valueNull = 0;
static const int _valueTrue = 1;
static const int _valueFalse = 2;
static const int _valueInt32 = 3;
static const int _valueInt64 = 4;
static const int _valueLargeInt = 5;
static const int _valueFloat64 = 6;
static const int _valueString = 7;
static const int _valueUint8List = 8;
static const int _valueInt32List = 9;
static const int _valueInt64List = 10;
static const int _valueFloat64List = 11;
static const int _valueList = 12;
static const int _valueMap = 13;

看done方法:

packages\flutter\lib\src\foundation\serialization.dart\WriteBuffer

ByteData done() {
    final ByteData result = _buffer.buffer.asByteData(0, _buffer.lengthInBytes);
    _buffer = null;
    return result;
}

其實是將剛才write進(jìn)去的數(shù)據(jù)轉(zhuǎn)成一個byte數(shù)組返回,這個數(shù)組的代表就是ByteData對象肉瓦。

2.6 發(fā)送消息(binaryMessenger.send)

上面提到binaryMessenger是_DefaultBinaryMessenger類型遭京,看看里面的send方法:

@override
Future<ByteData> send(String channel, ByteData message) {
    final MessageHandler handler = _mockHandlers[channel];
    if (handler != null)
      return handler(message);
    return _sendPlatformMessage(channel, message);
}

這里的_mockHandlers是Map<String, MessageHandler>類型胃惜,而MessageHandler的類型卻是:

typedef MessageHandler = Future<ByteData> Function(ByteData message);

一個函數(shù)泞莉。所以send方法最開始從這個Map中查找channel名稱對應(yīng)的函數(shù)是否存在,存在的話船殉,直接調(diào)用鲫趁,而不用執(zhí)行后面的方法了。明顯的利虫,這里需要調(diào)用_sendPlatformMessage方法:

Future<ByteData> _sendPlatformMessage(String channel, ByteData message) {
    final Completer<ByteData> completer = Completer<ByteData>();
    ui.window.sendPlatformMessage(channel, message, (ByteData reply) {
        completer.complete(reply);
    });
    return completer.future;
}

看看ui.window的sendPlatformMessage方法:

ui\window.dart\Window

void sendPlatformMessage(String name,ByteData data,PlatformMessageResponseCallback callback) {
    final String error = _sendPlatformMessage(name, _zonedPlatformMessageResponseCallback(callback), data);
}
String _sendPlatformMessage(String name,
                          PlatformMessageResponseCallback callback,
                          ByteData data) native 'Window_sendPlatformMessage';

最終調(diào)用到了native的Window_sendPlatformMessage方法:

ui\window\window.cc\Window

void Window::RegisterNatives(tonic::DartLibraryNatives* natives) {
    {"Window_sendPlatformMessage", _SendPlatformMessage, 4, true},
}

void _SendPlatformMessage(Dart_NativeArguments args) {
  tonic::DartCallStatic(&SendPlatformMessage, args);
}

Dart_Handle SendPlatformMessage(Dart_Handle window,const std::string& name,Dart_Handle callback,Dart_Handle data_handle) {
  UIDartState* dart_state = UIDartState::Current();

  if (!dart_state->window()) {
    return tonic::ToDart(
        "Platform messages can only be sent from the main isolate");
  }

  fml::RefPtr<PlatformMessageResponse> response;
  if (!Dart_IsNull(callback)) {
    response = fml::MakeRefCounted<PlatformMessageResponseDart>(
        tonic::DartPersistentValue(dart_state, callback),
        dart_state->GetTaskRunners().GetUITaskRunner());
  }
  if (Dart_IsNull(data_handle)) {
    dart_state->window()->client()->HandlePlatformMessage(
        fml::MakeRefCounted<PlatformMessage>(name, response));
  } else {
    tonic::DartByteData data(data_handle);
    const uint8_t* buffer = static_cast<const uint8_t*>(data.data());
    dart_state->window()->client()->HandlePlatformMessage(fml::MakeRefCounted<PlatformMessage>(name, std::vector<uint8_t>(buffer, buffer + data.length_in_bytes()),response));
  }

  return Dart_Null();
}

DartCallStatic方法將args轉(zhuǎn)換成了dart可處理的變量類型挨厚。

2.6.1 預(yù)定義返回

這里response對應(yīng)的是PlatformMessageResponseDart類型,看看這個方法:

ui\window\platform_message_response_dart.cc\PlatformMessageResponseDart

mMessageResponseDart::PlatformMessageResponseDart(
    tonic::DartPersistentValue callback,
    fml::RefPtr<fml::TaskRunner> ui_task_runner)
    : callback_(std::move(callback)),
      ui_task_runner_(std::move(ui_task_runner)) {}

void PlatformMessageResponseDart::Complete(std::unique_ptr<fml::Mapping> 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<tonic::DartState> dart_state = callback.dart_state().lock();
        if (!dart_state)
          return;
        tonic::DartState::Scope scope(dart_state);

        Dart_Handle byte_buffer = WrapByteData(std::move(data));
        tonic::DartInvoke(callback.Release(), {byte_buffer});
      }));
}

調(diào)用完成時會回調(diào)到這里,最終會調(diào)用callback對應(yīng)的閉包糠惫。

2.6.3 處理消息(HandlePlatformMessage)

接下來執(zhí)行HandlePlatformMessage疫剃,看看一系列調(diào)用堆棧:

runtime\runtime_controller.cc

// |WindowClient|
void RuntimeController::HandlePlatformMessage(fml::RefPtr<PlatformMessage> message) {
  client_.HandlePlatformMessage(std::move(message));
}

shell\common\engine.cc

void Engine::HandlePlatformMessage(fml::RefPtr<PlatformMessage> message) {
  if (message->channel() == kAssetChannel) {
    HandleAssetPlatformMessage(std::move(message));
  } else {
    delegate_.OnEngineHandlePlatformMessage(std::move(message));
  }
}

shell\common\shell.cc

// |Engine::Delegate|
void Shell::OnEngineHandlePlatformMessage(fml::RefPtr<PlatformMessage> message) {
    if (message->channel() == kSkiaChannel) {
        HandleEngineSkiaMessage(std::move(message));
        return;
    }

    task_runners_.GetPlatformTaskRunner()->PostTask([view = platform_view_->GetWeakPtr(), message = std::move(message)]() {
        if (view) {
            view->HandlePlatformMessage(std::move(message));
        }
    });
}

view對應(yīng)類,以Android平臺為例:

shell\platform\android\platform_view_android.cc

// |PlatformView|
void PlatformViewAndroid::HandlePlatformMessage(fml::RefPtr<flutter::PlatformMessage> message) {
  JNIEnv* env = fml::jni::AttachCurrentThread();
  fml::jni::ScopedJavaLocalRef<jobject> view = java_object_.get(env);
  if (view.is_null())
    return;

  int response_id = 0;
  if (auto response = message->response()) {
    response_id = next_response_id_++;
    pending_responses_[response_id] = response;
  }
  auto java_channel = fml::jni::StringToJavaString(env, message->channel());
  if (message->hasData()) {
    fml::jni::ScopedJavaLocalRef<jbyteArray> message_array(env, env->NewByteArray(message->data().size()));
    env->SetByteArrayRegion(message_array.obj(), 0, message->data().size(), reinterpret_cast<const jbyte*>(message->data().data()));
    message = nullptr;

    // This call can re-enter in InvokePlatformMessageXxxResponseCallback.
    FlutterViewHandlePlatformMessage(env, view.obj(), java_channel.obj(),message_array.obj(), response_id);
  } else {
    message = nullptr;
    
    // This call can re-enter in InvokePlatformMessageXxxResponseCallback.
    FlutterViewHandlePlatformMessage(env, view.obj(), java_channel.obj(),nullptr, response_id);
  }
}

接下來調(diào)用FlutterViewHandlePlatformMessage方法硼讽,這個方法對應(yīng)的是Java jni注冊的方法巢价,看看方法體:

shell\platform\android\platform_view_android_jni.cc

void FlutterViewHandlePlatformMessage(JNIEnv* env, jobject obj,jstring channel,jobject message,jint responseId) {
  env->CallVoidMethod(obj, g_handle_platform_message_method, channel, message,responseId);
  FML_CHECK(CheckException(env));
}

看看g_handle_platform_message_method注冊的地方:

shell\platform\android\platform_view_android_jni.cc

g_handle_platform_message_method = env->GetMethodID(g_flutter_jni_class->obj(), "handlePlatformMessage","(Ljava/lang/String;[BI)V");

2.6.4 到系統(tǒng)平臺處理消息

對應(yīng)Java中的handlePlatformMessage方法,參數(shù)是String,byte數(shù)組壤躲,int城菊。看看handlePlatformMessage方法:

shell\platform\android\io\flutter\embedding\engine\FlutterJNI.java

private void handlePlatformMessage(
  @NonNull final String channel, byte[] message, final int replyId) {
    if (platformMessageHandler != null) {
      platformMessageHandler.handleMessageFromDart(channel, message, replyId);
    }
}

在FlutterJNI類中碉克,通過setPlatformMessageHandler方法設(shè)置platformMessageHandler對象凌唬,看看是哪里設(shè)置的。還記得FlutterNativeView構(gòu)造函數(shù)中漏麦,最后調(diào)用了attach方法客税,如下:

shell\platform\android\io\flutter\view\FlutterNativeView.java

private void attach(FlutterNativeView view, boolean isBackgroundView) {
    mFlutterJNI.attachToNative(isBackgroundView);
    dartExecutor.onAttachedToJNI();
}

看看onAttachedToJNI方法:

shell\platform\android\io\flutter\embedding\engine\dart\DartExecutor.java

public void onAttachedToJNI() {
    flutterJNI.setPlatformMessageHandler(dartMessenger);
}

這里的dartMessenger對應(yīng)的是DartMessenger類,所以此處的platformMessageHandler對應(yīng)的是DartMessenger對象唁奢。另外在dartMessenger初始化的時候霎挟,會調(diào)用setMessageHandler方法:

shell\platform\android\io\flutter\embedding\engine\dart\DartExecutor.java

private final BinaryMessenger.BinaryMessageHandler isolateChannelMessageHandler =
  new BinaryMessenger.BinaryMessageHandler() {
    @Override
    public void onMessage(ByteBuffer message, final BinaryReply callback) {
      isolateServiceId = StringCodec.INSTANCE.decodeMessage(message);
      if (isolateServiceIdListener != null) {
        isolateServiceIdListener.onIsolateServiceIdAvailable(isolateServiceId);
      }
    }
};

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);
}

這里的isolateChannelMessageHandler對應(yīng)的是BinaryMessenger.BinaryMessageHandler類,channel name是flutter/isolate麻掸。在DartMessenger中酥夭,通過setMessageHandler方法將channel name和MessageHandler放到了messageHandlers這個Map對象中。如下:

@Override
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);
    }
}

回到開始調(diào)用handleMessageFromDart的地方脊奋,這個方法在DartMessenger中有定義:

shell\platform\android\io\flutter\embedding\engine\dart\DartMessenger.java

@Override
public void handleMessageFromDart(
  @NonNull final String channel, @Nullable byte[] message, final int replyId) {
    Log.v(TAG, "Received message from Dart over channel '" + channel + "'");
    BinaryMessenger.BinaryMessageHandler handler = messageHandlers.get(channel);
    if (handler != null) {
      try {
        Log.v(TAG, "Deferring to registered handler to process message.");
        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這個Map中取出channel name對應(yīng)的MessageHandler熬北,然后回調(diào)到他的onMessage方法中。

3诚隙、Android端

3.1 MethodChannel

Android端最開始注冊接收的代碼如下:

MethodChannel(flutterView, METHOD_CHANNEL).setMethodCallHandler {
}

flutterView其實是FlutterActivityDelegate中的FlutterView flutterView對象讶隐,而FlutterView實現(xiàn)了BinaryMessenger接口。

看看MethodChannel構(gòu)造函數(shù):

MethodChannel

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

public MethodChannel(BinaryMessenger messenger, String name, MethodCodec codec) {
    this.messenger = messenger;
    this.name = name;
    this.codec = codec;
}

這里的messenger就是FlutterView類型久又。

3.2 MethodCallHandler

接下來看看MethodChannel的setMethodCallHandler方法:

shell\platform\android\io\flutter\plugin\common\MethodChannel.java

public void setMethodCallHandler(final @Nullable MethodCallHandler handler) {
    messenger.setMessageHandler(name,handler == null ? null : new IncomingMethodCallHandler(handler));
}

到這里巫延,我們的handler其實是在我們的MainActivity中定義了的,只不過lamada表達(dá)式將類名隱藏地消,只顯示了閉包接收的參數(shù)炉峰。完整的形式是:

MethodChannel(flutterView, METHOD_CHANNEL).setMethodCallHandler(MethodChannel.MethodCallHandler { p0, p1 ->
}

3.2.1 IncomingMethodCallHandler

最終通過IncomingMethodCallHandler將我們的MethodCallHandler初始化給IncomingMethodCallHandler類的handler對象,如下:

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

    IncomingMethodCallHandler(MethodCallHandler handler) {
      this.handler = handler;
    }
    public void onMessage(ByteBuffer message, final BinaryReply reply) {
      
    }
}

這里的codec在MethodChannel構(gòu)造的時候默認(rèn)為StandardMethodCodec實例脉执。

看看messenger所屬的FlutterView中的setMessageHandler函數(shù):

FlutterView

public void setMessageHandler(String channel, BinaryMessageHandler handler) {
    mNativeView.setMessageHandler(channel, handler);
}

這里的handler就是IncomingMethodCallHandler,看看setMessageHandler的setMessageHandler方法:

FlutterNativeView

public void setMessageHandler(String channel, BinaryMessageHandler handler) {
    dartExecutor.getBinaryMessenger().setMessageHandler(channel, handler);
}

3.3 DefaultBinaryMessenger

又回到dartExecutor這里了疼阔,getBinaryMessenger()方法對應(yīng)的是DefaultBinaryMessenger,看看他的setMessageHandler方法:

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

DefaultBinaryMessenger構(gòu)造的時候半夷,有初始化一個messenger對象婆廊,他對應(yīng)的是DartMessenger,就可以發(fā)現(xiàn)最終是向他所屬的Map中添加channel對應(yīng)的BinaryMessenger.BinaryMessageHandler巫橄。

messageHandlers.put(channel, handler);

這里終于將dart發(fā)送過來的消息和java層的注冊對接起來了淘邻。

3.4 MethodCallHandler中處理消息

handleMessageFromDart中通過handler執(zhí)行的onMessage方法,即IncomingMethodCallHandler類中的onMessage方法湘换,通過StandardMethodCodec解碼之后得到MethodCall對象宾舅,然后回調(diào)給MainActivity里面MethodCallHandler的onMethodCall方法敬尺。

IncomingMethodCallHandler直接處理dart來的數(shù)據(jù),并分發(fā)

public void onMessage(ByteBuffer message, final BinaryReply reply) {
    final MethodCall call = codec.decodeMethodCall(message);
    handler.onMethodCall(call,new Result() {
        @Override
        public void success(Object result) {
            reply.reply(codec.encodeSuccessEnvelope(result));
        }
        
        @Override
        public void error(String errorCode, String errorMessage, Object errorDetails) {
            reply.reply(codec.encodeErrorEnvelope(errorCode, errorMessage, errorDetails));
        }
    });
}

MainActicity注冊Handler之后接收數(shù)據(jù)贴浙,處理數(shù)據(jù)砂吞,完成之后返回

MethodChannel(flutterView, METHOD_CHANNEL).setMethodCallHandler(MethodChannel.MethodCallHandler { p0, p1 ->
    MyLog.d(TAG, "method is ${p0.method}")
    when (p0.method) {
        "method_name" -> {
            p1.success(data)
        }
    }
}

4、返回

Android端處理完dart的消息之后崎溃,可以通過Result對象將需要返回的數(shù)據(jù)返回蜻直,包括成功,失敗袁串,未完成概而。

reply其實是在handleMessageFromDart方法中初始化的,handler.onMessage(buffer, new Reply(flutterJNI, replyId))囱修。

4.1 返回成功或失敗

成功的話赎瑰,會通過StandardMethodCodec的encodeSuccessEnvelope將數(shù)據(jù)編碼:

reply.reply(codec.encodeSuccessEnvelope(result));

public ByteBuffer encodeSuccessEnvelope(Object result) {
    final ExposedByteArrayOutputStream stream = new ExposedByteArrayOutputStream();
    stream.write(0);
    messageCodec.writeValue(stream, result);
    final ByteBuffer buffer = ByteBuffer.allocateDirect(stream.size());
    buffer.put(stream.buffer(), 0, stream.size());
    return buffer;
}

先寫進(jìn)去一個成功的標(biāo)志位,messageCodec是StandardMethodCodec類型破镰,將要返回的數(shù)據(jù)寫進(jìn)一個byte數(shù)組中餐曼,然后放到ByteBuffer中,返回鲜漩。

失敗的話源譬,會有失敗原因:

reply.reply(codec.encodeErrorEnvelope(errorCode, errorMessage, errorDetails));

@Override
public ByteBuffer encodeErrorEnvelope(
  String errorCode, String errorMessage, Object errorDetails) {
    final ExposedByteArrayOutputStream stream = new ExposedByteArrayOutputStream();
    stream.write(1);
    messageCodec.writeValue(stream, errorCode);
    messageCodec.writeValue(stream, errorMessage);
    messageCodec.writeValue(stream, errorDetails);
    final ByteBuffer buffer = ByteBuffer.allocateDirect(stream.size());
    buffer.put(stream.buffer(), 0, stream.size());
    return buffer;
}

編碼失敗數(shù)據(jù)時,與成功唯一的差別是標(biāo)志位不一樣孕似。

4.2 Reply返回數(shù)據(jù)

看看Reply的具體返回方式:

4.2.1 Reply

@Override
public void reply(@Nullable ByteBuffer reply) {
  if (done.getAndSet(true)) {
    throw new IllegalStateException("Reply already submitted");
  }
  if (reply == null) {
    flutterJNI.invokePlatformMessageEmptyResponseCallback(replyId);
  } else {
    flutterJNI.invokePlatformMessageResponseCallback(replyId, reply, reply.position());
  }
}

我們這里的reply不為空踩娘,執(zhí)行invokePlatformMessageResponseCallback方法:

shell\platform\android\io\flutter\embedding\engine\FlutterJNI.java

public void invokePlatformMessageResponseCallback(int responseId, @Nullable ByteBuffer message, int position) {
    if (isAttached()) {
      nativeInvokePlatformMessageResponseCallback(nativePlatformViewId, responseId, message, position);
    }
}

private native void nativeInvokePlatformMessageResponseCallback(long nativePlatformViewId, int responseId, @Nullable ByteBuffer message, int position);

這里的nativePlatformViewId其實是我們在應(yīng)用啟動時,初始化引擎返回給我們的一個long類型的id喉祭。

4.3 引擎中處理數(shù)據(jù)

nativeInvokePlatformMessageResponseCallback對應(yīng)注冊的native方法是InvokePlatformMessageResponseCallback:

shell\platform\android\platform_view_android_jni.cc

bool RegisterApi(JNIEnv* env) {
  static const JNINativeMethod flutter_jni_methods[] = {
    {
      .name = "nativeInvokePlatformMessageResponseCallback",
      .signature = "(JILjava/nio/ByteBuffer;I)V",
      .fnPtr = reinterpret_cast<void*>(&InvokePlatformMessageResponseCallback),
    },
  }
}

具體看看InvokePlatformMessageResponseCallback的調(diào)用棧:

shell\platform\android\platform_view_android_jni.cc

static void InvokePlatformMessageResponseCallback(JNIEnv* env,jobject jcaller,jlong shell_holder,jint responseId,jobject message,jint position) {
    ANDROID_SHELL_HOLDER->GetPlatformView()->InvokePlatformMessageResponseCallback(env,responseId,message,position);
}

shell\platform\android\platform_view_android.cc

void PlatformViewAndroid::InvokePlatformMessageResponseCallback(JNIEnv* env,jint response_id,jobject java_response_data,jint java_response_position) {
    if (!response_id)
        return;
    auto it = pending_responses_.find(response_id);
    if (it == pending_responses_.end())
        return;
    uint8_t* response_data = static_cast<uint8_t*>(env->GetDirectBufferAddress(java_response_data));
    std::vector<uint8_t> response = std::vector<uint8_t>(response_data, response_data + java_response_position);
    auto message_response = std::move(it->second);
    pending_responses_.erase(it);
    message_response->Complete(std::make_unique<fml::DataMapping>(std::move(response)));
}

4.3 平臺返回數(shù)據(jù)回到dart

這里的Complete對應(yīng)的是在PlatformMessageResponseDart中养渴,flutter發(fā)送消息的過程中有定義,這個方法中對應(yīng)的callback方法在dart send方法的時候就有定義泛烙,這里再寫一遍:

Future<ByteData> _sendPlatformMessage(String channel, ByteData message) {
    ui.window.sendPlatformMessage(channel, message, (ByteData reply) {
        completer.complete(reply);
    });
    return completer.future;
}

最終執(zhí)行到這個閉包了理卑。Completer是一個工作流的狀態(tài)管理類,最開始的時候新建一個對象胶惰,接下來執(zhí)行future任務(wù)傻工,任務(wù)完成后執(zhí)行complete表示執(zhí)行完成霞溪。

執(zhí)行完成的時候孵滞,在MethodChannel的invokeMethod方法中就接收到了返回數(shù)據(jù):

flutter\lib\src\services\platform_channel.dart

Future<T> invokeMethod<T>(String method, [ dynamic arguments ]) async {
    final ByteData result = await binaryMessenger.send(name,codec.encodeMethodCall(MethodCall(method, arguments)),);
    if (result == null) {
        throw MissingPluginException('No implementation found for method $method on channel $name');
    }
    final T typedResult = codec.decodeEnvelope(result);
    return typedResult;
}

這里的codec是StandardMethodCodec類型,將返回的數(shù)據(jù)解碼就可以返回了鸯匹。最終也在我們自己的dart代碼中接收到返回數(shù)據(jù)了坊饶。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市殴蓬,隨后出現(xiàn)的幾起案子匿级,更是在濱河造成了極大的恐慌蟋滴,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,755評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件痘绎,死亡現(xiàn)場離奇詭異津函,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)孤页,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評論 3 395
  • 文/潘曉璐 我一進(jìn)店門尔苦,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人行施,你說我怎么就攤上這事允坚。” “怎么了蛾号?”我有些...
    開封第一講書人閱讀 165,138評論 0 355
  • 文/不壞的土叔 我叫張陵稠项,是天一觀的道長。 經(jīng)常有香客問我鲜结,道長展运,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,791評論 1 295
  • 正文 為了忘掉前任精刷,我火速辦了婚禮乐疆,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘贬养。我一直安慰自己挤土,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,794評論 6 392
  • 文/花漫 我一把揭開白布误算。 她就那樣靜靜地躺著仰美,像睡著了一般。 火紅的嫁衣襯著肌膚如雪儿礼。 梳的紋絲不亂的頭發(fā)上咖杂,一...
    開封第一講書人閱讀 51,631評論 1 305
  • 那天,我揣著相機(jī)與錄音蚊夫,去河邊找鬼诉字。 笑死,一個胖子當(dāng)著我的面吹牛知纷,可吹牛的內(nèi)容都是我干的壤圃。 我是一名探鬼主播,決...
    沈念sama閱讀 40,362評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼琅轧,長吁一口氣:“原來是場噩夢啊……” “哼伍绳!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起乍桂,我...
    開封第一講書人閱讀 39,264評論 0 276
  • 序言:老撾萬榮一對情侶失蹤冲杀,失蹤者是張志新(化名)和其女友劉穎效床,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體权谁,經(jīng)...
    沈念sama閱讀 45,724評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡剩檀,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了旺芽。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片谨朝。...
    茶點故事閱讀 40,040評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖甥绿,靈堂內(nèi)的尸體忽然破棺而出字币,到底是詐尸還是另有隱情,我是刑警寧澤共缕,帶...
    沈念sama閱讀 35,742評論 5 346
  • 正文 年R本政府宣布洗出,位于F島的核電站,受9級特大地震影響图谷,放射性物質(zhì)發(fā)生泄漏翩活。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,364評論 3 330
  • 文/蒙蒙 一便贵、第九天 我趴在偏房一處隱蔽的房頂上張望菠镇。 院中可真熱鬧,春花似錦承璃、人聲如沸利耍。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽隘梨。三九已至,卻和暖如春舷嗡,著一層夾襖步出監(jiān)牢的瞬間轴猎,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評論 1 270
  • 我被黑心中介騙來泰國打工进萄, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留捻脖,地道東北人。 一個月前我還...
    沈念sama閱讀 48,247評論 3 371
  • 正文 我出身青樓中鼠,卻偏偏與公主長得像可婶,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子兜蠕,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,979評論 2 355

推薦閱讀更多精彩內(nèi)容