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)
    }


}

  1. CHANNEL :通道名称,需要确保Flutter与原生Android代码中定义的这个值是相同的
  2. 需要在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))
                }
            }

        }

  1. 在旧版中MethodChannel的第一个参数是FlutterView,注意现在是BinaryMessenger
  2. 声明调用方法:通过创建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;
    });
  }
}

总结:

  1. 声明调用的方法名:创建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)
  1. 对接收到的方法名的判断以及相应处理:创建MethodChannel并实现MethodCallHandler接口方法
        MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL).setMethodCallHandler { call, result ->
            this.result = result
            when (call.method) {//不同方法名的不同处理逻辑
                "xxx" -> {
                  result.suceess(xxx)//通知对方已接收到调用
                }
                "xxx" -> {
                   
                }
                "xxx"->{
                   
                }
            }

        }

  1. 以上两点适用于原生代码与Flutter的互相调用,反过来即可。

到此为止,Flutter与原生代码的互相调用就介绍完毕了,多写才能熟能生巧,感兴趣的小伙伴可以下载源码看一下,希望大家可以点个Star,支持一下小白的flutter学习经历,最后,希望喜欢我文章的朋友们可以帮忙点赞、收藏,也可以关注一下,如果有问题可以在评论区提出,后面我会持续更新Flutter的学习记录,与大家分享,谢谢大家的支持与阅读!

以上是关于Flutter学习日记之Flutter与原生Android的互相调用的主要内容,如果未能解决你的问题,请参考以下文章

Flutter学习日记之Http&Dio网络请求的使用与封装

Flutter学习日记之表单组件Radio单选框&Checkbox复选框的使用

Flutter学习日记之Flutter_swiper实现轮播图功能

Flutter学习日记之集成极光推送

Flutter学习日记之集成极光推送

Flutter学习日记之集成极光推送