flutter_boost在iOS端的简单使用

Flutter简介(摘自Flutter github

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

接入

在配置文件pubspec.yaml中加入依赖:

  flutter_boost: ^0.0.420

flutter_boost:
    git:
      url: 'https://github.com/alibaba/flutter_boost.git'
      ref: '0.0.420'

iOS端的简单实用(swift工程)

Flutter端示例代码:
  • 1、工程中app首页(一般为main.dart)添加如下代码:
import 'package:flutter_boost/flutter_boost.dart';
import './pages/TestDemoPage.dart';

// 此处的platform以及messageChannel在具体的page页面会用到, 他们是全局的实例对象
const MethodChannel platform = const MethodChannel("infosearch.flutter.io/flutterCallNative");
const BasicMessageChannel messageChannel = const BasicMessageChannel("infosearch.flutter.io/basic", StandardMessageCodec());

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

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

class _MyAppState extends State<MyApp>{
@override
  void initState() {
    super.initState();
    FlutterBoost.singleton.registerPageBuilders({
      'searchinfo_demo': (pageName, params, _) => TestDemoPage(params: params),
      'searchinfo_news_favorites': (pageName, params, _) => NewsList(params: params, pageName: pageName),
      'searchinfo_news_collection': (pageName, params, _) => NewsList(params: params, pageName: pageName),
      'searchinfo_news_history': (pageName, params, _) => NewsList(params: params, pageName: pageName),
    });
    FlutterBoost.handleOnStartPage();
  }

  @override
  Widget build(BuildContext context) {
    return new CupertinoApp(
      title: "Flutter Boost demo",
      debugShowCheckedModeBanner: false,
      builder: FlutterBoost.init(postPush: _onRoutePushed),
      home: Container(),
    );
  }

  void _onRoutePushed(String pageName, String uniqueId, Map params, Route route, Future _) {
    print('flutter main page name is $pageName');
  }
}
  • 2、接main中注册的TestDemoPage.dart页面代码:
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter_boost/flutter_boost.dart';
import 'package:flutter_module/main.dart';

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

  @required
  final Map params;

  _TestDemoPageState createState() => _TestDemoPageState();
}

class _TestDemoPageState extends State<TestDemoPage> {

void _receiveMessage() {
    messageChannel.setMessageHandler((message) async {
      print('message: $message, current page is ${widget.pageName}');
      return '返回Native端的数据';
    });
  }

@override
  void initState() { 
    super.initState();
  // 初始化后开始监听通过BasicMessageChannel从Native传递过来的数据
    _receiveMessage();
  }
// 通过调用方法关闭当前页面,back按钮可调用此函数
void _closeCurrentPage() {
    FlutterBoost.singleton.closePageForContext(context);
}

// 以下三个函数是通过MethodChannel实现Flutter调用Native的方法
 void _showLoading() async {
    await platform.invokeMethod('showLoading');
  }

  void _dismissLoading() async {
    await platform.invokeMethod('dismissLoading');
  }

  void _showTips() async {
    await platform.invokeMethod('showTips', {'tips': '请求失败,请稍后重试'});
  }

// 此方法需要绑定到具体的事件上去
void _openNativePage(dynamic obj) async {
      // 如果参数obj是model,需要调用model对应的类名.toJson()方法转为json对象
      Map<String, dynamic> jsonObj;
      // jsonObj = (obj as News.Result).toJson();
      
      // 因为我要跳转native的页面故加一个type字段
      // 每个Flutter的页面都是从native调用进行实例化FlutterViewContainer的
      // native通过解析此处的type字段决定跳转Native还是Flutter页面
      jsonObj["type"] = "App";
      FlutterBoost.singleton.openPage("news_detail", jsonObj);
}

@override
  Widget build(BuildContext context) {
    return new CupertinoPageScaffold(
      navigationBar: new CupertinoNavigationBar(
        backgroundColor: Color(0xffDB2C30),
        middle: Text(
          widget.params['title'],
          style: new TextStyle(color: CupertinoColors.white),
        ),
        leading: CupertinoButton(
            padding: EdgeInsets.only(top: 0, bottom: 0, left: 0),
            child: Icon(
              Icons.arrow_back,
              color: CupertinoColors.white,
            ),
            onPressed: () {
              _closeCurrentPage();
            }),
      ),

      child: new Container(),
    );
  } 
}
iOS端代码(swift):

主要实现一个类FlutterRouter.swift

import Foundation
import UIKit
import flutter_boost
import EasyNavigationbar

class FlutterRouter: NSObject, FLBPlatform {
    
    lazy var navigationController: UINavigationController? = {
        let nav = UIViewController.easy_currentViewController()?.navigationController
        return nav
    }()
    
    var _fvc: FlutterViewController?
    
    var fvc: FlutterViewController? {
        didSet {
            _fvc = fvc
            setupFlutterCallNative()
        }
    }
    
