美文网首页
iOS 采用 flutter_boost接入flutter 模

iOS 采用 flutter_boost接入flutter 模

作者: iOS刘耀宗 | 来源:发表于2021-08-10 15:30 被阅读0次

Demo下载亲测可用. 不坑请点赞
在阅读此篇文章,默认已经有相应的 flutter基础
场景:
如果我们在原生项目上想要接入 flutter. 这个时候就不能采用创建一个 flutter项目的模式.因为原生项目已经开发很多了. 那么这个时候就要采取原生接入 flutter 模块的形式. 然后把模块接入 iOS/安卓端.
接入的方案是采用 flutter_boost(亿级用户). 就可以实现原生到 flutter 页面的相互跳转,相互传递数据. 是不是很香?

步骤:
1.创建 ios 项目(我这里的项目叫做 flutter_swift).
2:创建 flutter 模块

//打开终端,执行命令
cd  xxxx(你的目录)
flutter create -t module flutter_demo

注意iOS 项目和 flutter 模块的目录要在同一层级,如下图


图 1.png

3:集成flutter_boost
flutter_boost github地址
里面有详细的集成文档. 按照步骤一步一步来.
我的步骤:
修改配置:
注意: 这里一定要对 environment 进行修改. 不然会因为 null safety 的问题报错. 我在这里折腾了好久. 改了这里就一切正常了.

flutter 配置.png

修改之后 flutter packages get

我的 demo 很简单. 主要代码在main.dart. 简单实现通信. 其他的请按需扩展
flutter main.dart

import 'package:flutter/material.dart';
import 'package:flutter_boost/flutter_boost.dart';
import 'mine.dart';
import 'homePage.dart';

//这里要特别注意,如果你的工程里已经有一个继承自WidgetsFlutterBinding的自定义Binding,则只需要将其with上BoostFlutterBinding
//如果你的工程没有自定义的Binding,则可以参考这个CustomFlutterBinding的做法
//BoostFlutterBinding用于接管Flutter App的生命周期,必须得接入的
class CustomFlutterBinding extends WidgetsFlutterBinding
    with BoostFlutterBinding {}

void main() {
  CustomFlutterBinding();
  runApp(MyApp());
}

class MyApp extends StatefulWidget {
  MyApp({Key key}) : super(key: key);

  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  ///路由表
  static Map<String, FlutterBoostRouteFactory> routerMap = {
    'homePage': (settings, uniqueId) {
      return PageRouteBuilder<dynamic>(
          settings: settings,
          pageBuilder: (_, __, ___) {
            return homePage();
          });
    },
    'minePage': (settings, uniqueId) {
      return PageRouteBuilder<dynamic>(
          settings: settings, pageBuilder: (_, __, ___) {
            Map<String,Object> map = settings.arguments;
            String data = uniqueId;
            return minePage(
              data: data,
            );
          });
    },
  };

  Route<dynamic> routeFactory(RouteSettings settings, String uniqueId) {
    FlutterBoostRouteFactory func = routerMap[settings.name];
    if (func == null) {
      return null;
    }
    return func(settings, uniqueId);
  }

  Widget appBuilder(Widget home) {
    return MaterialApp(home: home, debugShowCheckedModeBanner: false);
  }

  @override
  Widget build(BuildContext context) {
    return FlutterBoostApp(
      routeFactory,
      appBuilder: appBuilder,
    );
  }
}

4:iOS 端的配置
修改 pod
注意点:
flutter_application_path = '../flutter_demo' flutter_demo 就是同级目录的 flutter模块的名字. 也是它的路径

一共需要添加
flutter_application_path = '../flutter_demo'
load File.join(flutter_application_path, '.ios', 'Flutter', 'podhelper.rb') install_flutter_engine_pod
install_all_flutter_pods(flutter_application_path)


# Uncomment the next line to define a global platform for your project
platform :ios, '9.0'
flutter_application_path = '../flutter_demo'
load File.join(flutter_application_path, '.ios', 'Flutter', 'podhelper.rb')
target 'flutter_swift' do
  # Comment the next line if you don't want to use dynamic frameworks
  use_frameworks!
  install_flutter_engine_pod
  install_all_flutter_pods(flutter_application_path)
  # Pods for flutter_swift

end

post_install do |installer|
  installer.pods_project.targets.each do |target|
    target.build_configurations.each do |config|
      config.build_settings['ENABLE_BITCODE'] = 'NO'
    end
  end
end

install! 'cocoapods', :disable_input_output_paths => true

然后pod install

接下来:
在AppDelegate 导入import flutter_boost

创建类BoostDelegate. 其作用是实现FlutterBoostDelegate,用它来实现跳转.用这个类统一管理页面跳转,数据传输

import flutter_boost
class BoostDelegate: NSObject,FlutterBoostDelegate {
    
    static let shared = BoostDelegate()
    ///您用来push的导航栏
    var navigationController:UINavigationController?
    
    ///用来存返回flutter侧返回结果的表
    var resultTable:Dictionary<String,([AnyHashable:Any]?)->Void> = [:];
    
