Flutter學(xué)習(xí)資源匯總持續(xù)更新中....

常用三方類庫


flutter_lints                   - Flutter團(tuán)隊(duì)推薦的Flutter相關(guān)規(guī)則集

cupertino_icons                 -  加載蘋果風(fēng)格的圖標(biāo)

ios_platform_images             -  share images between Flutter and iOS

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

flustars                        -  Flutter常用工具類庫,包括日期、時(shí)間、正則、log日志、json轉(zhuǎn)換、屏幕相關(guān)

shared_preferences              -  本地?cái)?shù)據(jù)存取插件 ,在Android上它是基于 SharePreferences的,在iOS上它是基于 NSUserDefaults

flutter_boost

隨著Flutter的發(fā)展,國(guó)內(nèi)越來越多的App開始使用Flutter。為了降低風(fēng)險(xiǎn),大部分App采用漸進(jìn)式方式引入Flutter,在App里選幾個(gè)頁面用Flutter來編寫,但都碰到了相同的問題,在原生頁面和Flutter頁面共存的情況下,如何管理路由? 官方?jīng)]有提供這樣的解決方案,而FlutterBoost就是為了解決這個(gè)問題而生。

FlutterBoost的使命是讓開發(fā)者非常簡(jiǎn)單的在原生App中開發(fā)Flutter頁面。

很多Flutter開發(fā)者只會(huì)一端,只會(huì)Android 或者只會(huì)IOS,但他需要接入雙端,所以雙端統(tǒng)一能降低他的 學(xué)習(xí)成本和接入成本。FlutterBoost3.0,在設(shè)計(jì)上 Android和IOS都做了對(duì)齊,特別接口上做到了參數(shù)級(jí)的對(duì)齊。

新一代Flutter-Native混合解決方案。 FlutterBoost是一個(gè)Flutter插件,它可以輕松地為現(xiàn)有原生應(yīng)用程序提供Flutter混合集成方案。FlutterBoost的理念是將Flutter像Webview那樣來使用。在現(xiàn)有應(yīng)用程序中同時(shí)管理Native頁面和Flutter頁面并非易事。 FlutterBoost幫你處理頁面的映射和跳轉(zhuǎn),你只需關(guān)心頁面的名字和參數(shù)即可(通常可以是URL)。

將FlutterBoost添加到你的Flutter工程依賴中


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

之后在flutter工程下運(yùn)行flutter pub get dart端就集成完畢了

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

將FlutterBoost添加到你的iOS工程依賴中

首先到自己的iOS目錄下,執(zhí)行一次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.


進(jìn)行準(zhǔn)備工作創(chuàng)建FlutterBoostDelegate。 這里面的內(nèi)容是完全可以自定義的,在您了解各個(gè)API的含義時(shí),你可以完全自定義這里面每個(gè)方法的代碼,下面只是給出大多數(shù)場(chǎng)景的默認(rèn)解法


import flutter_boost

class BoostDelegate: NSObject,FlutterBoostDelegate {
    
    static let shared = BoostDelegate()
    
    ///您用來push的導(dǎo)航欄
    var navigationController:UINavigationController?
    
    var flutterVC:FBFlutterViewContainer?
    
    ///用來存返回flutter側(cè)返回結(jié)果的表
    var resultTable:Dictionary<String,([AnyHashable:Any]?)->Void> = [:];
    
    func pushNativeRoute(_ pageName: String!, arguments: [AnyHashable : Any]!) {
        
        //可以用參數(shù)來控制是push還是pop
        let isPresent = arguments["isPresent"] as? Bool ?? false
        let isAnimated = arguments["isAnimated"] as? Bool ?? true
        //這里根據(jù)pageName來判斷生成哪個(gè)vc,這里給個(gè)默認(rèn)的了
        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
        
        //用參數(shù)來控制是push還是pop
        let isPresent = (options.arguments?["isPresent"] as? Bool)  ?? false
        let isAnimated = (options.arguments?["isAnimated"] as? Bool) ?? true
        
        //對(duì)這個(gè)頁面設(shè)置結(jié)果
        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!) {
        //如果當(dāng)前被present的vc是container,那么就執(zhí)行dismiss邏輯
        if let vc = self.navigationController?.presentedViewController as? FBFlutterViewContainer,vc.uniqueIDString() == options.uniqueId{
            
            //這里分為兩種情況,由于UIModalPresentationOverFullScreen下,生命周期顯示會(huì)有問題
            //所以需要手動(dòng)調(diào)用的場(chǎng)景,從而使下面底部的vc調(diào)用viewAppear相關(guān)邏輯
            if vc.modalPresentationStyle == .overFullScreen {
                
                //這里手動(dòng)beginAppearanceTransition觸發(fā)頁面生命周期
                self.navigationController?.topViewController?.beginAppearanceTransition(true, animated: false)
                
                vc.dismiss(animated: true) {
                    self.navigationController?.topViewController?.endAppearanceTransition()
                }
            }else{
                //正常場(chǎng)景,直接dismiss
                vc.dismiss(animated: true, completion: nil)
            }
        }else{
            self.navigationController?.popViewController(animated: true)
        }
        //否則直接執(zhí)行pop邏輯
        //這里在pop的時(shí)候?qū)?shù)帶出,并且從結(jié)果表中移除
        if let onPageFinshed = resultTable[options.pageName] {
            onPageFinshed(options.arguments)
            resultTable.removeValue(forKey: options.pageName)
        }
    }
}

