【Flutter】三个Channel(Android-java / Ios-swift)

Channel

实现与原生通信

【1】MethodChannel

flutter MethodChannel官方文档

通过MethodChannel来传递数据,调用方法

案例

分别调用Android和Ios原生的获取电量的方法

Flutter端

实例一个MethodChannel, 唯一标识name,定义方法名称getBatteryLevel

methodchannel.invokeMethod(name)来调用方法

dart 复制代码
  static const platform = MethodChannel('sample.flutter.dev/battery');
  static const method = 'getBatteryLevel';
  String _batteryLevel = 'Unknown battery level';

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

界面操作

dart 复制代码
  @override
  Widget build(BuildContext context) {
    return Material(
      child: Column(
        mainAxisAlignment: MainAxisAlignment.spaceEvenly,
        children: [
          ElevatedButton(
            onPressed: _getBatteryLevel,
            child: const Text('Get Battery Level'),
          ),
          Text(_batteryLevel),
        ],
      ),
    );
  }
Android端
java 复制代码
    private static final String CHANNEL = "sample.flutter.dev/battery";
    private MethodChannel methodChannel;

    private static final String METHOD = "getBatteryLevel";

    @Override
    public void configureFlutterEngine(@NonNull FlutterEngine flutterEngine) {
        super.configureFlutterEngine(flutterEngine);
        BinaryMessenger binaryMessenger = flutterEngine.getDartExecutor().getBinaryMessenger();
        methodChannel = new MethodChannel(binaryMessenger, CHANNEL);
        methodChannel.setMethodCallHandler((call, result) -> {
            
        });
    }
java 复制代码
if (call.method.equals(METHOD)) {
                int batteryLevel = getBatteryLevel();
                if (batteryLevel != -1) {
                    result.success(batteryLevel);
                } else {
                    result.error("UNAVAILABLE", "Battery level not avaiable", null);
                }
            } else {
                result.notImplemented();
            }
java 复制代码
private int getBatteryLevel() {
        int batteryLevel = -1;
        if (VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            BatteryManager batteryManager = (BatteryManager) getSystemService(BATTERY_SERVICE);
            batteryLevel = batteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY);
        } else {
            IntentFilter intentFilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
            Intent intent = new ContextWrapper(getApplicationContext()).registerReceiver(null, intentFilter);
            batteryLevel = (intent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1) * 100) /
                    intent.getIntExtra(BatteryManager.EXTRA_SCALE, -1);
        }
        return batteryLevel;
    }
Ios端

实例FlutterMethodChannel

swift 复制代码
override func application(
    _ application: UIApplication,
    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
  ) -> Bool {
      let method : String = "getBatteryLevel"
      let controller : FlutterViewController = window?.rootViewController as! FlutterViewController
      let batteryChannel = FlutterMethodChannel(name: "sample.flutter.dev/battery", binaryMessenger: controller.binaryMessenger)
      batteryChannel.setMethodCallHandler({
          (call: FlutterMethodCall, result: @escaping FlutterResult) -> Void in
          guard call.method == method else {
              result(FlutterMethodNotImplemented)
              return
          }
          self.receiveBatteryLevel(result: result)
      })
      GeneratedPluginRegistrant.register(with: self)
      return super.application(application, didFinishLaunchingWithOptions: launchOptions)
  }

定义获取电量的方法

swift 复制代码
func receiveBatteryLevel(result: FlutterResult) -> Void {
        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))
        }
    }
运行测试

【2】EventChannel

墙外的参考文章

区别MethodChannel,它是continuously

采用event streams

案例

在原生端(Android&Ios)会有个计时器,不停的传时间给Flutter端,Flutter端显示出来

Flutter端

实例一个EventChannel,唯一标识name

dart 复制代码
  late EventChannel eventChannel;

  @override
  void initState() {
    eventChannel = const EventChannel('timeHandlerEvent');
    super.initState();
  }

在Flutter注册监听

dart 复制代码
Stream<String> get streamTimeFromNative =>
      eventChannel.receiveBroadcastStream().map((event) => event.toString());

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: StreamBuilder<String>(
          stream: streamTimeFromNative,
          builder: (BuildContext context, AsyncSnapshot<String> snapshot) {
            if (snapshot.hasData) {
              return Text(
                '${snapshot.data}',
                style: Theme.of(context).textTheme.headlineMedium,
              );
            } else {
              return const CircularProgressIndicator();
            }
          },
        ),
      ),
    );
  }
