iOS使用Flutter_Boost管理頁面跳轉

上一篇文章介紹了如何集成Flutter_Boost,本篇將詳細介紹flutter如何與原生進行交互。

首先給出文章demo,具體代碼可作參考。

一:flutter_module項目使用FlutterBoost進行路由配置
import 'package:flutter/material.dart';
import 'package:flutter_boost/flutter_boost.dart';
import 'simple_page_widgets.dart';

void main() {
  run App(MyApp());
}

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  @override
  void initState() {
    super.initState();
    FlutterBoost.singleton.registerPageBuilders({
      'first': (pageName, params, _) => FirstRouteWidget(),
      'second': (pageName, params, _) => SecondRouteWidget(),
      'flutterPage': (pageName, params, _) {
        print("flutterPage params:$params");
        return FlutterRouteWidget(params:params);
      },
    });
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        title: 'Flutter example',
        builder: FlutterBoost.init(postPush: _onRoutePushed),
        home: Container());
  }

  void _onRoutePushed(
      String pageName, String uniqueId, Map params, Route route, Future _) {
  }
}

這里首先在Widget builder中初始化了FlutterBoost,然后在initState方法中通過FlutterBoost為三個頁面注冊了路由,這里注冊的路由是原生與flutter通用的,這個后面可以體現。

二:在Flutter頁面路由中使用FlutterBoost跳轉

總結在Flutter中有以下幾種跳轉方式:
1.Flutter=>Flutter(使用Flutter自己的路由)

Navigator.push(context, MaterialPageRoute(builder: (_) => FirstRouteWidget()));

以下三種跳轉方式,都是通過FlutterBoost進行跳轉,使用的是同一個方法,只是場景有所不同

