前言

在前面的文章中我们讲了许多Flutter中的组件和Flutter中的特定操作,但是单单使用Flutter里的组件和方法是不够的。

就像以前我们讲到文件存储、数据库操作单单靠使用Flutter我们是不能完成的,因为这些数据最终需要存储在特定的终端平台上,我们需要通过特点的代码来实现与特点的平台交互,所以我们引入了第三方库来完成这些操作。

当然,这些第三方库帮我们实现了与不同平台交互的代码,所以我们不需要自己再去自己去编写这些与特定平台交互的代码。

当时我们你不可能一直使用人家的第三方库啊,一些特定的功能是没人能帮你的,所以我们还是很有必要来学习下如何跟特定的平台交互的

原谅我不会Object C ,不会Ios开发,这里仅仅以Android为例来做今天的例子

平台通道

lutter使用了一个灵活的系统,允许您调用特定平台的API,无论在Android上的Java或Kotlin代码中,还是iOS上的ObjectiveC或Swift代码中均可用。

Flutter平台特定的API支持不依赖于代码生成,而是依赖于灵活的消息传递的方式:

应用的Flutter部分通过平台通道(platform channel)将消息发送到其应用程序的所在的宿主(iOS或Android)。

宿主监听的平台通道,并接收该消息。然后它会调用特定于该平台的API(使用原生编程语言) - 并将响应发送回客户端,即应用程序的Flutter部分。

用平台通道在客户端(Flutter UI)和宿主(平台)之间传递消息,如下图所示:

在客户端,MethodChannel 可以发送与方法调用相对应的消息。 在宿主平台上,MethodChannel 在Android((API) 和 FlutterMethodChannel iOS (API) 可以接收方法调用并返回结果。这些类允许您用很少的“脚手架”代码开发平台插件。

接下来我们来个例子看看

调用Android平台Toast

在自前面我们可以很清楚的看到在Android平台我们需要借助于MethodChannel来与Android平台代码交互。我们通过代码来讲解下如何使用

import 'dart:async';import 'package:flutter/material.dart';
import 'package:flutter/services.dart';void main() {runApp(MaterialApp(home: MyApp(),));
}class MyApp extends StatelessWidget {static const platform = const MethodChannel("com.flyou.test/android");showToast(String msg) async {try {await platform.invokeMethod("showToast",{"msg":msg});} on PlatformException catch (e) {print(e.toString());}}@overrideWidget build(BuildContext context) {return Scaffold(appBar: AppBar(title: Text("platformChannels"),),body:  Center(child: RaisedButton(child: Text("点我提示"),onPressed: () {showToast("我是android系统的toast");},),),);}
}

首先我们需要在我们的Dart代码中定义我们的想要调用的通道

static const platform = const MethodChannel("com.flyou.test/android");

当然这个频道的名字是可以自己定义的的,但是必须要要和一会在Android MainActivity中使用的一致。

然后,我们同个通道来调用在Android平台定义的方法

showToast(String msg) async {try {await platform.invokeMethod("showToast",{"msg":msg});} on PlatformException catch (e) {print(e.toString());}}

我们使用

platform.invokeMethod(“showToast”,{“msg”:msg})

来调用我们在Android平台定义的“showToast”方法

接下来,我们来看下我们在Android Activity做了哪些事情

package com.yourcompany.test1;import android.os.Bundle;
import android.text.TextUtils;
import android.widget.Toast;
import io.flutter.app.FlutterActivity;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;
import io.flutter.plugins.GeneratedPluginRegistrant;public class MainActivity extends FlutterActivity {private static final String CHANNEL = "com.flyou.test/android";@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);GeneratedPluginRegistrant.registerWith(this);new MethodChannel(getFlutterView(), CHANNEL).setMethodCallHandler((call, result) -> {System.out.println(call.method);if (call.method.equals("showToast")) {if (call.hasArgument("msg") && !TextUtils.isEmpty(call.argument("msg").toString())) {Toast.makeText(MainActivity.this, call.argument("msg").toString(), Toast.LENGTH_SHORT).show();} else {Toast.makeText(MainActivity.this, "toast text must not null", Toast.LENGTH_SHORT).show();}}});}
}

首先我们也定义了一个跟dart文件中一样的”com.flyou.test/android”

然后我们创建了一个MethodChannel对象并对回调多了处理,当回调中参数的method方法和我们在dart中定义的一样时,我们就调用Android平台的Toast方法弹出吐司,如果msg为空则弹出toast text must not null的吐司。

