颤音:与本地平台进行沟通
#android #flutter #ios #crossplatform

Flutter 是跨平台应用程序的理想工具。您可以轻松地制作出具有颤动的表演剂和美丽的应用程序。但是,为了访问本机平台API,您需要与本机平台进行通信。 Flutter只能理解DART语言,而本地平台只能理解其各自的编程语言。那么,颤动和本地平台如何相互通信?它必须是扑朔迷离和本机平台的语言。那么,用来互相交流的是什么?

猜测

Photo by [Markus Winkler](https://unsplash.com/@markuswinkler?utm_source=medium&utm_medium=referral) on [Unsplash](https://unsplash.com?utm_source=medium&utm_medium=referral)

如果您猜到了,二进制,那么您猜对了。

Flutter通过传递二进制消息与本机平台进行对话。为了区分消息,使用了频道。那么我们如何通过平台发送这些二进制消息?

我们可以利用BinaryMessenger类在平台上发送消息。

BinaryMessenger类是Flutter团队定义的Messenger类,它在整个Flutter Platform屏障上发送二进制数据。该课程还注册了传入消息的处理程序。

下面的代码使用binarymessenger通过频道向平台发送二进制消息。

import 'dart:convert'; 
import 'package:flutter/services.dart';
import 'dart:ui' as ui; 

class CustomBinaryMessenger {

  // A static method for sending a given value as a binary message.
  static Future<void> givenValue(String data) async {
    // Create a buffer to hold the binary data.
    final WriteBuffer buffer = WriteBuffer();

    // Convert the given data string into UTF-8 bytes.
    final List<int> utf8Bytes = utf8.encode(data);

    // Convert the UTF-8 bytes into an Uint8List.
    final Uint8List utf8Int8List = Uint8List.fromList(utf8Bytes);

    // Put the Uint8List into the buffer.
    buffer.putUint8List(utf8Int8List);

    // Get the final binary message data from the buffer.
    final ByteData message = buffer.done();

    // Send the binary message using the 'Messenger' class through chaneel `foo`.
    await Messenger().send('foo', message);

    return;
  }
}

// A custom implementation of the BinaryMessenger interface. I am only handling
// send here for the sake of example
class Messenger implements BinaryMessenger {
  @override
  // Handle incoming platform messages. In this case, it throws an unsupported error.
  Future<void> handlePlatformMessage(
      String channel, ByteData? data, PlatformMessageResponseCallback? callback) {
    throw UnsupportedError("This platform message handling is not supported.");
  }

  @override
  // Send a binary message to the platform using the 'ui.PlatformDispatcher'.
  Future<ByteData?>? send(String channel, ByteData? message) {
    // Use the 'ui.PlatformDispatcher' to send the platform message and handle the callback
    ui.PlatformDispatcher.instance.sendPlatformMessage(channel, message, (data) {});

    return null;
  }

  @override
  // Set a handler for incoming messages. In this case, it throws an unsupported error.
  void setMessageHandler(String channel, MessageHandler? handler) {
    throw UnsupportedError("Setting message handler is not supported.");
  }
}

现在在Android上,您可以使用以下代码接收:

class MainActivity : FlutterActivity() {

    override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
        super.configureFlutterEngine(flutterEngine)

        // Configure the binary messenger to handle messages from Flutter.
        flutterEngine.dartExecutor.binaryMessenger.setMessageHandler("foo") { message, reply ->
        message?.order(ByteOrder.nativeOrder()) // Ensure proper byte order.
        val data = decodeUtf8String(message!!) // Decode the binary data to UTF-8 string.
        val x = message.toString() // Convert the message to a string for demonstration.
        // Display a Toast with the received message.
        Toast.makeText(this, "Received message from Flutter: $data", Toast.LENGTH_SHORT).show()
        reply.reply(null)
        }

        // Call the super method to finalize the FlutterEngine configuration.
        super.configureFlutterEngine(flutterEngine)
    }

    // Function to decode a ByteBuffer into a UTF-8 string.
    private fun decodeUtf8String(byteBuffer: ByteBuffer): String {
        return try {
            val byteArray = ByteArray(byteBuffer.remaining())
            byteBuffer.get(byteArray)
            String(byteArray, Charsets.UTF_8)
        } catch (e: Exception) {
            e.printStackTrace()
            ""
        }
    }
}

类似于iOS,

import UIKit
import Flutter

@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
  override func application(
    _ application: UIApplication,
    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
  ) -> Bool {
      let flutterViewController = self.window.rootViewController as! FlutterViewController

      // Configure the binary messenger to handle messages from Flutter.
      let binaryMessenger = flutterViewController.engine!.binaryMessenger
      binaryMessenger.setMessageHandlerOnChannel("foo", binaryMessageHandler: { [weak self] message, reply in
          // Ensure proper byte order.
           guard let message = message else {
               reply(nil)
               return
           }
           // Decode the binary data to UTF-8 string.
           if let data = String(data: message, encoding: .utf8) {
               let x = message.debugDescription // Convert the message to a string for demonstration.
               // Display an alert with the received message.
               let alertController = UIAlertController(
                   title: "Message from Flutter",
                   message: data,
                   preferredStyle: .alert
               )
               alertController.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
               flutterViewController.present(alertController, animated: true, completion: nil)
           }
           reply(nil)
      }
    )

      GeneratedPluginRegistrant.register(with: self)
    return super.application(application, didFinishLaunchingWithOptions: launchOptions)
  }

    // Function to decode a ByteBuffer into a UTF-8 string.
    private func decodeUtf8String(byteBuffer: FlutterStandardTypedData) -> String? {
            let byteArray = [UInt8](byteBuffer.data)
            return  String(bytes: byteArray, encoding: .utf8)
    }
}

交流是双向的,您可以从本机平台发送到扑朔迷离。确保在我们的类Messenger中实现setMessageHandler,以从本机平台接收二进制消息并解码它们。只需扭转我们的代码流,您就可以发送:
在iOS中,使用

// Send a binary message from platform to the flutter. It takes channel and message
// as params
flutterViewController.engine!.binaryMessenger.send(onChannel: <#T##String#>, message: <#T##Data?#>)

在Android中,使用

// Send a binary message from platform to the flutter.It takes channel and message
// as params
flutterEngine.dartExecutor.binaryMessenger.send()

消息和响应是异步传递的,以确保用户界面保持响应能力。

现在,您可以将消息从颤动传递到本机平台,反之亦然。但是,如您所见,我们必须担心编码,解码和处理寄存器等。它可以导致详细代码并增加代码的复杂性。那么,解决方案是什么?

平台频道:使上述过程更容易导致平台频道。平台频道是结合频道名称和编解码器的构造。这种配对使消息可以转换为二进制格式,以进行传输,并在接收时促进其从二进制格式的转换。它使使用本机平台的工作变得更加容易。

查看一个名为MethodChannel的平台频道。如果您查看代码,可以看到它处理自己的binarymessenger。

在我的下一篇文章中,我们将查看平台频道,以及如何使用它将消息从颤音传递到本机平台,反之亦然。


保持好奇心,不要错过下一篇文章。