    private static var share: FlutterRouter?
    class func sharedRouter() -> FlutterRouter {
        guard let instance = share else {
            share = FlutterRouter.init()
            FlutterBoostPlugin.sharedInstance()?.startFlutter(with: share!, onStart: { (fvc) in
                DispatchQueue.main.asyncAfter(deadline: .now() + 0.001, execute: {
                    FlutterRouter.sharedRouter().fvc = fvc
                })
            })
            return share!
        }
        return instance
    }

    // Flutter调用此函数的方式: 
    // FlutterBoost.singleton.openPage("news_detail", jsonObj);
    // Native可直接调用
    func openPage(_ name: String, params: [AnyHashable : Any], animated: Bool, completion: @escaping (Bool) -> Void) {
        print("打开页面传递的参数 = \(params)")
        
        // ["type": "Flutter", "session": session, "title": "title"]
        guard let value = params["type"], let type = value as? String else {
            return
        }
        
        // type为调转目标为App or Flutter
        // params的所有键值对可以自己定义,我的格式是["type": "Flutter", "session": session, "title": "title"]
        switch type {
        case "App":
            // 跳转原生以及传递参数
            openNativeController(with: name, params: params, animated: animated)
        default:
            // 跳转Flutter页面以及传参
            if let isPresent = params["present"], (isPresent as? Bool) == true{
                let vc = CFLBFlutterViewContainer.init();
                vc.setName(name, params: params)
                navigationController?.present(vc, animated: animated, completion: {})
            } else {
                let vc = CFLBFlutterViewContainer.init();
                vc.setName(name, params: params)
                vc.hidesBottomBarWhenPushed = true
                navigationController?.easy_pushViewController(vc, animated: animated)
            }
        }
    }

     // Flutter调用此函数的方式: 
    //  FlutterBoost.singleton.closePageForContext(context);
    func closePage(_ uid: String, animated: Bool, params: [AnyHashable : Any], completion: @escaping (Bool) -> Void) {
        print("关闭页面传递的参数 = \(params)")
        if let vc = navigationController?.presentedViewController,
            vc.isKind(of: CFLBFlutterViewContainer.self),
            (vc as! CFLBFlutterViewContainer).uniqueIDString == uid{
            vc.dismiss(animated: animated, completion: {})
        } else {
            navigationController?.popViewController(animated: animated)
        }
    }
    
    func accessibilityEnable() -> Bool {
        return true
    }
    
    // 判断跳转原生各Native页面处理
    private func openNativeController(with pageName: String, params: [AnyHashable : Any], animated: Bool) {
        
        switch pageName {
        case "news_detail":
            let vc = UIViewController.init()
            navigationController?.easy_pushViewController(vc, animated: true)
        default:
            let vc = NativeViewController.init()
            vc.navBar.title = params["title"] as? String
            vc.hidesBottomBarWhenPushed = true
            navigationController?.easy_pushViewController(vc, animated: true)
        }
    }
    
    // MARK: FlutterCallNative Flutter调用Native在此处回调,处理完成还可以通过result(params)回调params数据给flutter使用
    private func setupFlutterCallNative() {
        // 用于Flutter 调用 Native
        // 这个channelname必须与Native里接收的一致
        guard let vc = _fvc else {
            return
        }
        let flutterCallNativeChannel = FlutterMethodChannel(name: "infosearch.flutter.io/flutterCallNative", binaryMessenger: vc)
        //FlutterMethodCall call, FlutterResult result
        flutterCallNativeChannel.setMethodCallHandler { (call, result) in
            print("method: \(call.method)")
            
            print("arguments: \(String(describing: call.arguments))")
            switch call.method {
            case "showLoading":
                YZTProgressHUD.show()
            case "dismissLoading":
                YZTProgressHUD.dismiss()
            case "showTips":
                if let arg = call.arguments as? [String: String], let tips = arg["tips"] {
                    YZTProgressHUD.showText(tips)
                }
            default:
                result(FlutterMethodNotImplemented)
            }
        }
    }
    
    // BasicMessageChannel在native的实现代码,需要发送消息给Flutter就调用此处函数:
    // FlutterRouter.sharedRouter().setupBasicMessageChannel(pageName: "collect")
    // 入参可以自定义,在Flutter端各页面可用此参数来区分是从哪里传递过来的数据
    func setupBasicMessageChannel(pageName: String) {
        if let vc = _fvc {
            let messageChannel = FlutterBasicMessageChannel.init(name: "infosearch.flutter.io/basic", binaryMessenger: vc)
            messageChannel.sendMessage(pageName)
        }
    }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,126评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,254评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,445评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,185评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,178评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,970评论 1 284
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,276评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,927评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,400评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,883评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,997评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,646评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,213评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,204评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,423评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,423评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,722评论 2 345