    func pushNativeRoute(_ pageName: String!, arguments: [AnyHashable : Any]!) {
        
        //可以用参数来控制是push还是pop
        let isPresent = arguments["isPresent"] as? Bool ?? false
        let isAnimated = arguments["isAnimated"] as? Bool ?? true
        //这里根据pageName来判断生成哪个vc,这里给个默认的了
        var targetViewController = UIViewController()
        
        if(isPresent){
            self.navigationController?.present(targetViewController, animated: isAnimated, completion: nil)
        }else{
            self.navigationController?.pushViewController(targetViewController, animated: isAnimated)
        }
    }
    
    func pushFlutterRoute(_ options: FlutterBoostRouteOptions!) {
        let vc:FBFlutterViewContainer = FBFlutterViewContainer()
        vc.setName(options.pageName, uniqueId: options.uniqueId, params: options.arguments,opaque: options.opaque)
        
        //用参数来控制是push还是pop
        let isPresent = (options.arguments?["isPresent"] as? Bool)  ?? false
        let isAnimated = (options.arguments?["isAnimated"] as? Bool) ?? true
        
        //对这个页面设置结果
        resultTable[options.pageName] = options.onPageFinished;
        
        //如果是present模式 ,或者要不透明模式,那么就需要以present模式打开页面
        if(isPresent || !options.opaque){
            self.navigationController?.present(vc, animated: isAnimated, completion: nil)
        }else{
            self.navigationController?.pushViewController(vc, animated: isAnimated)
        }
    }
    
    func popRoute(_ options: FlutterBoostRouteOptions!) {
        //如果当前被present的vc是container,那么就执行dismiss逻辑
        if let vc = self.navigationController?.presentedViewController as? FBFlutterViewContainer,vc.uniqueIDString() == options.uniqueId{
            
            //这里分为两种情况,由于UIModalPresentationOverFullScreen下,生命周期显示会有问题
            //所以需要手动调用的场景,从而使下面底部的vc调用viewAppear相关逻辑
            if vc.modalPresentationStyle == .overFullScreen {
                
                //这里手动beginAppearanceTransition触发页面生命周期
                self.navigationController?.topViewController?.beginAppearanceTransition(true, animated: false)
                
                vc.dismiss(animated: true) {
                    self.navigationController?.topViewController?.endAppearanceTransition()
                }
            }else{
                //正常场景,直接dismiss
                vc.dismiss(animated: true, completion: nil)
            }
        }else{
            self.navigationController?.popViewController(animated: true)
        }
        //否则直接执行pop逻辑
        //这里在pop的时候将参数带出,并且从结果表中移除
        if let onPageFinshed = resultTable[options.pageName] {
            onPageFinshed(options.arguments)
            resultTable.removeValue(forKey: options.pageName)
        }
    }
}

需要在 appdelegate 里面进行初始化操作

//
//  AppDelegate.swift
//  flutter_swift
//
//  Created by liuyaozong on 2021/8/10.
//

import UIKit
import flutter_boost
@main
class AppDelegate: UIResponder, UIApplicationDelegate {


    var window: UIWindow?
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        // Override point for customization after application launch.
        //创建代理,做初始化操作
        let delegate = BoostDelegate()
        FlutterBoost.instance().setup(application, delegate: delegate) { engine in
            
        }
        
        window = UIWindow(frame: UIScreen.main.bounds)
        let navc = UINavigationController(rootViewController: ViewController())
        window?.rootViewController = navc
        window?.makeKeyAndVisible()
        return true
    }

}


如何使用呢:
直接上代码

//
//  ViewController.swift
//  flutter_swift
//
//  Created by liuyaozong on 2021/8/10.
//

import UIKit
import flutter_boost
class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        self.title = "我的原生页面"
        // Do any additional setup after loading the view.
        view.backgroundColor = .white
        BoostDelegate.shared.navigationController = self.navigationController
        
        let btn1 = creatBtn(title: "跳转到首页")
        btn1.addTarget(self, action: #selector(clickHome), for: .touchUpInside)
        let btn2 = creatBtn(title: "跳转到我的")
        btn2.addTarget(self, action: #selector(clickMine), for: .touchUpInside)

        view.addSubview(btn1)
        view.addSubview(btn2)
        btn1.frame = .init(x: 100, y: 100, width: 100, height: 50)
        btn2.frame = .init(x: 100, y: 300, width: 100, height: 50)
    }
    
    //跳转到首页
    @objc func clickHome() {
        let options = FlutterBoostRouteOptions()
        options.pageName = "homePage"
        
        BoostDelegate.shared.pushFlutterRoute(options)
    }
    
    //跳转到个人中心
    @objc func clickMine() {
        let options = FlutterBoostRouteOptions()
        options.pageName = "minePage"
        options.arguments = ["data": "床前明月光,疑是地上霜"]
        options.uniqueId = "举头望明月,低头思故乡"
        BoostDelegate.shared.pushFlutterRoute(options)
    }
    
    func creatBtn(title: String) -> UIButton {
        let btn = UIButton()
        btn.setTitle(title, for: .normal)
        btn.setTitleColor(.black, for: .normal)
        return btn
    }
}

效果:


原生页面.png

跳转到flutter我的页面


image.png

相关文章

网友评论

      本文标题:iOS 采用 flutter_boost接入flutter 模

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