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

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 {
  //注意这里的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 invokeNativeGetResult() async {
    try {
      // 调用原生方法并传参,以及等待原生返回结果数据,getNativeResult是方法名,{"key": "value"}是参数
      var result = await platform.invokeListMethod('getNativeResult', {"key": "参数1"});
    } catch (e) {}
  }

你可能感兴趣的:(iOS现有项目集成Flutter与相互交互)