Flutter学习日记之Flutter与原生Android的互相调用
Posted Android_小黑
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Flutter学习日记之Flutter与原生Android的互相调用相关的知识,希望对你有一定的参考价值。
本文地址:https://blog.csdn.net/qq_40785165/article/details/118633058,转载请附上此地址
大家好,我是小黑,一个还没秃头的程序员~~~
不积跬步,无以至千里,不积小流,无以成江海
这次介绍的是Flutter中关于原生android与Flutter的互相调用(因为本人是Android开发,所以只能介绍Android与Flutter的互相调用),Flutter编程主要是为了使用组件进行界面开发,像一些比如Service之类的技术,还是得靠原生编写,所以这就需要了解两端互相调用的内容了,源码地址:https://gitee.com/fjjxxy/flutter-study.git,效果如下:
从上面效果可以看出,第一个按钮是Flutter页面去调用原生Android的方法,调用成功后Android端会返回相应信息,Flutter可以在界面中进行后续操作,第二个按钮点击后Flutter会先调用Android的方法,开启Android中的Service类,实现在后台计时的功能,随后Android端通过调用Flutter的方法将时间传到Flutter界面进行显示。
使用到的第三方库:
- implementation ‘org.greenrobot:eventbus:3.1.1’ Eventbus事件总线,用于Service与activity的通信
(一)编写Android端项目
注:本人使用的是AndroidStudio进行Flutter开发
打开AndroidStudio,点击File->Open->选择你Flutter项目中的原生Android端文件夹,打开即可开始编写你的原生Android代码,注意不能在Flutter项目中直接编写原生代码,会有一堆爆红报错, 因为我这边生成的原生代码是kotlin,所以以下的原生代码都是kotlin编写的,不清楚的人欢迎底下评论区指出,我都会回复的。
MainActivity.kt的代码如下:
class MainActivity : FlutterActivity() {
val CHANNEL = "com.example.flutter.study"
private val TAG = "MainActivity"
private var bind: TimeService.MyBind? = null;
private var result: MethodChannel.Result? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
EventBus.getDefault().register(this)
}
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
super.configureFlutterEngine(flutterEngine)
MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL).setMethodCallHandler { call, result ->
this.result = result
when (call.method) {
"getAndroidData" -> {
Log.e(TAG, "configureFlutterEngine: " + call.method)
Log.e(TAG, "configureFlutterEngine: " + call.arguments)
result.success("调用成功,这是回调信息:method:" + call.method + ",args:" + call.arguments)
}
"getService" -> {
var intent = Intent(this, TimeService::class.java)
startService(intent)
}
"closeTimer"->{
stopService(Intent(this,TimeService::class.java))
}
}
}
}
@Subscribe(threadMode = ThreadMode.MAIN)
fun onEvent(count: String) {
val messenger = flutterEngine?.dartExecutor?.binaryMessenger
// 新建一个 Channel 对象
val channel = MethodChannel(messenger, CHANNEL)
var map = HashMap<String, String>()
map.put("count", count)
channel.invokeMethod("sendCount", map)
}
}
- CHANNEL :通道名称,需要确保Flutter与原生Android代码中定义的这个值是相同的
- 需要在onCreate创建MethodChannel以及在MethodCallHandler处理各种调用方法的处理逻辑,根据与Flutter约定的方法名进行不同逻辑的进行,代码如下:下面代码中,第一个逻辑是打印来自Flutter的调用方法名与参数,第二个逻辑是开启原生代码中的Service,第三个则是关闭
MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL).setMethodCallHandler { call, result ->
this.result = result
when (call.method) {
"getAndroidData" -> {
Log.e(TAG, "configureFlutterEngine: " + call.method)
Log.e(TAG, "configureFlutterEngine: " + call.arguments)
result.success("调用成功,这是回调信息:method:" + call.method + ",args:" + call.arguments)
}
"getService" -> {
var intent = Intent(this, TimeService::class.java)
startService(intent)
}
"closeTimer"->{
stopService(Intent(this,TimeService::class.java))
}
}
}
- 在旧版中MethodChannel的第一个参数是FlutterView,注意现在是BinaryMessenger
- 声明调用方法:通过创建MethodChannel并调用invokeMethod方法即可声明调用的方法,另一端使用MethodCallHandler中的回调进行处理,invokeMethod中的第一个参数为与另一端约定的方法名,第二个参数是传过去的参数,代码如下:
val messenger = flutterEngine?.dartExecutor?.binaryMessenger
// 新建一个 Channel 对象
val channel = MethodChannel(messenger, CHANNEL)
var map = HashMap<String, String>()
map.put("count", count)
channel.invokeMethod("sendCount", map)
Android端Service的编写代码如下:代码就不详解了,相信Android的小伙伴应该都看的懂,就是在onStartCommand中开启定时器,并通过EventBus将计时传到activity,最终activity通过调用Flutter的方法传到界面上进行显示
class TimeService : JobIntentService() {
var mTimer: Timer? = null
val TAG = "TimeService"
var count = 0
override fun onHandleWork(intent: Intent) {
TODO("Not yet implemented")
}
//只有第一次开启服务才会调用
override fun onCreate() {
super.onCreate()
}
override fun onBind(intent: Intent): IBinder? {
return MyBind()
}
class MyBind : Binder() {
fun getService(): TimeService {
return TimeService()
}
}
//每次开启服务都会调用
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
count = 0
mTimer = Timer()
mTimer?.schedule(object : TimerTask() {
override fun run() {
count++
EventBus.getDefault().post(count.toString())
}
}, 0, 1000)
return super.onStartCommand(intent, flags, startId)
}
override fun onDestroy() {
super.onDestroy()
mTimer?.cancel()
}
}
(二)编写Flutter端代码
Flutter中也有方法的调用与接收到另一端方法的处理,接收回调处理可以在initState中创建,代码如下:
@override
void initState() {
// TODO: implement initState
super.initState();
_initChannel();
}
void _initChannel() {
var channel = MethodChannel("com.example.flutter.study");
channel.setMethodCallHandler((call) {
// 同样也是根据方法名分发不同的函数
switch (call.method) {
case "sendCount":
{
String msg = call.arguments["count"];
setState(() {
text2 = msg;
});
}
break;
}
return null;
});
}
调用另一端代码的实现与上面Android端讲的一致,同样使用的是invokeMethod方法,代码如下:这里的data即另一端接收到方法之后的响应信息
onPressed: () async {
var data = await platform
.invokeMethod("getAndroidData", {"name": "getAndroidData"});
print("count:$data");
setState(() {
text = data;
});
}
完整代码如下:
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
class ServicePage extends StatefulWidget {
@override
_ServicePageState createState() => _ServicePageState();
}
class _ServicePageState extends State<ServicePage> {
var text = "";
var text2 = "";
static const platform = const MethodChannel('com.example.flutter.study');
@override
void initState() {
// TODO: implement initState
super.initState();
_initChannel();
}
@override
void dispose() async{
// TODO: implement dispose
super.dispose();
await platform
.invokeMethod("closeTimer", {"name": "closeTimer"});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("原生与flutter互相调用"),
),
body: Column(
children: [
ElevatedButton(
child: Text("flutter给原生Android传值"),
onPressed: () async {
var data = await platform
.invokeMethod("getAndroidData", {"name": "getAndroidData"});
print("count:$data");
setState(() {
text = data;
});
},
),
Text(text),
ElevatedButton(
child: Text("Android调用flutter的方法进行传值"),
onPressed: () async {
var data = await platform
.invokeMethod("getService", {"name": "getAndroidData"});
},
),
Text(text2)
],
),
);
}
void _initChannel() {
var channel = MethodChannel("com.example.flutter.study");
channel.setMethodCallHandler((call) {
// 同样也是根据方法名分发不同的函数
switch (call.method) {
case "sendCount":
{
String msg = call.arguments["count"];
setState(() {
text2 = msg;
});
}
break;
}
return null;
});
}
}
总结:
- 声明调用的方法名:创建MethodChannel并使用invokeMethod方法
val messenger = flutterEngine?.dartExecutor?.binaryMessenger
// 新建一个 Channel 对象
val channel = MethodChannel(messenger, CHANNEL)
var map = HashMap<String, String>()
map.put("count", count)
channel.invokeMethod("sendCount", map)
- 对接收到的方法名的判断以及相应处理:创建MethodChannel并实现MethodCallHandler接口方法
MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL).setMethodCallHandler { call, result ->
this.result = result
when (call.method) {//不同方法名的不同处理逻辑
"xxx" -> {
result.suceess(xxx)//通知对方已接收到调用
}
"xxx" -> {
}
"xxx"->{
}
}
}
- 以上两点适用于原生代码与Flutter的互相调用,反过来即可。
到此为止,Flutter与原生代码的互相调用就介绍完毕了,多写才能熟能生巧,感兴趣的小伙伴可以下载源码看一下,希望大家可以点个Star,支持一下小白的flutter学习经历,最后,希望喜欢我文章的朋友们可以帮忙点赞、收藏,也可以关注一下,如果有问题可以在评论区提出,后面我会持续更新Flutter的学习记录,与大家分享,谢谢大家的支持与阅读!
以上是关于Flutter学习日记之Flutter与原生Android的互相调用的主要内容,如果未能解决你的问题,请参考以下文章
Flutter学习日记之Http&Dio网络请求的使用与封装
Flutter学习日记之表单组件Radio单选框&Checkbox复选框的使用