当我们点击flutter程序中的按钮时,就会触发调用Android系统的Toast回调。

看下效果:

从Android平台获取数据

和上面的类似,我们可以调用系统的方法,我们同样刻印调用我们自己写的方法并且返回调用方法的值,那么我们还是举个例子看下吧。

我们通过flutter调用Android平台的方法获取当前格式化好的时间。

同样的我们还是用用和刚才一样的通道,只不过这一次我们需要更改我们调用的方法即可。

import 'dart:async';import 'package:flutter/material.dart';
import 'package:flutter/services.dart';void main() {runApp(MaterialApp(home: MyApp(),));
}class MyApp extends StatelessWidget {static const platform = const MethodChannel("com.flyou.test/android");Future<String> getAndroidTime() async {var str;try {str = await platform.invokeMethod("getAndroidTime");} on PlatformException catch (e) {print(e.toString());}return str;}@overrideWidget build(BuildContext context) {return Scaffold(appBar: AppBar(title: Text("platformChannels"),),body: new Center(child: new Builder(builder: (BuildContext context) {return new RaisedButton(onPressed: () {getAndroidTime().then((str){Scaffold.of(context).showSnackBar(new SnackBar(content:Text(str!=null?str:"获取失败")));});},child: Text("点我获取Android平台数据"),);}),),);}
}

我们使用一个泛型为String的Future对象来接收Androd平台传来的字符串信息。然后调用then来显示字符串

在MainActivity中我们定义一个getCurrentTime的方法,当触发方法名为getAndroidTime时调用改方法并返回给Flutter调用处

下面就是效果了:

获取系统回调与监听

在前面的Flutter与平台的交互图上我们可以看到,使用MethodChannel可以调用原生平台的方法,在上面的例子中我们呢也给大家演示了如何使用,但是我们如何获取原生平台的监听与回调呢?类似于Android中的广播我们如何在Flutter接收到呢?

下面我们就需要来看下EventChannel了,借助于EventChannel(事件通道)我们可以很轻易的接收平台事件监听的回调。

那么我们还是举个例子,以Android平台网络变化为例,每当网络变化时就会触发Android本地的广播,然后通过EventChannel通知给Flutter组件中,这时候只要我们在Flutter注册相应的EventChannel就可以实现对网络变化事件的监听。

下面我们首先看下ManActivity方法中是怎么做的

package com.yourcompany.test1;import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.Bundle;
import android.util.Log;
import io.flutter.app.FlutterActivity;
import io.flutter.plugin.common.EventChannel;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;
import io.flutter.plugins.GeneratedPluginRegistrant;public class MainActivity extends FlutterActivity {private static final String CHANNEL = "com.flyou.test/android";private static final String NET_CHANGE_CHANNEL = "com.flyou.test/netChanged";@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);GeneratedPluginRegistrant.registerWith(this);new MethodChannel(getFlutterView(), CHANNEL).setMethodCallHandler(new MethodChannel.MethodCallHandler() {@Overridepublic void onMethodCall(MethodCall call, MethodChannel.Result result) {System.out.println(call.method);if (call.method.equals("netConnection")) {boolean networkConnected = NetUtil.isNetworkConnected(getApplicationContext());result.success(networkConnected);}else if (call.method.equals("showToast")) {if (call.hasArgument("msg") && !TextUtils.isEmpty(call.argument("msg").toString())) {Toast.makeText(MainActivity.this, call.argument("msg").toString(), Toast.LENGTH_SHORT).show();} else {Toast.makeText(MainActivity.this, "toast text must not null", Toast.LENGTH_SHORT).show();}}}});new EventChannel(getFlutterView(), NET_CHANGE_CHANNEL).setStreamHandler(new EventChannel.StreamHandler() {private BroadcastReceiver netStateChangeReceiver;@Overridepublic void onListen(Object arguments, EventChannel.EventSink events) {netStateChangeReceiver = createNetStateChangeReceiver(events);registerReceiver(netStateChangeReceiver, new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION));}@Overridepublic void onCancel(Object arguments) {unregisterReceiver(netStateChangeReceiver);netStateChangeReceiver = null;}});}private BroadcastReceiver createNetStateChangeReceiver(final EventChannel.EventSink events) {return new BroadcastReceiver() {@Overridepublic void onReceive(Context context, Intent intent) {boolean networkConnected = NetUtil.isNetworkConnected(context);events.success(networkConnected?"网络可用":"网络不可用");}};}
}

