Flutter学习资源汇总持续更新中....

2024-06-12  本文已影响0人  陈科比大宝贝儿

常用三方类库


flutter_lints                   - Flutter团队推荐的Flutter相关规则集

cupertino_icons                 -  加载苹果风格的图标

ios_platform_images             -  share images between Flutter and iOS

flutter_boost                   -  新一代Flutter-Native混合解决方案

flustars                        -  Flutter常用工具类库,包括日期、时间、正则、log日志、json转换、屏幕相关

shared_preferences              -  本地数据存取插件 ,在Android上它是基于 SharePreferences的,在iOS上它是基于 NSUserDefaults

flutter_boost

随着Flutter的发展,国内越来越多的App开始使用Flutter。为了降低风险,大部分App采用渐进式方式引入Flutter,在App里选几个页面用Flutter来编写,但都碰到了相同的问题,在原生页面和Flutter页面共存的情况下,如何管理路由? 官方没有提供这样的解决方案,而FlutterBoost就是为了解决这个问题而生。

FlutterBoost的使命是让开发者非常简单的在原生App中开发Flutter页面。

很多Flutter开发者只会一端,只会Android 或者只会IOS,但他需要接入双端,所以双端统一能降低他的 学习成本和接入成本。FlutterBoost3.0,在设计上 Android和IOS都做了对齐,特别接口上做到了参数级的对齐。

新一代Flutter-Native混合解决方案。 FlutterBoost是一个Flutter插件,它可以轻松地为现有原生应用程序提供Flutter混合集成方案。FlutterBoost的理念是将Flutter像Webview那样来使用。在现有应用程序中同时管理Native页面和Flutter页面并非易事。 FlutterBoost帮你处理页面的映射和跳转,你只需关心页面的名字和参数即可(通常可以是URL)。

将FlutterBoost添加到你的Flutter工程依赖中


flutter_boost:
    git:
        url: 'https://github.com/alibaba/flutter_boost.git'
        ref: 'v3.0-release.2'

之后在flutter工程下运行flutter pub get dart端就集成完毕了

将FlutterBoost集成到Android部分和iOS部分

将FlutterBoost添加到你的iOS工程依赖中

首先到自己的iOS目录下,执行一次pod install


yushuhuideMacBook-Pro:wargame_cloudgame_ios yushuhui$ pod install
Analyzing dependencies
Downloading dependencies
Installing FlutterPluginRegistrant 0.0.1
Installing flutter_boost (0.0.2)
Installing ios_platform_images (0.0.1)
Installing path_provider_ios (0.0.1)
Installing shared_preferences_ios (0.0.1)
Generating Pods project
Integrating client project
Pod installation complete! There are 31 dependencies from the Podfile and 45 total pods installed.


进行准备工作创建FlutterBoostDelegate。 这里面的内容是完全可以自定义的,在您了解各个API的含义时,你可以完全自定义这里面每个方法的代码,下面只是给出大多数场景的默认解法


import flutter_boost

class BoostDelegate: NSObject,FlutterBoostDelegate {
    
    static let shared = BoostDelegate()
    
    ///您用来push的导航栏
    var navigationController:UINavigationController?
    
    var flutterVC:FBFlutterViewContainer?
    
    ///用来存返回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)
        self.flutterVC = vc
        
        //用参数来控制是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的didFinishLaunchingWithOptions方法中进行初始化


//创建代理,做初始化操作
import flutter_boost
let flutterBoostDelegate = BoostDelegate()

FlutterBoost.instance().setup(application, delegate: flutterBoostDelegate, callback: { engine in
            
})

iOS原生跳转到flutter模块的settingPage页面


class ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        let flutterBtn = UIButton()
        flutterBtn.backgroundColor = ColorConst.color_e8f4
        flutterBtn.layer.cornerRadius = 5
        flutterBtn.layer.masksToBounds = true
        flutterBtn.setTitle("toFlutterVC", for: .normal)
        flutterBtn.setTitleColor(ColorConst.color_28, for: .normal)
        flutterBtn.addTarget(self, action: #selector(clickToSettingVC), for: .touchUpInside)
        flutterBtn.frame = CGRect(x: 100, y: 100, width: 100, height: 100)
        view.addSubview(flutterBtn)
    }

