Flutter與Android原生混合開發——EventChannel與MethodChannel的使用

在使用Flutter開發app時,會遇到跟Android原生系統API交互的情況,
通常可以使用Flutter來寫頁面,複用原來已有的Android的邏輯(如自己的或者第三方的SDK),來加快開發進度。
可以使用插件來解決,官網關於插件的開發介紹:
撰寫雙端平臺代碼(插件編寫實現)

文中列出了一個完整的demo:
注意:可在 /examples/platform_channel/ 中獲得使用 Java 實現的 Android 及使用 Objective-C 實現的 iOS 的該示例完整可運行的代碼。對於用 Swift 實現的 iOS 代碼,請參閱 /examples/platform_channel_swift/


Channel

Flutter定義了三種不同類型的Channel,它們分別是

  • BasicMessageChannel:用於傳遞字符串和半結構化的信息,可以雙向的請求數據。
  • MethodChannel:用於傳遞方法調用(method invocation,即Flutter端可以調用Platform端的方法並通過Result接口回調結果數據。
  • EventChannel: 用於數據流(event streams)的通信,即Flutter端監聽Platform端的實時消息,一旦Platform端產生了數據,立即回調到Flutter端。

⚠️注意:在Android和iOS平臺上,Platform Task Runner跑在主線程上。因此,不應該在Platform端的Handler中處理耗時操作。

先看一下MethodChannel和EventChannel的使用
main.dart文件如下:

class PlatformChannel extends StatefulWidget {
  @override
  _PlatformChannelState createState() => _PlatformChannelState();
}

class _PlatformChannelState extends State<PlatformChannel> {
  static const MethodChannel methodChannel =
      MethodChannel('samples.flutter.io/battery');
  static const EventChannel eventChannel =
      EventChannel('samples.flutter.io/charging');

  String _batteryLevel = 'Battery level: unknown.';
  String _chargingStatus = 'Battery status: unknown.';

  Future<void> _getBatteryLevel() async {
    String batteryLevel;
    try {
      final int result = await methodChannel.invokeMethod('getBatteryLevel');
      batteryLevel = 'Battery level: $result%.';
    } on PlatformException {
      batteryLevel = 'Failed to get battery level.';
    }
    setState(() {
      _batteryLevel = batteryLevel;
    });
  }

  @override
  void initState() {
    super.initState();
    eventChannel.receiveBroadcastStream().listen(_onEvent, onError: _onError);
  }

  void _onEvent(Object event) {
    setState(() {
      _chargingStatus =
          "Battery status: ${event == 'charging' ? '' : 'dis'}charging.";
    });
  }

  void _onError(Object error) {
    setState(() {
      _chargingStatus = 'Battery status: unknown.';
    });
  }

  @override
  Widget build(BuildContext context) {
    return Material(
      child: Column(
        mainAxisAlignment: MainAxisAlignment.spaceEvenly,
        children: <Widget>[
          Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              Text(_batteryLevel, key: const Key('Battery level label')),
              Padding(
                padding: const EdgeInsets.all(16.0),
                child: RaisedButton(
                  child: const Text('Refresh'),
                  onPressed: _getBatteryLevel,
                ),
              ),
            ],
          ),
          Text(_chargingStatus),
        ],
      ),
    );
  }
}

void main() {
  runApp(MaterialApp(home: PlatformChannel()));
}

1. 使用MethodChannel步驟

  • 其中定義了一個MethodChannel對象,使用methodChannelinvokeMethod('getBatteryLevel')方法可以調用到Android原生的方法,
  • 在Android定義MethodChannel對象,並調用其setMethodCallHandler方法,在回調接口MethodCallHandler中實現onMethodCall方法,通過Result對象回傳值到Flutter端。
  private static final String BATTERY_CHANNEL = "samples.flutter.io/battery";



    new MethodChannel(getFlutterView(), BATTERY_CHANNEL).setMethodCallHandler(
        new MethodCallHandler() {
          @Override
          public void onMethodCall(MethodCall call, Result result) {
            if (call.method.equals("getBatteryLevel")) {
              int batteryLevel = getBatteryLevel();

              if (batteryLevel != -1) {
                result.success(batteryLevel);
              } else {
                result.error("UNAVAILABLE", "Battery level not available.", null);
              }
            } else {
              result.notImplemented();
            }
          }
        }
    );

在該MethodCallHandler回調中處理Flutter部分發來的方法調用請求,並通過result.success(batteryLevel)傳遞迴數據。

這是直接能獲取到Android端立即返回值的情況,但是通常Android端是異步操作,並在接口回調中返回值,那這時如何將值再傳遞到Flutter端呢?這時就可以使用EventChannel了。

2. 使用EventChannel步驟

  • 在Android端定義EventChannel對象,並調用setStreamHandler()方法,在匿名內部類StreamHandler裏實現onListen和onCancel方法,通過EventSink對象來回傳數據到Flutter端,
  • Flutter端通過 eventChannel.receiveBroadcastStream().listen(_onEvent, onError: _onError);來定義_onEvent函數和_onError函數處理傳回的值。
  new EventChannel(getFlutterView(), CHARGING_CHANNEL).setStreamHandler(
        new StreamHandler() {
          private BroadcastReceiver chargingStateChangeReceiver;
          @Override
          public void onListen(Object arguments, EventSink events) {
            chargingStateChangeReceiver = createChargingStateChangeReceiver(events);
            registerReceiver(
                chargingStateChangeReceiver, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
          }

          @Override
          public void onCancel(Object arguments) {
            unregisterReceiver(chargingStateChangeReceiver);
            chargingStateChangeReceiver = null;
          }
        }
    );

3. 使用BasicMessageChannel步驟

Android端:
在這裏插入圖片描述
dart端:

在這裏插入圖片描述

參考:
Flutter Platform channel詳解
深入理解Flutter Platform Channel

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章