Ios端

实例一个FlutterEventChannel,加上唯一标识timeHandlerEvent

swift 复制代码
let controller : FlutterViewController = window?.rootViewController as! FlutterViewController
      let eventChannel = FlutterEventChannel(name: "timeHandlerEvent", binaryMessenger: controller.binaryMessenger)

定义FlutterStreamHandler

swift 复制代码
class TimeHandler: NSObject, FlutterStreamHandler {
        func onCancel(withArguments arguments: Any?) -> FlutterError? {
            return nil
        }
        
        func onListen(withArguments arguments: Any?, eventSink: @escaping FlutterEventSink) -> FlutterError? {
            return nil
        }
    }

每间隔1秒发送一次当前时间

swift 复制代码
    class TimeHandler: NSObject, FlutterStreamHandler {
        var timer = Timer()
        private var eventSink: FlutterEventSink?
        
        func onCancel(withArguments arguments: Any?) -> FlutterError? {
            eventSink = nil
            return nil
        }
        
        func onListen(withArguments arguments: Any?, eventSink: @escaping FlutterEventSink) -> FlutterError? {
            self.eventSink = eventSink
            self.timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true, block: {_ in 
                let dateFormat = DateFormatter()
                dateFormat.dateFormat = "HH:mm:ss"
                let time = dateFormat.string(from: Date())
                eventSink(time)
            })
            return nil
        }
    }

注册监听

swift 复制代码
eventChannel.setStreamHandler(TimeHandler())
Android端

new 一个EventChannel对象

在channel注册一个stream Handler

java 复制代码
        EventChannel.StreamHandler streamHandler = new EventChannel.StreamHandler() {
            @Override
            public void onListen(Object arguments, EventChannel.EventSink events) {
            }

            @Override
            public void onCancel(Object arguments) {
            }
        };
        eventChannel.setStreamHandler(streamHandler);

不断将当前时间返回

java 复制代码
EventChannel.StreamHandler streamHandler = new EventChannel.StreamHandler() {
            private final Handler handler = new Handler(Looper.getMainLooper());

            private EventChannel.EventSink eventSink = null;

            @Override
            public void onListen(Object arguments, EventChannel.EventSink events) {
                eventSink = events;
                Runnable runnable = new Runnable() {
                    @Override
                    public void run() {
                        Locale locale = new Locale("zh", "CN");
                        SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm:ss", locale);
                        String time = dateFormat.format(new Date());
                        events.success(time);
                        handler.postDelayed(this, 1000);
                    }
                };
                handler.postDelayed(runnable, 1000);
            }

            @Override
            public void onCancel(Object arguments) {
                eventSink = null;
            }
        };
        eventChannel.setStreamHandler(streamHandler);
运行测试

在建立好EventChannel之后,运行项目。

获取到当前的时间,并且不停的

【3】BasicMessageChannel

参考文章

约定一种数据格式,来互相传递数据

案例

传递Map数据到Android/Ios端,再解析并返回数据到Flutter端

Flutter端

构建BasicMessageChannel, 唯一标识name,约定数据格式StandardMessageCodec

dart 复制代码
static const messageChannel =
      BasicMessageChannel('basic_message_channel', StandardMessageCodec());

发送数据

dart 复制代码
Map<String, dynamic> message = {
                  "name": "apple",
                  "time": "2024-04-09 12:30:00"
                };
messageChannel.send(arguments)

接收数据

dart 复制代码
Map reply = await messageChannel.send(arguments) as Map;
Android 端

接收数据

java 复制代码
messageChannel.setMessageHandler((message, reply) -> {});

发送数据

java 复制代码
reply.reply(resultMap);
java 复制代码
package com.example.basic_message_channel_example;

import android.os.Bundle;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import java.sql.Timestamp;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

import io.flutter.embedding.android.FlutterActivity;
import io.flutter.embedding.engine.FlutterEngine;
import io.flutter.plugin.common.BasicMessageChannel;
import io.flutter.plugin.common.BinaryMessenger;
import io.flutter.plugin.common.StandardMessageCodec;

