美文网首页
iOS现有项目集成Flutter与相互交互

iOS现有项目集成Flutter与相互交互

作者: 拖不垮打不烂 | 来源:发表于2022-01-14 17:03 被阅读0次

    1.iOS集成Flutter

    1.1创建项目

    创建原生项目"iOS_demo",创建Flutter项目"flutter_lab",两个项目在同一级目录, 在flutter_lab项目里找到lib文件夹,添加dart代码,如图:

    目录结构
    1.2使用CocoPods集成

    "iOS_demo"添加PodFile文件,命令:cd iOS_demo path -> touch Podfile
    打开新创建的Podfile文件,添加代码

    flutter_application_path = '../flutter_lab'  //这里是flutter项目名
    load File.join(flutter_application_path, '.ios', 'Flutter', 'podhelper.rb')
    
    target 'iOS_demo' do
      install_all_flutter_pods(flutter_application_path)
    end
    

    命令: pod install, iOS集成Flutter完成

    2.iOS调起Flutter

    2.1 AppDelegate配置,注册FlutterEngine,代码如下:
    import UIKit
    import Flutter
    import FlutterPluginRegistrant
    
    @main
    class AppDelegate: UIResponder, UIApplicationDelegate {
        lazy var flutterEngine = FlutterEngine(name: "my flutter engine")
        func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
            // Override point for customization after application launch.
            GeneratedPluginRegistrant.register(with: self.flutterEngine);
            flutterEngine.run()
            return true
        }
    }
    
    2.2 使用 FlutterEngine 展示 FlutterViewController,代码如下:
    import UIKit
    import Flutter
    
    class ViewController: UIViewController {
      override func viewDidLoad() {
        super.viewDidLoad()
    
        // Make a button to call the showFlutter function when pressed.
        let button = UIButton(type:UIButton.ButtonType.custom)
        button.addTarget(self, action: #selector(showFlutter), for: .touchUpInside)
        button.setTitle("Show Flutter!", for: UIControl.State.normal)
        button.frame = CGRect(x: 80.0, y: 210.0, width: 160.0, height: 40.0)
        button.backgroundColor = UIColor.blue
        self.view.addSubview(button)
      }
    
      @objc func showFlutter() {
        let flutterEngine = (UIApplication.shared.delegate as! AppDelegate).flutterEngine
        let flutterViewController =
            FlutterViewController(engine: flutterEngine, nibName: nil, bundle: nil)
        present(flutterViewController, animated: true, completion: nil)
      }
    }
    

    以上默认执行flutter的main函数, 只能实现调起单一路由(控制器),实际操作中,一个iOS原生控制器会根据不同的事件调起不同的路由, 操作如下,首先需要更改2.2代码:

    @objc func showFlutter() {
       let flutterViewController = FlutterViewController(project: nil, initialRoute: "home", nibName: nil, bundle: nil) // 这里initialRoute要与Flutter项目中的main.dart设置的名称一致, 跳转到homeVC路由
       self.modalPresentationStyle = .fullScreen
       self.navigationController?.setNavigationBarHidden(true, animated: true)
       self.navigationController?.pushViewController(flutterViewController, animated: true)        
    }
    

    main.dart代码如下:

    void main() {
      // 获取原生跳转的路由,根据路由显示对应的界面,ui.window.defaultRouteName就是上面设置的 “home”路由标识
      runApp(run(ui.window.defaultRouteName));
    }
    
    //根据路由标识返回对应的Widget,这里需要注意的是如果是单独的界面,必须使用MaterialApp包裹住,不然跳转过来后显示不了当前ui
    Widget run(String name){
      switch (name) {
        case "test":
          return TestVC();
          break;
        case "home":
          return HomeVC();
          break;
        case "myApp":
          return MyApp();
          break;
      }
      return Center(
        child: Text('Unknown route: $name'),
      );
    }
    

    3.iOS与Flutter相互传值

    3.1.iOS传值到Flutter

    iOS代码:
    按钮点击方法showFlutter()的跳转加FlutterEventChannel

    @objc func showFlutter() {
    //   push代码...
    let evenChannel1 = FlutterEventChannel.init(name: "com.nativeToFlutter", binaryMessenger: flutterViewController as! FlutterBinaryMessenger)
    evenChannel1.setStreamHandler(self)
    }
    

    实现代理方法,该代理方法,只有Flutter项目做了监听才可以触发:

    func onListen(withArguments arguments: Any?, eventSink events: @escaping FlutterEventSink) -> FlutterError? {
            print("push传值代理方法")
            events(["key": "push传值", "state": "0"])
            return nil
        }
        
    func onCancel(withArguments arguments: Any?) -> FlutterError? {  
          return nil
     }
    

    Flutter中的HomeVC代码:

    class _HomeVCState extends State<HomeVC> {
      //注意这里的com.nativeToFlutter一定要与原生的名称相同,不然没办法通信
      static const eventChannel = EventChannel('com.nativeToFlutter');
      @override
      void initState() {
        // TODO: implement initState
        super.initState();
        eventChannel.receiveBroadcastStream().listen(_getData,onError: _getError);
      }
      //获得到传值(["key": "push传值", "state": "0"])
      void _getData(dynamic data) {
        print("传值${data}");
      }
    //获取到错误
      void _getError(Object err) {
    
      }
    
    3.1.Flutter传值到iOS

    iOS代码:
    按钮点击方法showFlutter()的跳转加FlutterEventChannel

    @objc func showFlutter() {
    //   push代码...
    let presentChannel:FlutterMethodChannel = FlutterMethodChannel.init(name: "sf.flutter.io/sf_present", binaryMessenger: flutterViewController as! FlutterBinaryMessenger)
    weak var weakSelf = self
    // 添加监听回调
    presentChannel.setMethodCallHandler { (call, result) in
      print(call.method)
       // 当flutter调用了原生方法后,此回调会调用
       // call.method 为方法名,call对象里面还有参数属性
      if call.method == "getNativeResult" {
          let dict:[String : Any] = call.arguments as! [String : Any]
          print(dict["key"] ?? "")
          weakSelf?.navigationController?.popViewController(animated: true)
         }
      }
    }
    

    Flutter中的HomeVC代码:

    // 任意事件返回到原生,同时传值到原生
    Future<void> invokeNativeGetResult() async {
        try {
          // 调用原生方法并传参,以及等待原生返回结果数据,getNativeResult是方法名,{"key": "value"}是参数
          var result = await platform.invokeListMethod('getNativeResult', {"key": "参数1"});
        } catch (e) {}
      }
    

    相关文章

      网友评论

          本文标题:iOS现有项目集成Flutter与相互交互

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