flutter 写平台相关的代码

198 阅读2分钟

0、概述

一、BasicMessageChannel

class BasicMessageChannel<T> {
     /// The logical channel on which communication happens, not null.
    final String name;

    /// The message codec used by this channel, not null.
    final MessageCodec<T> codec;
    
    /// The messenger which sends the bytes for this channel, not null.
    final BinaryMessenger? _binaryMessenger;
    
    /// Creates a [BasicMessageChannel] with the specified [name], [codec] and [binaryMessenger].
    ///
    /// The [name] and [codec] arguments cannot be null. The default [ServicesBinding.defaultBinaryMessenger]
    /// instance is used if [binaryMessenger] is null.
    const BasicMessageChannel(this.name, this.codec, { BinaryMessenger? binaryMessenger }) : assert(name != null),  assert(codec != null), _binaryMessenger = binaryMessenger;

    BinaryMessenger get binaryMessenger => _binaryMessenger ?? ServicesBinding.instance!.defaultBinaryMessenger;
}

通用的平台侧交互类,该类实现的功能: 编码数据、发送数据、解码接收到的数据。

二、MethodChannel

class MethodChannel {
    /// Creates a [MethodChannel] with the specified [name].
    /// The [codec] used will be [StandardMethodCodec], unless otherwise
    /// specified.
    /// The [name] and [codec] arguments cannot be null. The default [ServicesBinding.defaultBinaryMessenger]
    /// instance is used if [binaryMessenger] is null.
    const MethodChannel(this.name, [this.codec = const StandardMethodCodec(), BinaryMessenger? binaryMessenger ])
    : assert(name != null),
    assert(codec != null),
    _binaryMessenger = binaryMessenger;

    /// The logical channel on which communication happens, not null.
    final String name;

    /// The message codec used by this channel, not null.
    final MethodCodec codec;

    /// The messenger used by this channel to send platform messages.
    /// The messenger may not be null.

    BinaryMessenger get binaryMessenger => _binaryMessenger ?? ServicesBinding.instance!.defaultBinaryMessenger;
    final BinaryMessenger? _binaryMessenger;

    // 关键函数,比BasicMessageChannel多的功能
    @optionalTypeArgs
    Future<T?> _invokeMethod<T>(String method, { required bool missingOk, dynamic arguments }) async {
        assert(method != null);
        // 编码数据,并发送
        final ByteData? result = await binaryMessenger.send(
                                    name,
                                    codec.encodeMethodCall(MethodCall(method, arguments)),
                                    );
        if (result == null) {
            if (missingOk) {
                return null;
            }
            throw MissingPluginException('No implementation found for method $method on channel $name');
        }
        // 解码数据,返回
        return codec.decodeEnvelope(result) as T?;
    }
    
    @optionalTypeArgs
    Future<T?> invokeMethod<T>(String method, [ dynamic arguments ]) {
        return _invokeMethod<T>(method, missingOk: false, arguments: arguments);
    }
    
    
    void setMethodCallHandler(Future<dynamic> Function(MethodCall call)? handler) {
    _methodChannelHandlers[this] = handler;
    
    binaryMessenger.setMessageHandler(
      name,
      handler == null
        ? null
        : (ByteData? message) => _handleAsMethodCall(message, handler),
    );
    }
}

该类支持发送方法消息。

三、调用平台侧函数的流程

1、flutter 调用平台侧函数


static const platform = MethodChannel('samples.flutter.dev/battery');
 
// Get battery level.
String _batteryLevel = 'Unknown battery level.';

Future<void> _getBatteryLevel() async {
  String batteryLevel;
  try {
    final int result = await platform.invokeMethod('getBatteryLevel');
    batteryLevel = 'Battery level at $result % .';
  } on PlatformException catch (e) {
    batteryLevel = "Failed to get battery level: '${e.message}'.";
  }

  setState(() {
    _batteryLevel = batteryLevel;
  });
}

2、IOS侧的代码

@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
  override func application(
    _ application: UIApplication,
    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {

    let controller : FlutterViewController = window?.rootViewController as! FlutterViewController
    // 创建逻辑通道
    let batteryChannel = FlutterMethodChannel(name: "samples.flutter.dev/battery",
                                              binaryMessenger: controller.binaryMessenger)
                                              
                                              
    // 注册收到方法调用的回调
    batteryChannel.setMethodCallHandler({
      [weak self] (call: FlutterMethodCall, result: FlutterResult) -> Void in
      // This method is invoked on the UI thread.
      guard call.method == "getBatteryLevel" else {
        result(FlutterMethodNotImplemented)
        return
      }
      self?.receiveBatteryLevel(result: result)
    })

    //注册插件,当查找getBatteryLevel方法的会后,从当前类中查找
    GeneratedPluginRegistrant.register(with: self)
    return super.application(application, didFinishLaunchingWithOptions: launchOptions)
  }
}

在AppDelegate.swift 中添加下面的方法:

private func receiveBatteryLevel(result: FlutterResult) {
  let device = UIDevice.current
  device.isBatteryMonitoringEnabled = true
  if device.batteryState == UIDevice.BatteryState.unknown {
    result(FlutterError(code: "UNAVAILABLE",
                        message: "Battery level not available.",
                        details: nil))
  } else {
    result(Int(device.batteryLevel * 100))
  }
}