在MainActivity中我们做了三件事件。

第一件事,跟上面的一样,让用户可以通过自己去触发操作判断当前网络是否可用,当然还是通过MethodChannel来实现的,然后把网络连接的状态通过我们刚才实现的Toast来弹出来。

当然这件事我们可以不做,只做监听也是可以的

new MethodChannel(getFlutterView(), CHANNEL).setMethodCallHandler(new MethodChannel.MethodCallHandler() {@Overridepublic void onMethodCall(MethodCall call, MethodChannel.Result result) {System.out.println(call.method);if (call.method.equals("netConnection")) {boolean networkConnected = NetUtil.isNetworkConnected(getApplicationContext());result.success(networkConnected);}}});

第二件事,我们构造了一个动态广播接受者,来处理网络变化的广播事件,当接收到广播时判断网络状态并返回给Flutter中

private BroadcastReceiver createNetStateChangeReceiver(final EventChannel.EventSink events) {return new BroadcastReceiver() {@Overridepublic void onReceive(Context context, Intent intent) {boolean networkConnected = NetUtil.isNetworkConnected(context);events.success(networkConnected?"网络可用":"网络不可用");}};}
}

第三件事,我们新建了EventChannel对象来对广播进行注册于解注册操作,负责广播的管理,并且声明注册广播的过滤器ConnectivityManager.CONNECTIVITY_ACTION,意思就是只接受网络状态变化的广播。

同样的我们定义了一个NET_CHANGE_CHANNEL通道。

new EventChannel(getFlutterView(), NET_CHANGE_CHANNEL).setStreamHandler(new EventChannel.StreamHandler() {private BroadcastReceiver netStateChangeReceiver;@Overridepublic void onListen(Object arguments, EventChannel.EventSink events) {netStateChangeReceiver = createNetStateChangeReceiver(events);registerReceiver(netStateChangeReceiver, new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION));}@Overridepublic void onCancel(Object arguments) {unregisterReceiver(netStateChangeReceiver);netStateChangeReceiver = null;}});}

在Flutter中我们需要注册对广播事件的监听并处理传来的事件即可。

import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';void main() {runApp(MaterialApp(home: MyApp(),));
}class MyApp extends StatefulWidget {@overrideState<StatefulWidget> createState() {return new MyAppState();}
}class MyAppState extends State<MyApp> {static const platform = const MethodChannel("com.flyou.test/android");static const EventChannel eventChannel =const EventChannel('com.flyou.test/netChanged');var netChangeStr = "点我获取当前网络状态";@overridevoid initState() {super.initState();eventChannel.receiveBroadcastStream().listen(_onEvent, onError: _onError);}void _onEvent(Object event) {setState(() {netChangeStr = event;});}void _onError(Object error) {setState(() {netChangeStr = "网络状态获取失败";});}Future<bool> isNetConnection() async {bool isConnection;try {isConnection = await platform.invokeMethod("netConnection");} on PlatformException catch (e) {print(e.toString());}return isConnection;}showToast(String msg) async {try {await platform.invokeMethod("showToast", {"msg": msg});} on PlatformException catch (e) {print(e.toString());}}@overrideWidget build(BuildContext context) {return Scaffold(appBar: AppBar(title: Text("platformChannels"),),body: Center(child: RaisedButton(child: Text(netChangeStr),onPressed: () {isNetConnection().then((bool) {showToast(bool ? "网络连接成功" : "网络连接失败");});},),),);}
}

在Flutter中我们使用了StatefulWidget在构建组件,使得获取到系统网络变化时可以及时更新界面UI状态。

具体的流程如下:

首先我们声明了跟MainActivity中一样的方法通道和事件通道来调用系统的方法接收系统的广播回调。

其次,我们完成对方法的注册于事件广播的注册

可以看到

eventChannel.receiveBroadcastStream().listen(_onEvent, onError: _onError)

回调事件我们单独写成方法来处理。

最后,当系统广播触发时,我们通过事件通过或者方法通道来将事件并更新界面上按钮的状态

我们还是来看下效果:

小结

  • 我们可以通过MethodChannel来调用系统平台的方法
  • 我们可以使用EventChannel来处理系统平台的监听或回调
  • 不同平台(Ios、Android)需要单独的代码去实现相应的功能