public class MainActivity extends FlutterActivity {

    @Override
    public void configureFlutterEngine(@NonNull FlutterEngine flutterEngine) {
        super.configureFlutterEngine(flutterEngine);
        BinaryMessenger binaryMessenger = Objects.requireNonNull(getFlutterEngine()).getDartExecutor().getBinaryMessenger();
        BasicMessageChannel<Object> messageChannel = new BasicMessageChannel<Object>(binaryMessenger, "basic_message_channel", StandardMessageCodec.INSTANCE);
        messageChannel.setMessageHandler((message, reply) -> {
            Map<Object, Object> arguments = (Map<Object, Object>) message;
            assert message != null;
            String name = (String) arguments.get("name");
            assert name != null;
            if (name.equals("apple")) {
                Map<String, Object> resultMap = new HashMap<>();
                String timeStr = (String) arguments.get("time");
                Timestamp timestamp = Timestamp.valueOf(timeStr);
                resultMap.put("message", "i eat the " + name + " at " + timestamp.toString());
                resultMap.put("code", 200);
                reply.reply(resultMap);
            } else {
                Map<String, Object> resultMap = new HashMap<>();
                resultMap.put("message", "i dislike " + name);
                resultMap.put("code", 500);
                reply.reply(resultMap);
            }
        });
    }
}
Ios 端

构建通道

swift 复制代码
let controller : FlutterViewController = window?.rootViewController as! FlutterViewController
let basicMessageChannel = FlutterBasicMessageChannel(name: channelName, binaryMessenger: controller.binaryMessenger)

接收数据

swift 复制代码
      basicMessageChannel.setMessageHandler { message, reply in
          
      }

返回数据

swift 复制代码
reply(result)
swift 复制代码
import UIKit
import Flutter

@available(iOS 15.0, *)
@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
  override func application(
    _ application: UIApplication,
    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
  ) -> Bool {
      let channelName : String = "basic_message_channel"
      let controller : FlutterViewController = window?.rootViewController as! FlutterViewController
      let basicMessageChannel = FlutterBasicMessageChannel(name: channelName, binaryMessenger: controller.binaryMessenger)
      basicMessageChannel.setMessageHandler { message, reply in
          if let data = message as? Dictionary<String, Any> {
              let name: String = data["name"] as? String ?? ""
              if name == "apple" {
                  let timeStr: String = data["time"] as? String ?? ""
                  var message: String = "I eat the "
                  message.append(name)
                  message.append(" at ")
                  message.append(timeStr)
                  let result = ["code": 200, "message": message]
                  reply(result)
              } else {
                  var message = "I dislike "
                  message.append(name)
                  let result = ["code": 500, "message": message]
                  reply(result)
              }
          }
      }
    GeneratedPluginRegistrant.register(with: self)
    return super.application(application, didFinishLaunchingWithOptions: launchOptions)
  }
}
运行测试




总结

MethodChannel 定义方法名调用

EventChannel 持续监听数据传递

BasicMessageChannel 约定一种数据格式,传递数据

相关推荐
安和昂1 小时前
【iOS】bug调试技巧
ios·bug·cocoa
恋猫de小郭1 小时前
IntelliJ IDEA 2024.3 K2 模式已发布稳定版,Android Studio Meerkat 预览也正式支持
android·android studio
emperinter1 小时前
WordCloudStudio Now Supports AliPay for Subscriptions !
人工智能·macos·ios·信息可视化·中文分词
AirDroid_cn2 小时前
iPhone或iPad接收的文件怎么找?怎样删除?
ios·iphone·ipad·文件传输
找藉口是失败者的习惯5 小时前
Jetpack Compose 如何布局解析
android·xml·ui
Swift社区8 小时前
在 Swift 中实现字符串分割问题:以字典中的单词构造句子
开发语言·ios·swift
#摩斯先生8 小时前
Swift从0开始学习 对象和类 day3
ios·xcode·swift
没头脑的ht8 小时前
Swift内存访问冲突
开发语言·ios·swift
#摩斯先生8 小时前
Swift从0开始学习 并发性 day4
ios·xcode·swift
没头脑的ht9 小时前
Swift闭包的本质
开发语言·ios·swift