    @objc func clickToSettingVC() {
        // 创建options,进行open操作的构建
        let options = FlutterBoostRouteOptions()
        options.pageName = "settingPage"
        options.arguments = ["data": "settingPage", "isPresent": false, "isAnimated": true]

        // 这个是push操作完成的回调,而不是页面关闭的回调!!!!
        options.completion = { _ in
            print("open operation is completed")
        }

        // 这个是页面关闭并且返回数据的回调,回调实际需要根据您的Delegate中的popRoute来调用
        options.onPageFinished = { [weak self] dic in
            if let data = dic?["data"] as? String {
                print("settingPage return data is: \(data)")
            }
        }
        BoostDelegate.shared.navigationController = UIViewController.current.navigationController
        BoostDelegate.shared.pushFlutterRoute(options)
    }
}


flutter run 配置iOS证书


vim ~/.flutter_settings


{
  "ios-signing-cert": "Apple Development: XXXX@gmail.com (XXXXXXXX)",
  "enable-macos-desktop": true
}

单独调试某个flutter页面示例,无需经过集成到原生工程


Widget appBuilder(Widget home) {
    return const MaterialApp(
      home: MySettingPage(), // 这里是需要调试的页面的名称
      // home: home,
      debugShowCheckedModeBanner: false,

      ///必须加上builder参数,否则showDialog等会出问题
      // builder: (_, __) {
      //   return home;
      // },
    );

将FlutterBoost添加到你的android工程依赖中,原生和flutter通信的各种情况如下:

  1. Android 原生携带参数打开flutter页面

         HashMap<String, Object> map = new HashMap<>();//传递给flutter的参数map
         map.put("data","1");
         map.put("UserName","2");
         map.put("HeaderUrl","3");
         map.put("CurrUserId","4");
         FlutterBoostRouteOptions options = new FlutterBoostRouteOptions.Builder()
                 .pageName("settingPage") //settingPage打开的flutter页面的名称
                 .arguments(map)
                 .requestCode(1111)
                 .build();
         FlutterBoost.instance().open(options);
    

    flutter接收传递的数据:

    Map<String, FlutterBoostRouteFactory> routerMap = {
     'settingPage': (settings, uniqueId) {
       return CupertinoPageRoute(
           settings: settings,
           builder: (_) {
    
             Map<String, Object> map = settings.arguments as Map<String, Object>;
             print("收到原生传递的消息:"+ map.toString());
             String data = map['data'] as String;
             print("收到原生传递的消息 data:"+ data.toString());
             return MySettingPage(
               data: data,
             );
           });
     },  };
    
    
    
  2. flutter携带参数打开Android原生页面

   var user = {
    'data' : 'number',
    'age': 'turtledoves'
  }; 
  MainActivity:打开Android原生的目标页面。user传递的参数

Android原生接收:
先发送消息到原生,原生收到消息后,进行分发打开原生界面:

 EventListener listener = (key, args) -> {
         Log.d("EventListener", "onCreate: args ----key是:" + key+ "--------args是: "+ args);
         if (key.equals("event")){
//                Map<Object, Object> args
                 if (args.get("data").equals("Logout")){
                     startActivity(new Intent(this, MainActivity.class));
                 }
             }
         }
     };
     remover = FlutterBoost.instance().addEventListener("event", listener);
  1. flutter向Android原生发送消息

    发送的key是data,value是一个map集合
    BoostChannel.instance.sendEventToNative("event", {'data': "UserInfo"});
    

    Android原生接收消息:
    EventListener listener = (key, args) -> {

         Log.d("EventListener", "onCreate: args ----key是:" + key+ "--------args是: "+ args);
     };
    

    ListenerRemover remover = FlutterBoost.instance().addEventListener("event", listener);

    注意://最后在清理的时候移除监听(比如onDestroy中) remover.remove();

  2. Android向Flutter发送消息

    Map<Object,Object> map = new HashMap<>();
    map.put("key","value");
    FlutterBoost.instance().sendEventToFlutter("eventToFlutter",map);
    

    flutter端接收:

```
///声明一个用来存回调的对象
VoidCallback removeListener;

///添加事件响应者,监听native发往flutter端的事件
removeListener = BoostChannel.instance.addEventListener("yourEventKey", (key, arguments) {
  ///deal with your event here
  return;
});

///然后在退出的时候(比如dispose中)移除监听者
removeListener?.call();
```
上一篇下一篇

猜你喜欢

热点阅读