Flutter调用平台代码相关推荐

  1. flutter调用js代码

    首先需要在pubspec.yaml中配置: dependencies:js: ^0.6.1+1 #主要是指明这个,可以根据实际情况配置版本flutter:sdk: flutter 然后直接看代码,在l ...

  2. flutter 调用原生安卓插件_Flutter 如何调用Android和iOS原生代码

    分3个大步骤: 1.在flutter中调用原生方法 2.在Android中实现被调用的方法 3.在iOS中实现被调用的方法 在flutter中调用原生方法 场景,这里你希望调用原生方法告诉你一个boo ...

  3. flutter 调用原生安卓插件_Flutter 如何调用Android和iOS原生代码-阿里云开发者社区...

    分3个大步骤: 1.在flutter中调用原生方法 2.在Android中实现被调用的方法 3.在iOS中实现被调用的方法 在flutter中调用原生方法 场景,这里你希望调用原生方法告诉你一个boo ...

  4. 使用Model-View-ViewModel使用Dart Streams使Flutter中的代码更清晰

    by QuickBird Studios 通过QuickBird Studios 使用Model-View-ViewModel使用Dart Streams使Flutter中的代码更清晰 (Use Mo ...

  5. flutter调用android 原生TextView

    https://blog.csdn.net/zl18603543572/article/details/95983215 本文链接:https://blog.csdn.net/zl1860354357 ...

  6. php调用C代码的方法详解和zend_parse_parameters函数详解

    来源:http://my.oschina.net/Customs/blog/490873 http://blog.csdn.net/super_ufo/article/details/3863731 ...

  7. 在C代码调用C++代码

    由于历史原因,以及不同开发人员的技术偏好,C语言和C++语言都有一些独有的非常有价值的项目,因而两种语言的互操作,充分利用前人造的轮子是一件非常有价值的事情. C++代码调用C代码很简单,只要分别在包 ...

  8. 奇淫巧技-Flutter调用C#

    前言 众所周知,Xamarin应该是.net下的跨平台开发工具.2016年之前还处于收费状态,后被微软收购后开源.但似乎有个现象,开源后的Xamarin发展似乎有些停滞,而且维护Xamarin的团队又 ...

  9. flutter调用api_如何在Flutter(REST API)中进行API调用

    flutter调用api 在本文中,我们将看一下如何快速进行API调用并使用简单的REST API. 在这里查看我在Flutter上的其他一些帖子: Flutter vs React Native 了 ...

最新文章

  1. java猜拳_求一个java猜拳游戏程序
  2. 虚拟人春节搞事情!先在央视《对话》,又跟李玉刚组团除夕出道
  3. 软件测试之三——路径覆盖
  4. 树莓派4B安装系统及基础配置
  5. pyspark reduce代码示例
  6. SAP Commerce的Runtime Attributes
  7. .NET基金会讨论 .NET 开源事业之路
  8. asp.net core 集成JWT
  9. c++ socket学习(1.4)
  10. 一则非常巧合的ORA-15042恢复
  11. 从「及格线」到优等生,威马只用一台W6
  12. 让电脑替你说:"I IOVE YOU"
  13. Yahoo Programming Contest 2019 E - Odd Subrectangles
  14. I/O多路复用通信连接select篇
  15. 「代码随想录」337.打家劫舍III 【动态规划】力扣详解!
  16. yii模版中的判断方法
  17. 架构运维篇(二):Centos7/Linux安装部署Tomcat环境
  18. excel怎么设置自动计算_Excel智能化考勤表,自带万年历设置,考勤加班计算,无脑轻松...
  19. 施努卡:锂电池电芯底面和侧板的压胶面积
  20. 运用人类「从众心理」!掌握简单心理学成为说服高手

热门文章

  1. 2020某宝双十二活动auto脚本,强势来袭!
  2. 假期文案丨运营必看!各类节日文案合集,强烈建议收藏
  3. uCharts常用图表示例
  4. MongoDBC++开发 (三) C++ Driver 浅析(结合mongo-cxx-driver/examples中代码)
  5. Java毕设项目大学生心愿墙系统(java+VUE+Mybatis+Maven+Mysql)
  6. Opencv画图函数整理 及 cvCircle cvLine 只能画出黑白两种颜色问题 解决
  7. 分享134个ASP整站程序源码,总有一款适合您
  8. BlueCam Cloud Technical Support
  9. (转)2010最骚最贱最有深度的100句话
  10. Linux中脚本实现倒计时【两种方法:算术法和显示法】