Flutter

iOS+Flutter--FlutterBoost(二)

2020-09-08  本文已影响0人  Red_Wang

iOS+Flutter--FlutterBoost(一)

上一章介绍了iOS项目如何集成FlutterBoost,这一章介绍使用FlutterBoost管理页面。

一、修改AppDelegate

import UIKit

// 导入Flutter
import Flutter
import flutter_boost

@UIApplicationMain
class AppDelegate: FlutterAppDelegate { //将UIResponder, UIApplicationDelegate替换为FlutterAppDelegate

    // var window: UIWindow?  //去除window声明,因为FlutterAppDelegate中已经声明

    override func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {

        self.window = UIWindow(frame: UIScreen.main.bounds)
        let rootViewController = UINavigationController(rootViewController: FirstViewController())
        self.window?.rootViewController = rootViewController
        self.window?.backgroundColor = .white
        self.window?.makeKeyAndVisible()

        let router: FLBPlatform = PlatformRouter()
        FlutterBoostPlugin.sharedInstance().startFlutter(with: router) { (flutterEngine) in
            print("#######  flutterEngine  #########")
        }

        return true
    }
}

二、添加PlatformRouter,代码如下:

import Foundation
import flutter_boost

class PlatformRouter: NSObject, FLBPlatform {
    
    func openNative(_ url: String, urlParams: [AnyHashable : Any],
                    exts: [AnyHashable : Any], animated: Bool,
                    completion: @escaping (Bool) -> Void) {
        
        let prefix = "nativebus://"
        guard url.hasPrefix(prefix) else {
            completion(false)
            return
        }
        
        let namespace = Bundle.main.infoDictionary!["CFBundleExecutable"] as! String
        let viewControllerName = String(url.dropFirst(prefix.count))
        guard let cls: AnyClass = NSClassFromString(namespace + "." + viewControllerName),
            let clsType = cls as? UIViewController.Type else {
            completion(false)
            return
        }
        let targetViewController = clsType.init()
        targetViewController.urlParams = urlParams
        self.navigationController().pushViewController(targetViewController, animated: animated)
    }
    
    func open(_ url: String, urlParams: [AnyHashable : Any],
              exts: [AnyHashable : Any], completion: @escaping (Bool) -> Void) {
        var animated = false
        if exts["animated"] != nil {
            animated = exts["animated"] as! Bool
        }
        
        guard url.hasPrefix("flutterbus://") else {
            //处理 nativebus: 页面
            openNative(url, urlParams: urlParams, exts: exts, animated: animated, completion: completion)
            return
        }
        
        let vc = FLBFlutterViewContainer()
        vc.setName(url, params: urlParams)
        navigationController().pushViewController(vc, animated: animated)
        completion(true)
    }
    
    func present(_ url: String, urlParams: [AnyHashable : Any], exts: [AnyHashable : Any],
                 completion: @escaping (Bool) -> Void) {
        var animated = false
        if exts["animated"] != nil {
            animated = exts["animated"] as! Bool
        }
        let vc = FLBFlutterViewContainer()
        vc.setName(url, params: urlParams)
        navigationController().present(vc, animated: animated) {
            completion(true)
        };
    }
    
    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 = navigationController().presentedViewController
        let vc = presentedVC as? FLBFlutterViewContainer
        if vc?.uniqueIDString() == uid {
            vc?.dismiss(animated: animated, completion: {
                completion(true)
            })
        } else {
            navigationController().popViewController(animated: animated)
        }
    }
    
    func navigationController() -> UINavigationController {
        let delegate = UIApplication.shared.delegate as! AppDelegate
        let navigationController = delegate.window?.rootViewController as! UINavigationController
        return navigationController;
    }
}

Flutter_Boost官方给出了FLBPlatform协议默认实现,具体可查看PlatformRouterImp,PlatformRouter在此基础上加了openNative代码

三、在FlutterBoostDemo module中配置路由页面

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

import 'FirstPage.dart';

void main() => runApp(MyApp());

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

class _MyAppState extends State<MyApp> {
  @override
  void initState() {
    super.initState();
    // 注册Native可以调用的页面
    FlutterBoost.singleton.registerPageBuilders({
      'flutterbus://FirstPage': (pageName, params, _) =>
          FirstPage(params: params),
    });
  }

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

四、Native 打开Flutter页面

通过FlutterBoostPlugin的open方法打开Flutter页面,代码如下

import UIKit
import Foundation
import flutter_boost

class FirstViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        title = "First Page"
        
        let button = UIButton(frame: CGRect(x: 80, y: 100, width: 200, height: 40))
        button.backgroundColor = .red
        button.setTitle("Native打开Fluter页面", for: UIControl.State.normal)
        button.titleLabel?.font = UIFont.systemFont(ofSize: 13)
        button.setTitleColor(.white, for: UIControl.State.normal)
        button.addTarget(self, action: #selector(openFlutterPage), for: UIControl.Event.touchUpInside)
        view.addSubview(button)
    }
    
    @objc func openFlutterPage() {
        let urlParams = ["startCount": 5] // 传入参数,Flutter可接收
        FlutterBoostPlugin.open("flutterbus://FirstPage", urlParams: urlParams, exts: [:], onPageFinished: { (map) in
           print(map)
        }) { (finished) in
        }
    }
}

五、Flutter打开Native页面

Flutter代码如下:

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

class FirstPage extends StatefulWidget {
  FirstPage({
    Key key,
    this.params,
  }) : super(key: key);

  final Map params; //Native传入

  @override
  State<StatefulWidget> createState() {
    _FirstPageState homeState = _FirstPageState();
    homeState.counter = params['startCount'];
    return homeState;
  }
}

class _FirstPageState extends State<FirstPage> {
  int counter;

  void _incrementCounter() {
    setState(() {
      counter++;
    });
  }

  void _stopCounter() {
    FlutterBoost.singleton.open("nativebus://SecondViewController",
        urlParams: {"message": "Flutter打开Native页面", "finalCount": counter});
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Row(
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
                Text(
                  '当前计数为:',
                ),
                Text(
                  '$counter',
                  style: Theme.of(context).textTheme.headline4,
                ),
              ],
            ),
            Padding(
              padding: EdgeInsets.all(12),
            ),
            Text(
              '点击下面按钮计数加1',
            ),
            FlatButton(onPressed: _incrementCounter, child: Icon(Icons.add)),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _stopCounter,
        tooltip: 'Stop',
        child: Icon(Icons.stop),
      ),
    );
  }
}

Native页面代码如下:

import UIKit

class SecondViewController: UIViewController {    
    
    override func viewDidLoad() {
        super.viewDidLoad()
        title = "Second Page"
        
        var count = 0
        if let params = urlParams as? [String: Any], let counter = params["finalCount"] as? Int {
            count = counter
        }
        
        let label = UILabel(frame: CGRect(x: 80, y: 100, width: 200, height: 40))
        label.text = "最终计数为\(count)"
        label.backgroundColor = .blue
        label.textColor = .white
        view.addSubview(label)
    }
}

其中urlParams是用UIViewController扩展添加的,代码如下:

import UIKit

private struct AssociatedKey {
    static var urlParams = "urlParams"
}

extension UIViewController {
    
    var urlParams: [AnyHashable : Any]? {
        set {
            objc_setAssociatedObject(self,
                                     &AssociatedKey.urlParams,
                                     newValue,
                                     .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
        get {
            var result: [AnyHashable : Any]?
            if let params = objc_getAssociatedObject(self, &AssociatedKey.urlParams) as? [AnyHashable : Any] {
                result = params
            }
            return result
        }
    }
}
上一篇下一篇

猜你喜欢

热点阅读