美文网首页
Flutter学习之旅-混合开发Part1

Flutter学习之旅-混合开发Part1

作者: 小码农沐枫 | 来源:发表于2020-12-29 09:25 被阅读0次

    场景

    1. Flutter项目中需要与Native进行通信
    2. Android原生项目嵌入Flutter开发模块
    3. iOS原生项目嵌入Flutter开发模块
    4. Flutter插件开发
    image

    平台通道数据类型支持

    Dart Android iOS
    null null nil (NSNull when nested)
    bool java.lang.Boolean NSNumber numberWithBool:
    int java.lang.Integer NSNumber numberWithInt:
    int, 如果不足32位 java.lang.Long NSNumber numberWithLong:
    int, 如果不足64位 java.math.BigInteger FlutterStandardBigInteger
    double java.lang.Double NSNumber numberWithDouble:
    String java.lang.String NSString
    Uint8List byte[] FlutterStandardTypedData typedDataWithBytes:
    Int32List int[] FlutterStandardTypedData typedDataWithInt32:
    Int64List long[] FlutterStandardTypedData typedDataWithInt64:
    Float64List double[] FlutterStandardTypedData typedDataWithFloat64:
    List java.util.ArrayList NSArray
    Map java.util.HashMap NSDictionary

    当在发送和接收值时,这些值在消息中的序列化和反序列化会自动进行。

    平台通道

    Platform Channel 是所以 Flutter 提供的和平台端通信的工具,针对不同的使用场景,Platform Channel 又分为以下三类:

    1. Message channel:用于传递字符串和半结构化的信息,支持使用自定义消息编解码器进行基本的异步消息传递
    2. Method channel:用于传递方法调用(method invocation)
    3. Event channel:用于数据流(event streams)的通信,通常用在需要进行实时监听的使用场景,比如:网络状态,电池充电状态以及一些监听器的实现

    Flutter项目中需要与Native进行通信-实战

    我们这里仅使用Method channel和Event channel进行通信实战

    要实现的功能:

    1. Flutter给Native传递三个参数,Native要把这三个参数相加得到的结果返回给Flutter,并显示在Flutter界面上
    2. Native写一个定时器,每隔1秒进行“+1操作”,每次“+1”后,把结果传递给Flutter,当结果大于30的时候结束定时器
    功能1:
    Android端:

    创建MethodChannelDemo.kt

    class MethodChannelDemo (messenger: BinaryMessenger): MethodChannel.MethodCallHandler{
    
        private var channel: MethodChannel = MethodChannel(messenger, "com.mufeng.flutterNativeChannel.MethodChannel")
    
        init {
            channel.setMethodCallHandler(this)
        }
    
        override fun onMethodCall(call: MethodCall, result: MethodChannel.Result) {
            when(call.method){
                "add" -> {
                    val params1 = call.argument<Int>("params1")
                    val params2 = call.argument<Int>("params2")
                    val params3 = call.argument<Int>("params3")
                    val params = params1!! + params2!! + params3!!
                    result.success(params)
                }
            }
        }
    }
    

    在MainActivity中启动平台通道

    class MainActivity: FlutterActivity() {
        override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
            super.configureFlutterEngine(flutterEngine)
            MethodChannelDemo(flutterEngine.dartExecutor.binaryMessenger)
        }
    }
    
    iOS端

    创建MethodChannelDemo.swift

    //
    //  MethodChannelDemo.swift
    //  Runner
    //
    //  Created by a on 2020/12/28.
    //
    
    import Foundation
    
    import Flutter
    import UIKit
    
    public class MethodChannelDemo {
        init(messenger: FlutterBinaryMessenger) {
            let channel = FlutterMethodChannel(name: "com.mufeng.flutterNativeChannel.MethodChannel", binaryMessenger: messenger)
            channel.setMethodCallHandler{ (call: FlutterMethodCall, result:@escaping FlutterResult)in
                if(call.method == "add"){
                    if let dict = call.arguments as? Dictionary<String, Any>{
                        let params1: Int = dict["params1"] as? Int ?? 0
                        let params2: Int = dict["params2"] as? Int ?? 0
                        let params3: Int = dict["params3"] as? Int ?? 0
                        result(params1 + params2 + params3)
                    }
                }
            }
        }
    }
    
    

    在 AppDelegate 中启动平台通道:

    import UIKit
    import Flutter
    
    @UIApplicationMain
    @objc class AppDelegate: FlutterAppDelegate {
      override func application(
        _ application: UIApplication,
        didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
      ) -> Bool {
        
        /// start
        let controller: FlutterViewController = window?.rootViewController as! FlutterViewController
        MethodChannelDemo(messenger: controller.binaryMessenger)
        /// end
        GeneratedPluginRegistrant.register(with: self)
        return super.application(application, didFinishLaunchingWithOptions: launchOptions)
      }
    }
    

    在ios中也用同样的操作,要保证平台通道的channel保持一致,这样在Flutter中就可以保证一套代码试用两个平台了

    Flutter
     /// 保证平台channel保持一致
     var channel = MethodChannel('com.mufeng.flutterNativeChannel.MethodChannel');
     var result = await channel.invokeMethod('add', {'params1': int.parse(controller1.text), 'params2': int.parse(controller2.text), 'params3': int.parse(controller3.text)});
     setState(() {
       this.result = result.toString();
     });
    
    显示结果:

    Android:


    image

    iOS:


    image
    功能2:
    Android端

    android 下创建 EventChannelDemo:

    package com.mufeng.flutter_native_channel
    
    import android.app.Activity
    import io.flutter.plugin.common.BinaryMessenger
    import io.flutter.plugin.common.EventChannel
    import java.util.*
    import kotlin.concurrent.timerTask
    
    class EventChannelDemo(private var activity: Activity, messenger: BinaryMessenger) : EventChannel.StreamHandler {
    
        private var channel: EventChannel = EventChannel(messenger, "com.mufeng.flutterNativeChannel.EventChannel")
        private var count = 0
        private var events: EventChannel.EventSink? = null
        init {
            channel.setStreamHandler(this)
            startTimer()
        }
    
        private fun startTimer() {
            var timer = Timer().schedule(timerTask {
                count++
                val map = mapOf("count" to count)
                activity.runOnUiThread {
                    // 必须运行在主线程
                    events?.success(map)
                }
                if(count >= 30){
                     activity.runOnUiThread {
                        events?.error("400", "超过30秒,倒计时结束", null)
                    }
                    cancel()
                }
            }, 0, 1000)
        }
    
        override fun onListen(arguments: Any?, events: EventChannel.EventSink?) {
            this.events = events
        }
    
        override fun onCancel(arguments: Any?) {
            this.events = null
        }
    }
    

    在 MainActivity 启动:

    class MainActivity: FlutterActivity() {
        override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
            super.configureFlutterEngine(flutterEngine)
            // MethodChannelDemo(flutterEngine.dartExecutor.binaryMessenger)
            EventChannelDemo(this, flutterEngine.dartExecutor.binaryMessenger)
        }
    }
    
    iOS端

    ios 下创建 EventChannelDemo

    
    import Foundation
    import Flutter
    import UIKit
    
    public class EventChannelDemo: NSObject, FlutterStreamHandler {
        var channel: FlutterEventChannel?
        var count = 0
        var events: FlutterEventSink?
        var timer: Timer?
        
        public override init() {
            super.init()
        }
        
        convenience init(messenger: FlutterBinaryMessenger) {
            self.init()
            
            channel = FlutterEventChannel(name: "com.mufeng.flutterNativeChannel.EventChannel", binaryMessenger: messenger)
            channel?.setStreamHandler(self)
            startTimer()
        }
        
        func startTimer() {
            timer = Timer.scheduledTimer(timeInterval: 1, target: self,selector: #selector(self.tickDown),userInfo: nil,repeats: true)
        }
        
        @objc func tickDown(){
            count += 1
            let args = ["count": count]
            if(events != nil){
                events!(args)
            }
            if(count >= 30){
                if(events != nil){
                    events!(FlutterError.init(code: "400", message: "超过30秒,倒计时结束", details: nil))
                }
                timer?.fireDate = Date.distantFuture
                timer?.invalidate()
            }
        }
        
        public func onListen(withArguments arguments: Any?, eventSink events: @escaping FlutterEventSink) -> FlutterError? {
            self.events = events
            return nil
        }
        
        public func onCancel(withArguments arguments: Any?) -> FlutterError? {
            self.events = nil
            timer?.invalidate()
            self.timer = nil
            return nil
        }
    }
    

    在 AppDelegate 启动:

    @UIApplicationMain
    @objc class AppDelegate: FlutterAppDelegate {
      override func application(
        _ application: UIApplication,
        didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
      ) -> Bool {
        
        let controller: FlutterViewController = window?.rootViewController as! FlutterViewController
        // MethodChannelDemo(messenger: controller.binaryMessenger)
        EventChannelDemo(messenger: controller.binaryMessenger)
        GeneratedPluginRegistrant.register(with: self)
        return super.application(application, didFinishLaunchingWithOptions: launchOptions)
      }
    }
    
    
    Flutter端
    var _eventChannel = EventChannel('com.mufeng.flutterNativeChannel.EventChannel');
    
    _eventChannel.receiveBroadcastStream().listen(_listen, onError: (value){
          print(value);
        });
        
      void _listen(event) {
        setState(() {
          second = event['count'].toString();
        });
      }
    
    显示结果

    Android:

    // 打印出原生发挥的错误信息
    I/flutter (24053): PlatformException(400, 超过30秒,倒计时结束, null, null)
    
    image

    iOS:

    // 打印出原生发挥的错误信息
    flutter: PlatformException(400, 超过30秒,倒计时结束, null, null)
    
    image

    源码地址:flutter_native_channel

    总结

    Flutter 与 Native 通信在 Flutter 应用中几乎是不可缺少的步骤,所以掌握其原理和实际用法尤其重要。熟练的掌握Flutter与Native的通信能极大的提高开发效率

    感谢

    老孟Flutter

    Flutter中文网-Flutter实战

    相关文章

      网友评论

          本文标题:Flutter学习之旅-混合开发Part1

          本文链接:https://www.haomeiwen.com/subject/apffoktx.html