本文基于Flutter 3.19.3版别进行开发

Flutter 3.19.3 • channel stable • github.com/flutter/flu…
Framework • revision ba39319843 (8 days ago) • 2024-03-07 15:22:21 -0600
Engine • revision 2e4ba9c6fb
Tools • Dart 3.3.1 • DevTools 2.31.1

本篇为Flutter基建的第十三篇文章,本篇文章首要介绍在Flutter中怎么经过插件的方式进行Android和iOS原生的交互操作,详细会分为两部分,其间一部分Flutter运用MethodChannel从原生端中获取信息,另一部分则是原生端经过EventChannel向Flutter端主动发送音讯,下面让咱们一同进入文章感触下吧~

Flutter基建 - 运用插件和原生Android、iOS交互

Flutter基建系列文章

运用MethodChannel获取音讯

MethodChannel首要作用便是Flutter层向原生层面获取音讯,原生层归于一个被迫的状况,当收到Flutter层传递获取的详细办法时,能够依据详细的办法和参数向Flutter层传递对应的音讯。下面咱们介绍MethodChannel的用法过程中,以获取Android和iOS体系版别为例,来直观的感触下MethodChannel的详细逻辑。

Flutter层界说MethodChannel

首要咱们在Flutter层面界说好MethodChannel目标,它需求接收一个name参数,这个参数仍是挺重要的,Flutter层和原生层便是经过name来匹配对应的通道。

class _MyHomePageState extends State<MyHomePage> {
  final methodChannel = const MethodChannel("version_channel");
  String _version = "";
  @override
  void initState() {
    super.initState();
    getVersion();
  }
  Future<void> getVersion() async {
    String version = await methodChannel.invokeMethod("getVersion");
    setState(() {
      _version = version;
    });
  }
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              'Version Info: $_version',
            ),
          ],
        ),
      ),
    );
  }
}

上述代码在第二行咱们进行了MethodChannel目标的界说,然后在initState()办法中调用了一个getVersion()办法,它内部便是经过MethodChannel来衔接原生层,经过对应的办法名来获取需求的信息,这儿需求留意的一点便是methodChannel.invokeMethod()办法是一个异步函数,大家在调用的时候略微留意一下,加上await等候即可。

methodChannel.invokeMethod()办法除了传入办法名以外,还能够经过可选参数arguments来传入指定的参数,然后在原生层获取即可。

Flutter层界说好管道和调用的办法之后,咱们就能够在Android或许iOS原生层进行办法的详细完成了,接着咱们以Android端为例(由于手头没有ios设备…..)

Android端完成音讯传递

无论是Android端仍是iOS端,也仍是以MethodChannel为主,它能够协助咱们处理管道对应的办法,然后进行音讯传递。

class MainActivity : FlutterActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        flutterEngine?.dartExecutor?.let {
            MethodChannel(it, "version_channel").setMethodCallHandler { call, result ->
                if (call.method == "getVersion") {
                    result.success("Android ${Build.VERSION.RELEASE}")
                }
            }
        }
    }
}

全体上来看,Android端的代码仍是比较简单的,经过创立一个MethodChannel目标,内部需求传入BinaryMessenger和name,这儿的BinaryMessenger能够经过flutterEngine获取到,然后name参数有必要和Flutter层保持一致,不然会提示找不到对应的MethodChannel。

界说好MethodChannel目标之后,直接调用它的setMethodCallHandler()办法即可,在回调中能够经过call获取经过对应的办法名和参数等信息,详细如下:

Flutter基建 - 运用插件和原生Android、iOS交互

回调的result能够协助咱们将对应的音讯传递给Flutter层,可运用result.success()来传递正常的音讯,也能够经过result.error()来通知Flutter层音讯传递失利。

这儿留意一下, 在写完Android端代码之后,记得保存一下,不然运转会不生效,不知道小伙伴会不会出现相同的问题,欢迎沟通交流~

最终咱们来运转看下效果:

Flutter基建 - 运用插件和原生Android、iOS交互

运用EventChannel获取音讯