在AppDelegate的didFinishLaunchingWithOptions方法中進(jìn)行初始化


//創(chuàng)建代理,做初始化操作
import flutter_boost
let flutterBoostDelegate = BoostDelegate()

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

iOS原生跳轉(zhuǎn)到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() {
        // 創(chuàng)建options,進(jìn)行open操作的構(gòu)建
        let options = FlutterBoostRouteOptions()
        options.pageName = "settingPage"
        options.arguments = ["data": "settingPage", "isPresent": false, "isAnimated": true]

        // 這個(gè)是push操作完成的回調(diào),而不是頁面關(guān)閉的回調(diào)!?。。?        options.completion = { _ in
            print("open operation is completed")
        }

        // 這個(gè)是頁面關(guān)閉并且返回?cái)?shù)據(jù)的回調(diào),回調(diào)實(shí)際需要根據(jù)您的Delegate中的popRoute來調(diào)用
        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
}

單獨(dú)調(diào)試某個(gè)flutter頁面示例,無需經(jīng)過集成到原生工程


Widget appBuilder(Widget home) {
    return const MaterialApp(
      home: MySettingPage(), // 這里是需要調(diào)試的頁面的名稱
      // home: home,
      debugShowCheckedModeBanner: false,

      ///必須加上builder參數(shù),否則showDialog等會(huì)出問題
      // builder: (_, __) {
      //   return home;
      // },
    );

將FlutterBoost添加到你的android工程依賴中,原生和flutter通信的各種情況如下:

  1. Android 原生攜帶參數(shù)打開flutter頁面

         HashMap<String, Object> map = new HashMap<>();//傳遞給flutter的參數(shù)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接收傳遞的數(shù)據(jù):

    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攜帶參數(shù)打開Android原生頁面

   var user = {
    'data' : 'number',
    'age': 'turtledoves'
  }; 
  MainActivity:打開Android原生的目標(biāo)頁面。user傳遞的參數(shù)

Android原生接收:
先發(fā)送消息到原生,原生收到消息后,進(jìn)行分發(fā)打開原生界面:

 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原生發(fā)送消息

    發(fā)送的key是data,value是一個(gè)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);

    注意://最后在清理的時(shí)候移除監(jiān)聽(比如onDestroy中) remover.remove();

  2. Android向Flutter發(fā)送消息

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

    flutter端接收:

```
///聲明一個(gè)用來存回調(diào)的對(duì)象
VoidCallback removeListener;

///添加事件響應(yīng)者,監(jiān)聽native發(fā)往flutter端的事件
removeListener = BoostChannel.instance.addEventListener("yourEventKey", (key, arguments) {
  ///deal with your event here
  return;
});

///然后在退出的時(shí)候(比如dispose中)移除監(jiān)聽者
removeListener?.call();
```
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 版本號(hào)0.1.54 看源碼之前,我先去看下官方文檔,對(duì)于其源碼的設(shè)計(jì)說明,文中所說的原生都是指android 看完...
    凸圖土吐閱讀 1,425評(píng)論 0 50
  • 目錄介紹 01.flutter和原生之間交互 02.MethodChanel流程 03.MethodChanel使...
    楊充211閱讀 881評(píng)論 0 4
  • 概述我們知道,在配置FlutterEngine的時(shí)候,有兩種方式可以設(shè)置初始路由,這個(gè)初始路由就是flutter第...
    Horps閱讀 2,934評(píng)論 0 1
  • 開發(fā)項(xiàng)目中Flutter問題總結(jié) 1.packages/flutter_tools/gradle/module_p...
    Miaoz0070閱讀 4,265評(píng)論 0 6
  • 面試必背 會(huì)舍棄、總結(jié)概括——根據(jù)我這些年面試和看面試題搜集過來的知識(shí)點(diǎn)匯總而來 建議根據(jù)我的寫的面試應(yīng)對(duì)思路中的...
    luoyangzk閱讀 7,165評(píng)論 6 173

友情鏈接更多精彩內(nèi)容