Flutter插件原理浅谈
Platform Channel是Flutter端与Platform端指定的通信机制,它分为三种: (1) BasicMessageChannel: 用于传递字符串和半结构化的信息(在大内存数据块传递的情况下使用)。 (2) MethodChannel: 用于传递方法的调用(method invocation)。 (3) EventChannel:用于数据流(event streams)的通信。
消息传递与编解码器 从图中可以看出,不同的Handler对应不同的消息通道。 其中,中间通信的消息都是编码的二进制格式形式,需要通过消息解码器进行处理。 编码分为两种:MessageCodec 和MethodCodec。其中,MessageCodec包括BinaryCodec, StringCodec,JSONMesageCodec和 StandardMessageCodec, MethodCodec包括JSONMethodCodec 和 StandardMethodCodec。
Plaffrom 数据类型支持 Flutter默认的消息编码器(StandardMessageCodec),目前支持的数据类型如下:
Dart
Android
IOS
null
null
nil(NSNull when nested)
bool
Java.lang.Boolean
NSNumber numberWithBool:
int
Java.lang.Integer
NSNumber numberWithInt:
int
Java.lang.Long
NSNumber numberWithLong:
double
Java.lang.Double
NSNumber numberWithDouble:
String
Java.lang.String
NSSttring
Unit8List
byte[]
FlutterStandardTypedData typedDataWithBytes:
int32List
int[]
FlutterStandardTypedData typedDataWithInt32:
int64List
long[]
FlutterStandardTypedData typedDataWithInt64:
Float64List
double[]
FlutterStandardTypedData typedDataWithFloat64:
List
java.util.ArrayList
NSArray
Map
java.util.HashMap
NSDictionary
Flutter插件调用流程图 备注:Android侧没有画出,是由于StartUML工具在画时序图时,无法调整序号。
Flutter插件原理分析
下面针对PlatfromChannel进行说明,为了更好的举例,下面先展出示例代码。
Dart端代码
android端原生代码
下面先从Flutter端开始说起
flutter插件先调用了MethodChannel.invokeMethod方法,在MethodChannel类中,此方法的定义如下:
1 2 3 4 5 6 7 8 9 10 11 12 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; }
此类方法定义在BasicMessageChannel.dart文件中,binaryMessenger对象在此类默认使用ServicesBinding.defaultBinaryMessenger
codec对象是消息解码器,在此类中,使用StandardMethodCodec。
下面我们看一下ServicesBinding.defaultBinaryMessenger.send方法的实现逻辑。
其实最终ServicesBinding.defaultBinaryMessenger类映射到binding.dart文件中_DefaultBinaryMessenger类,此类继承于BinaryMessenger类,BinaryMessenger类是个抽象类,类的定义形式如下:

_DefaultBinaryMessenger类send方法实现如下:
1 2 3 4 5 6 Future<ByteData> send(String channel, ByteData message) { final MessageHandler handler = _mockHandlers[channel]; if (handler != null) return handler(message); return _sendPlatformMessage(channel, message); }
可以看到,如果在MethodChannel时调用setMethodCallHandler方法时,设置了回调,优先调用了这个回调。前面我们没有调用setMethodCallHandler方法,所以直接走_sendPlatformMessage方法。下面是_sendPlatformMessage方法实现
_sendPlatformMessage(String channel, ByteData message) { 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 final Completer<ByteData> completer = Completer<ByteData>(); // ui.window is accessed directly instead of using ServicesBinding.instance.window // because this method might be invoked before any binding is initialized. // This issue was reported in #27541. It is not ideal to statically access // ui.window because the Window may be dependency injected elsewhere with // a different instance. However, static access at this location seems to be // the least bad option. ui.window.sendPlatformMessage(channel, message, (ByteData reply) { try { completer.complete(reply); } catch (exception, stack) { FlutterError.reportError(FlutterErrorDetails( exception: exception, stack: stack, library: 'services library', context: ErrorDescription('during a platform message response callback'), )); } }); return completer.future; }
在此方法中,有ui.window对象,ui引用于 'dart:ui' 库,ui.window最后映射到window.dart。在window.dart中,有window.dart中,定义了Window类,其中sendPlatformMessage方法,实现如下

从此方法中,可以最终是调用到了Native层的_sendPlatformMessage方法。Native层是C++实现的。此方法在window.cc文件中,最终映射到下面的方法
SendPlatformMessage(Dart_Handle window, 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 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(); }
该方法主要功能:
- 该方法是发送平台消息,则只允许从主isolate中发出,否则会跑出异常
- 该SendPlatformMessage方法的参数name代表是channel名,data_handle是记录待执行的方法名和参数,callback是执行后回调反馈结果数据的方法
- 创建PlatformMessageResponseDart对象,保存callback方法
- 调用RuntimeController的HandlePlatformMessage来处理平台消息
RuntimeController类定义在flutter/runtime/runtime_controller.cc
RuntimeController::HandlePlatformMessage( 1 2 3 fml::RefPtr<PlatformMessage> message) { client_.HandlePlatformMessage(std::move(message)); }
上面的类最终调用到了Engine::HandlePlatformMessage[-> flutter/shell/common/engine.cc]
constexpr char kAssetChannel[] 1 2 3 4 5 6 7 void Engine::HandlePlatformMessage(fml::RefPtr<PlatformMessage> message) { if (message->channel() == kAssetChannel) { HandleAssetPlatformMessage(std::move(message)); } else { delegate_.OnEngineHandlePlatformMessage(std::move(message)); } }
下一步调用了Shell类OnEngineHandlePlatformMessage方法[-> flutter/shell/common/shell.cc]
Shell::OnEngineHandlePlatformMessage( 1 2 3 4 5 6 7 8 9 10 11 12 13 14 fml::RefPtr<PlatformMessage> message) { FML_DCHECK(is_setup_); FML_DCHECK(task_runners_.GetUITaskRunner()->RunsTasksOnCurrentThread()); 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)); } }); }
接下来将HandlePlatformMessage的工作交给主线程的PlatformTaskRunner来处理,对于PlatformView在Android平台的实例为PlatformViewAndroid。
[-> flutter/shell/platform/android/platform_view_android.cc]
PlatformViewAndroid::HandlePlatformMessage( 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 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); } }
[-> flutter/shell/platform/android/platform_view_android_jni.cc]
FlutterViewHandlePlatformMessage(JNIEnv* env, jobject obj, 1 2 3 4 jstring channel, jobject message, jint responseId) { env->CallVoidMethod(obj, g_handle_platform_message_method, channel, message, responseId); }
接下来,会调用到FlutterJNI类的handlePlatformMessage方法中,此方法[->flutter/shell/platform/android/io/flutter/embedding/engine/FlutterJNI.java]
终于调用到Java代码了。
TODO(mattcarroll): determine if message is nonull or nullable 1 2 3 4 5 6 7 @SuppressWarnings("unused") private void handlePlatformMessage(@NonNull final String channel, byte[] message, final int replyId) { if (platformMessageHandler != null) { platformMessageHandler.handleMessageFromDart(channel, message, replyId); } // TODO(mattcarroll): log dropped messages when in debug mode (https://github.com/flutter/flutter/issues/25391) }
3.从宿主端android开始
- 3.1 FlutterView
在android原生页面,每个activity都继承于FlutterActivity。在FlutterActivity中有个代理类FlutterActivityDelegate类,此类代理了Activity类的几个生命周期方法,下面先从此类的onCreate说明,在此方法中定义了FlutterView,Activity的根view就是FlutterView,FlutterView继承SurfaceView,另外实现了BinaryMessenger,TextureRegistry两个接口,这个BinaryMessage接口很重要,后面会讲到。下面是FlutterActivityDelegate类中onCreate方法的定义:
class FlutterView extends SurfaceView implements BinaryMessenger, TextureRegistry { 1 2 3 4 5 6 7 8 9 10 11 12 13 14 ...... public void onCreate(Bundle savedInstanceState) { ...... this.flutterView = this.viewFactory.createFlutterView(this.activity); if (this.flutterView == null) { FlutterNativeView nativeView = this.viewFactory.createFlutterNativeView(); this.flutterView = new FlutterView(this.activity, (AttributeSet)null, nativeView); this.flutterView.setLayoutParams(matchParent); this.activity.setContentView(this.flutterView); ...... } ...... } }
创建FlutterView时,传入了FlutterNativeView。
- 3.2 FlutterNativeView
FlutterNativeView构造器定义如下:
FlutterNativeView(@NonNull Context context, boolean isBackgroundView) { 1 2 3 4 5 6 7 8 9 this.mContext = context; this.mPluginRegistry = new FlutterPluginRegistry(this, context); this.mFlutterJNI = new FlutterJNI(); this.mFlutterJNI.setRenderSurface(new FlutterNativeView.RenderSurfaceImpl()); this.dartExecutor = new DartExecutor(this.mFlutterJNI, context.getAssets()); this.mFlutterJNI.addEngineLifecycleListener(new FlutterNativeView.EngineLifecycleListenerImpl()); this.attach(this, isBackgroundView); this.assertAttached(); }
其中FlutterJNI类提前我们提到过,最后dart插件的方法,最后调用了FlutterJNI.handlePlatformMessage方法,那么现在就需要找到在何处调用了FlutterJNI.setPlatformMessageHandler方法。
从上面的代码中,FlutterJNI类传给了DartExecutor类。
3.3 DartExecutor DartExecutor类的构造类说明如下:
DartExecutor(@NonNull FlutterJNI flutterJNI, @NonNull AssetManager assetManager) { 1 2 3 4 5 this.flutterJNI = flutterJNI; this.assetManager = assetManager; this.messenger = new DartMessenger(flutterJNI); this.messenger.setMessageHandler("flutter/isolate", this.isolateChannelMessageHandler); }
- 3.4 DartMessenger
DartMessenger类的构造器类说明如下:
class DartMessenger implements BinaryMessenger, PlatformMessageHandler 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 DartMessenger(@NonNull FlutterJNI flutterJNI) { this.flutterJNI = flutterJNI; this.messageHandlers = new HashMap(); this.pendingReplies = new HashMap(); } public void setMessageHandler(@NonNull String channel, @Nullable BinaryMessageHandler handler) { if (handler == null) { Log.v("DartMessenger", "Removing handler for channel '" + channel + "'"); this.messageHandlers.remove(channel); } else { Log.v("DartMessenger", "Setting handler for channel '" + channel + "'"); this.messageHandlers.put(channel, handler); } } @UiThread public void send(@NonNull String channel, @NonNull ByteBuffer message) { Log.v("DartMessenger", "Sending message over channel '" + channel + "'"); this.send(channel, message, (BinaryReply)null); } public void handleMessageFromDart(@NonNull String channel, @Nullable byte[] message, int replyId) { Log.v("DartMessenger", "Received message from Dart over channel '" + channel + "'"); BinaryMessageHandler handler = (BinaryMessageHandler)this.messageHandlers.get(channel); if (handler != null) { try { Log.v("DartMessenger", "Deferring to registered handler to process message."); ByteBuffer buffer = message == null ? null : ByteBuffer.wrap(message); handler.onMessage(buffer, new DartMessenger.Reply(this.flutterJNI, replyId)); } catch (Exception var6) { Log.e("DartMessenger", "Uncaught exception in binary message listener", var6); this.flutterJNI.invokePlatformMessageEmptyResponseCallback(replyId); } } else { Log.v("DartMessenger", "No registered handler for message. Responding to Dart with empty reply message."); this.flutterJNI.invokePlatformMessageEmptyResponseCallback(replyId); } } }
DartMessenger类实现了platfromMessageHandler接口中的handleMessageFromDart方法,最终FlutterJNI是调用到了DartMessenger类handleMessageFromDart方法。下面就需要找FlutterJNI调用setPlatformMessageHandler(new DartMessager())的地方,我们往回看,发现DartExecutor类onAttachedToJNI方法正好实现了。
void onAttachedToJNI() { 1 2 3 Log.v("DartExecutor", "Attached to JNI. Registering the platform message handler for this Dart execution context."); this.flutterJNI.setPlatformMessageHandler(this.messenger); }
接着再往下看,又回到FlutterNativeView类,发现实现了FlutterNativeView调用了DartExecutor类的onAttachedToJNI方法,此方法定义如下:
void attach(FlutterNativeView view, boolean isBackgroundView) { 1 2 3 this.mFlutterJNI.attachToNative(isBackgroundView); this.dartExecutor.onAttachedToJNI(); }
attach方法在FlutterNativeView类的构造器中调用了。这样知道FlutterJNI类调用setPlatformMessageHandler方法了。 下面就看DartMessenger类的setMessageHandler方法在什么地方调用了。一直往回看,最终调用到了FlutterView.setMessageHandler方法,
1 2 3 4 @UiThread public void setMessageHandler(String channel, BinaryMessageHandler handler) { this.mNativeView.setMessageHandler(channel, handler); }
- 3.5 MethodChannel
下面我们从MethodChannel类看起,看看自定义的插件,是如何在被调用的。在自定义的Activity中,如果要让插件使用,需要在onCreate方法中,调用如下语句:
class MainActivity extends FlutterActivity { 1 2 3 4 5 6 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); GeneratedPluginRegistrant.registerWith(this); } }
最终调用到了我的自定义插件JdmaFlutterPlugin,在此插件中创建了MethodChannel对象,并且此对象调用了setMethodCallHandler方法,代码如下:
class JdmaFlutterPlugin implements MethodChannel.MethodCallHandler { 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 private static final String TAG = "JDMAPlugin"; private String account; private Context context; private boolean isDebug = false; private static final String CHANNEL_NAME = "xxx"; public static void registerWith(PluginRegistry.Registrar registrar) { final MethodChannel channel = new MethodChannel(registrar.messenger(), CHANNEL_NAME); channel.setMethodCallHandler(new JdmaFlutterPlugin(registrar.context())); } private JdmaFlutterPlugin(Context context) { this.context = context; } @Override public void onMethodCall(MethodCall methodCall, MethodChannel.Result result) { switch (methodCall.method) { case "setDebug": isDebug = (Boolean) methodCall.arguments; JDMaInterface.setShowLog(isDebug); result.success(null); break;
在接着往下看,MethodChannel类定义如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 public final class MethodChannel { private static final String TAG = "MethodChannel#"; private final BinaryMessenger messenger; private final String name; private final MethodCodec codec; public MethodChannel(BinaryMessenger messenger, String name) { this(messenger, name, StandardMethodCodec.INSTANCE); } ...... @UiThread public void setMethodCallHandler(@Nullable MethodChannel.MethodCallHandler handler) { this.messenger.setMessageHandler(this.name, handler == null ? null : new MethodChannel.IncomingMethodCallHandler(handler)); } ......
现在重点是BinaryMessenger对象,最终实现PluginRegistry接口的类发现是FlutterView类,FlutterView类实现了BinaryMessenger接口,这恰好找到了3.4节最后FlutterView调用setMessageHandler的地方。
总结