介绍完MethodChannel用法之后,咱们再来看下EventChannel的详细运用逻辑,它和MethodChannel最大的区别便是原生层在其间归于一个主动的角色,它能够自意向Flutter传递一些需求的音讯,当Flutter开始接收时,原生层就能够依据通道名来向此通道继续的发送音讯,下面咱们以定时器为例,完成一个Android端向Flutter层发送计时的一个小例子。

Flutter层界说EventChannel

直接上完好代码,后面咱们跟着代码一同了解下。

class _MyHomePageState extends State<MyHomePage> {
  final eventChannel = const EventChannel("count_channel");
  StreamSubscription? _streamSubscription;
  int count = 0;
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text('Count: $count'),
            TextButton(
              onPressed: () {
                registerEventChannel();
              },
              child: const Text("注册EventChannel")),
            TextButton(
              onPressed: () {
                unRegisterEventChannel();
              },
              child: const Text("解注册EventChannel")),
          ],
        ),
      ),
    );
  }
  void registerEventChannel() {
    _streamSubscription = eventChannel.receiveBroadcastStream().listen((event) {
      setState(() {
        count = event;
      });
    });
  }
  void unRegisterEventChannel() {
    if (_streamSubscription != null) {
      _streamSubscription!.cancel();
      _streamSubscription = null;
    }
  }
  @override
  void dispose() {
    super.dispose();
    unRegisterEventChannel();
  }
}

咱们先从第二行看,在这儿界说好了一个EventChannel目标,然后传入name参数,此name参数和MethodChannel作用一向,原生端要与其保持一致;

然后在下面第三行界说了一个StreamSubscription目标,它是EventChannel履行listen监听后发生的目标,可撤销和暂停监听操作;

然后在Widget中别离界说Text用于显现原生端传递过来的信息,两个TextButton别离用于履行注册监听和撤销监听;

在第34行的registerEventChannel()办法中,调用EventChannel.receiveBroadcastStream().listen()办法进行经过的监听,listen()办法中一共有四个参数:

  • onData()用于处理通道中传递过来的数据,这儿咱们直接将传递过来的count显现在界面上;
  • onError()用于处理通道中发生反常时场景;
  • onDone()办法则是表明通道被撤销监听或许原生端传递了done事件;
  • cancelOnError这个参数假如被赋值true之后,那么通道在发生反常时则会主动撤销监听。

接着在第42行unRegisterEventChannel()办法中咱们进行了通道的撤销监听操作。

接下来咱们再来看看Android端是怎么继续发送数据的:

Android端继续发送音讯

class MainActivity : FlutterActivity() {
    var count = 0
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        flutterEngine?.dartExecutor?.let {
            EventChannel(it, "count_channel").setStreamHandler(object : EventChannel.StreamHandler {
                override fun onListen(arguments: Any?, events: EventChannel.EventSink?) {
                    thread {
                        while (count < 20) {
                            runOnUiThread { events?.success(count++) }
                            Thread.sleep(1000L)
                        }
                    }
                }
                override fun onCancel(arguments: Any?) {
                    Log.d("taonce", "EventChannel onCancel")
                    count = 0
                }
            })
        }
    }
}

其实在EventChannel的运用场景下,Android端的代码就略微要简单一点了,只需求经过EventChannel目标的setStreamHandler()办法进行数据的传递即可,此办法需求传递一个EventChannel.StreamHandler回调,回调内部包含了onListen()onCancel()办法,传递需求能够在onListen()办法中处理,onCancel()办法则是表明Flutter端进行了撤销操作。

这儿不得不提一下,在原生端发送数据时线程问题,这儿需求在主线程中进行events.success() 操作,不然就会发生Crash问题~

最终咱们来运转下程序看看详细效果:

当咱们在第11s时点击解注册按钮之后,Android端就会收到onCancel回调。

写在最终

本篇文章首要介绍了Flutter中MethodChannel和EventChannel的基本运用,在Flutter的日常开发中,这两个常识点在运用频率和重要性上都是等级比较高的,希望经过文章给阅览的小伙伴们带来一点协助,后续会按部就班逐渐接触Flutter更多的常识。

我是Taonce,假如觉得本文对你有所协助,帮忙关注、赞或许收藏三连一下,谢谢~