FlutterBoost.singleton.open( String url,{Map<dynamic,dynamic> urlParams,Map<dynamic,dynamic> exts)

參數分別為:頁面名稱,通信傳參,擴展參數。對應相應跳轉方式使用如下:
2.Flutter=>Flutter(使用原生的navigationController)
例:first頁面打開路由名稱為second頁面,傳參為{"query": “aaa”},擴展參數中可以添加一些特殊數據,這里添加了{"animated": true},在原生中會解析為帶動畫跳轉

FlutterBoost.singleton.open( "second",urlParams: {"query": "aaa"}, exts: {"animated": true})

3.Flutter=>原生(push)
例:first頁面打開原生NativeViewController頁面,拼接native將在原生項目中解析為跳轉原生頁面,拼接push表明跳轉方式。

FlutterBoost.singleton.open( "native_push_NativeViewController",urlParams: {"query": "aaa"}, exts: {"animated": true})

4.Flutter=>原生(present)
同上,使用present跳轉方式。

FlutterBoost.singleton.open( "native_present_NativeViewController",urlParams: {"query": "aaa"}, exts: {"animated": true})

另外,Flutter關閉或返回上級頁面使用的是close方法,分為兩種
1.關閉當前頁面

FlutterBoost.singleton.closeCurrent(result: {}, exts: {});

2.通過id關閉指定頁面

FlutterBoost.singleton.close('id', result: {}, exts: {});
三:原生項目中配置路由通信
import Foundation

//實現FLBPlatform協議方法,flutter項目和原生項目使用FlutterBoost進行的跳轉都會通過該類進行處理
class PlatformRouterImp: NSObject, FLBPlatform {
    //處理打開原生頁面邏輯
    func openNative(_ url: String, urlParams: [AnyHashable : Any], exts: [AnyHashable : Any], completion: @escaping (Bool) -> Void) {
        var animated = false
        if exts["animated"] != nil{
            animated = exts["animated"] as! Bool
        }
        //與flutter端約定跳轉原生的url為三段式結構native_method_name
        let urlArr = url.components(separatedBy: "_")
        if urlArr.count == 3 {
            //通過類名找到相應頁面
            let cls : AnyClass? = NSClassFromString("TestWithFlutter." + urlArr[2])
            //該項目中的vc都繼承于BaseViewController,加了一個params用來接收Flutter傳過來的參數,另有方案的話改為UIViewController即可。
            if let clsType = cls as? BaseViewController.Type {
                let targetVC = clsType.init()
                targetVC.params = urlParams
                if urlArr[1] == "push" {
                    self.navigationController().pushViewController(targetVC, animated: animated)
                    completion(true)
                } else if urlArr[1] == "present" {
                    let navVC = UINavigationController(rootViewController: targetVC)
                    self.navigationController().present(navVC, animated: animated) {
                        completion(true)
                    }
                }
            }
        }
    }
    //FlutterBoost的open方法會在這里進行處理
    func open(_ url: String, urlParams: [AnyHashable : Any], exts: [AnyHashable : Any], completion: @escaping (Bool) -> Void) {
        if url.prefix(6) == "native" {//約定前面字符為native時跳轉原生頁面
            openNative(url, urlParams: urlParams, exts: exts, completion: completion)
        } else {//否則打開Flutter頁面
            var animated = false
            if exts["animated"] != nil{
                animated = exts["animated"] as! Bool
            }
            let vc = FLBFlutterViewContainer.init()
            vc.setName(url, params: urlParams)
            self.navigationController().pushViewController(vc, animated: animated)
            completion(true)
        }
    }
    //FlutterBoost的present方法會在這里進行處理,Flutter項目中不分present打開方式,都會走open方法
    func present(_ url: String, urlParams: [AnyHashable : Any], exts: [AnyHashable : Any], completion: @escaping (Bool) -> Void) {
        //直接present出的navVC,會導致flutter路由中uniqueid混亂,有待研究
//        var animated = false
//        if exts["animated"] != nil{
//            animated = exts["animated"] as! Bool
//        }
        let vc = FLBFlutterViewContainer.init()
        vc.setName(url, params: urlParams)
        let navVC = UINavigationController(rootViewController: vc)
        navVC.modalPresentationStyle = .fullScreen
        let delegate = UIApplication.shared.delegate as! AppDelegate
        delegate.window?.rootViewController = navVC
//        navigationController().present(navVC, animated: animated) {
//            completion(true)
//        }
    }
    //FlutterBoost的close方法會在這里進行處理
    func close(_ uid: String, result: [AnyHashable : Any], exts: [AnyHashable : Any], completion: @escaping (Bool) -> Void) {
        var animated = false;
        if exts["animated"] != nil{
            animated = exts["animated"] as! Bool
        }
        let presentedVC = self.navigationController().presentedViewController
        let vc = presentedVC as? FLBFlutterViewContainer
        if vc?.uniqueIDString() == uid {
            vc?.dismiss(animated: animated, completion: {
                completion(true)
            })
        }else{
            self.navigationController().popViewController(animated: animated)
        }
    }
    //獲取應用的navigationController,用來進行跳轉
    func navigationController() -> UINavigationController {
        let delegate = UIApplication.shared.delegate as! AppDelegate
        let navigationController = delegate.window?.rootViewController as! UINavigationController
        return navigationController
    }
}
四:在AppDelegate中初始化FlutterBoost
import UIKit
import Flutter

@UIApplicationMain
class AppDelegate: FlutterAppDelegate {
    
    override func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
        let router = PlatformRouterImp.init();
        FlutterBoostPlugin.sharedInstance().startFlutter(with: router, onStart: { (engine) in
        });
        
        self.window = UIWindow.init(frame: UIScreen.main.bounds)
        let viewController = ViewController.init()
        let navi = UINavigationController.init(rootViewController: viewController)
        self.window.rootViewController = navi
        self.window.makeKeyAndVisible()
        
        return true
    }
    
}
五:原生使用FlutterBoost進行跳轉

例:原生跳轉Flutter路由名為flutterPage的頁面

        FlutterBoostPlugin.open("flutterPage", urlParams:["query":"aaa"], exts: ["animated":true], onPageFinished: { (_ result:Any?) in
            print(String(format:"call me when page finished, and your result is:%@", result as! CVarArg));
        }) { (f:Bool) in
            print(String(format:"page is opened"));
        }
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容