preface

As mentioned in the previous article, after Android embedded flutter, it inherited FlutterActivity by custom Activity, and then rewrote some methods to open a FlutterActivity to achieve the desired effect. In this article we will talk about how the two interact, and also apply to pure Flutter projects, Flutter and native interaction

Embed the Flutter Module into Android Projects

Mainly through PlantformChannel interact, PlantformChannel there are three types of BasicMessageChannel, EventChannel, MethodChannel. Read this article for an in-depth understanding of Flutter Platform Channel

The body of the

BasicMessageChannel, mainly used for bidirectional string passing and semi-structured message passing messages

class BasicTestChannel(dartExecutor: DartExecutor) : MessageHandler<String> { private val tag: String = "BasicTestChannel" private val basicMessageChannel = BasicMessageChannel(dartExecutor, "com.zww/basic", StringCodec.INSTANCE) fun send(content: String, callback: Reply<String>) {basicMessageChannel. Send (content, callback) log. d(tag, "Android sends the contents of a flutter: $content") } init { basicMessageChannel.setMessageHandler(this) } override fun onMessage(message: String? , reply: Reply<String>) {log. d(tag, "Android received a message from flutter: $message") reply. Reply (" Android received a message from Flutter, $message content ")} fun removeMessageHandler () {basicMessageChannel. SetMessageHandler (null)}}Copy the code

OnMessage is a callback to a message sent by a Flutter. Call the reply method to reply a send message to a Flutter. The second argument is the callback to a Flutter response

use

class MyFlutterActivity : FlutterActivity() { private lateinit var basicTestChannel: BasicTestChannel override fun provideFlutterEngine(context: Context): FlutterEngine? { val flutterEngine = FlutterEngine(this, null, false); basicTestChannel = BasicTestChannel(flutterEngine.dartExecutor) return flutterEngine } override fun onStart() { super.onStart() basicTestChannel.send("Android To Flutter", Callback = BasicMessageChannel. Reply {the d (" basicTestChannel ", "android is sent to Flutter message received Reply, Reply content is: $it") }) } override fun shouldDestroyEngineWithHost(): Boolean { return true } override fun onDestroy() { basicTestChannel.removeMessageHandler() super.onDestroy() } override fun onFlutterUiDisplayed() { super.onFlutterUiDisplayed() Toast.makeText(this, "onFlutterUiDisplayed", Toast.LENGTH_LONG).show() } }Copy the code

** Flutter **

static const basicChannel = const BasicMessageChannel("com.zww/basic", StringCodec()); @override void initState() { basicChannel.setMessageHandler((message) => _handlePlatform(message)); super.initState(); } Future<String> _handlePlatform(String message) async {print(" Receive Native message: $message"); setState(() { _counter++; }); Future.delayed(const Duration(seconds: 3), () async {String result = await basicchannel. send("Flutter sends Android content: Flutter To Android"); Print (" $result"); }); Return "Received Native message: $message"; }Copy the code

SetMessageHandler Is an asynchronous listener that Android sends to a Flutter. The return value of the send method is also asynchronous. The return value of the send method is the reply that Android receives from the message, that is, the reply of Android

* * * * process

Android sends messages to a Flutter, which receives and returns a response to the received message. Three seconds later, Flutter actively sends a message to Android. Android receives the message and returns a reply. The log is as follows

D/BasicTestChannel: Android sends a flutter message: Android To flutter I/flutter: Android To Flutter D/basicTestChannel Android received a reply To a message sent To a Flutter. The reply is as follows: Android received a Native message To a Flutter D/BasicTestChannel: Android received a message To a Flutter: The message that a Flutter sends To Android is: Flutter To Android I/ Flutter: the message that a Flutter sends To Android is: Android receives a message from a flutter that contains the message "flutter To Android"Copy the code

Here’s an example of a hybrid scenario:

When the Android list page starts Flutter, it passes an itemId and specifies the route to the list details interface. The interface then receives this Id to request the details and load them

EventChannel

** is used to pass the event stream. 支那

class EventTestChannel(dartExecutor: DartExecutor) : EventChannel.StreamHandler { private var eventChannel: EventChannel = EventChannel(dartExecutor, "com.zww/event") init { eventChannel.setStreamHandler(this) } override fun onListen(arguments: Any? , events: EventChannel.EventSink?) { events? .success("1") events? .success("2") events? .success("3") events? .success("4") events? .error("1001", "This is error", "This is details") events? .endOfStream() events? .success("5") } override fun onCancel(arguments: Any?) { } fun removeStreamHandler() { eventChannel.setStreamHandler(null) } } class MyFlutterActivity : FlutterActivity() { private lateinit var eventTestChannel: EventTestChannel override fun provideFlutterEngine(context: Context): FlutterEngine? { val flutterEngine = FlutterEngine(this, null, false); eventTestChannel = EventTestChannel(flutterEngine.dartExecutor) return flutterEngine } override fun shouldDestroyEngineWithHost(): Boolean { return true } override fun onDestroy() { eventTestChannel.removeStreamHandler() super.onDestroy() } override fun onFlutterUiDisplayed() { super.onFlutterUiDisplayed() Toast.makeText(this, "onFlutterUiDisplayed", Toast.LENGTH_LONG).show() } }Copy the code

**Flutter **

static const eventChannel = const EventChannel("com.zww/event"); @override void initState() { super.initState(); basicChannel.setMessageHandler((message) => _handlePlatform(message)); EventChannel. ReceiveBroadcastStream (). Listen ((event) {print (" event received value is $event "); }, onError: (Object error, StackTrace stackTrace) => print("onError: $error $stackTrace"), onDone: () => print("onDone"), ); }Copy the code

** Log**

I/flutter: event Received value 1. I/flutter: Event received value 2. Event Received value 3. Event Received value 4. PlatformException(1001, This is error, This is details) I/flutter: onDoneCopy the code

MethodChannel

** is used to pass method calls and is the more common PlatformChannel**

Here’s how Flutter calls Android methods. Take Toast for example

class ToastChannel(context: Context, dartExecutor: DartExecutor) : MethodChannel.MethodCallHandler { private val mContext: Context = context private val methodChannel: MethodChannel = MethodChannel(dartExecutor, "com.zww/toast") init { methodChannel.setMethodCallHandler(this) } override fun onMethodCall(call: MethodCall, result: MethodChannel.Result) { when (call.method) { "show" -> { val content: String? = call.argument("content") Toast.makeText(mContext, content, Toast.LENGTH_SHORT) .show() result.success(null) } } } fun removeMethodCallHandler() { methodChannel.setMethodCallHandler(null) } } class MyFlutterActivity : FlutterActivity() { private lateinit var toastChannel: ToastChannel override fun provideFlutterEngine(context: Context): FlutterEngine? { val flutterEngine = FlutterEngine(this, null, ToastChannel = toastChannel (this.context, flutterEngine.dartExecutor) return flutterEngine } override fun shouldDestroyEngineWithHost(): Boolean { return true } override fun onFlutterUiDisplayed() { super.onFlutterUiDisplayed() Toast.makeText(this, "onFlutterUiDisplayed", Toast.LENGTH_LONG).show() } override fun onDestroy() { toastChannel.removeMethodCallHandler() super.onDestroy() } }Copy the code

** flutter **

 static const toastChannel = const MethodChannel("com.zww/toast");
  int _counter = 0;
  void _incrementCounter() {
    setState(() {
      _counter++;
    });

    toastChannel.invokeMethod(
        "show", {"content": "Flutter Module Call  ToastPlugin's show method"});
  }
Copy the code

conclusion

We can learn from this article

  • How do Android and Flutter interact
  • The article recommended by the head of the article suggests that we must go to see