iOS集成Flutter Module以及flutter_boost使用

2,667 阅读3分钟

iOS集成Flutter Module以及flutter_boost使用

一 把Flutter当做成一个组件集成到iOS中

1.1 创建Flutter_Module (name必须为小写)

flutter create -t module name

1.2 引入相关依赖(.yaml)

  flutter_boost:

​    git:

​      url: 'https://github.com/alibaba/flutter_boost.git'

​      ref: 'v3.0-preview.9'

1.3 执行安装命令

flutter pub get

1.4 iOS原生工程Podfile修改以及导入

进入iOS原生工程的Podfile文件,写入
flutter_application_path = '../name_flutter' #这里是我们创建的flutter_module的路径
load File.join(flutter_application_path, '.ios', 'Flutter', 'podhelper.rb')

target 'iOSProjectName' do

 use_frameworks!

install_all_flutter_pods(flutter_application_path)

 \# Pods for nativeIOS

end

1.5 执行安装命令

pod install

二 flutter_boost使用(根据官方文档整理)

2.1 Dart部分的准备工作

新建CustomFlutterBinding with混入BoostFlutterBinding
//这里要特别注意,如果你的工程里已经有一个继承自WidgetsFlutterBinding的自定义Binding,则只需要将其with上BoostFlutterBinding
//如果你的工程没有自定义的Binding,则可以参考这个CustomFlutterBinding的做法
//BoostFlutterBinding用于接管Flutter App的生命周期,必须得接入的
class CustomFlutterBinding extends WidgetsFlutterBinding with BoostFlutterBinding {

}
main中初始化
void main() {
  //在runApp之前确保BoostFlutterBinding初始化
  CustomFlutterBinding();
  runApp(MyApp());
}
注册的路由表
  static Map<String, FlutterBoostRouteFactory> routerMap = {

​    'mainPage': (settings, uniqueId) {

​      return PageRouteBuilder<dynamic>(

​        settings: settings,

​        pageBuilder: (_, __, ___) {

​          Map<String, Object> map = settings.arguments;

​          String data = map['data'];

​          return MainPage(

​            data: data,

​          );

​        },

​      );

​    },

​    'simplePage': (settings, uniqueId) {

​      Map<String, Object> map = settings.arguments;

​      String data = map['data'];

​      return PageRouteBuilder<dynamic>(

​        settings: settings,

​        pageBuilder: (_, __, ___) {

​          return SimplePage(data: data);

​        },

​      );

​    }

  };
Main.dart完整代码
import 'package:flutter/material.dart';

import 'customFlutterBinding.dart';

import 'simplePage.dart';

import 'package:flutter_boost/flutter_boost.dart';

import 'main_page.dart';



void main() {

  CustomFlutterBinding();

  runApp(MyApp());

}



class MyApp extends StatelessWidget {

  static Map<String, FlutterBoostRouteFactory> routerMap = {

​    'mainPage': (settings, uniqueId) {

​      return PageRouteBuilder<dynamic>(

​        settings: settings,

​        pageBuilder: (_, __, ___) {

​          Map<String, Object> map = settings.arguments;

​          String data = map['data'];

​          return MainPage(

​            data: data,

​          );

​        },

​      );

​    },

​    'simplePage': (settings, uniqueId) {

​      Map<String, Object> map = settings.arguments;

​      String data = map['data'];

​      return PageRouteBuilder<dynamic>(

​        settings: settings,

​        pageBuilder: (_, __, ___) {

​          return SimplePage(data: data);

​        },

​      );

​    }

  };

  @override

  Widget build(BuildContext context) {

​    return FlutterBoostApp(routeFactory);

  }



  Route<dynamic> routeFactory(RouteSettings settings, String uniqueId) {

​    FlutterBoostRouteFactory func = routerMap[settings.name];

​    if (func == null) {

​      return null;

​    }

​    return func(settings, uniqueId);

  }

}

2.2 iOS端准备工作

新建BoostDelegate实现FlutterBoostDelegate完成原生和flutter页面切换操作
#import <Foundation/Foundation.h>
#import <flutter_boost/FlutterBoost.h>

NS_ASSUME_NONNULL_BEGIN

@interface BoostDelegate : NSObject<FlutterBoostDelegate>

@property (nonatomic, strong) UINavigationController *navigationController;

@end

NS_ASSUME_NONNULL_END


#import "BoostDelegate.h"
#import "ViewControllerDemo.h"
#import "ViewController.h"

@implementation BoostDelegate

-(void)pushNativeRoute:(NSString *)pageName arguments:(NSDictionary *)arguments {
    BOOL animated = [arguments[@"animated"] boolValue];
    BOOL present = [arguments[@"present"] boolValue];
    ViewControllerDemo *vc = [[ViewControllerDemo alloc]init];
    if (present) {
        [self.navigationController presentViewController:vc animated:animated completion:^{
            
        }];
    } else {
        [self.navigationController pushViewController:vc animated:YES];
    }
}

-(void)pushFlutterRoute:(FlutterBoostRouteOptions *)options {
    FBFlutterViewContainer *vc = FBFlutterViewContainer.new;
    [vc setName:options.pageName uniqueId:options.uniqueId params:options.arguments opaque:options.opaque];
    BOOL animated = [options.arguments[@"animated"] boolValue];
    BOOL present = [options.arguments[@"present"] boolValue] || !options.opaque;
    
    if (present) {
        [self.navigationController presentViewController:vc animated:animated completion:^{
            options.completion(YES);
        }];
    } else {
        [self.navigationController pushViewController:vc animated:animated];
        options.completion(YES);
    }
}

-(void)popRoute:(FlutterBoostRouteOptions *)options {
    FBFlutterViewContainer *vc = (id)self.navigationController.presentedViewController;
    NSDictionary *map = options.arguments;
    NSLog(@"%@", map);
    
    if ([vc isKindOfClass:FBFlutterViewContainer.class] && [vc.uniqueIDString isEqual:options.uniqueId]) {
        if (vc.modalPresentationStyle == UIModalPresentationFullScreen) {
            [self.navigationController.topViewController beginAppearanceTransition:YES animated:NO];
            [vc dismissViewControllerAnimated:YES completion:^{
                [self.navigationController.topViewController endAppearanceTransition];
            }];
        } else {
            [vc dismissViewControllerAnimated:YES completion:^{
                
            }];
        }
    } else {
        [self.navigationController popViewControllerAnimated:YES];
    }
    
}


@end

appdelegate中注册
#import <FlutterPluginRegistrant/FlutterPluginRegistrant-umbrella.h>
#import "BoostDelegate.h"
#import <flutter_boost/FlutterBoost.h>
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

    
    BoostDelegate *delegate = [[BoostDelegate alloc]init];
    [[FlutterBoost instance] setup:application delegate:delegate callback:^(FlutterEngine *engine) {
    }];
    .....
}    

2.3 具体使用 iOS进入flutter页面 pageName需要和注册的路由名一致

    FlutterBoostRouteOptions* options = [[FlutterBoostRouteOptions alloc]init];
    options.pageName = @"mainPage"; 
    options.arguments = @{@"animated":@(YES)};
    options.completion = ^(BOOL completion) {
        
    };
    
    [[FlutterBoost instance]open:options];
    options.onPageFinished = ^(NSDictionary *dic) {
        NSLog(@"%@", dic);
    };

2.4 flutter进入原生或者返回原生iOS

      Model("open native page", () { ///忽略Model是啥

        //// 执行push时 如果找不到路由名,那么就会走上面的BoostDelegate push到原生
​        BoostNavigator.instance.push("homePage", arguments: {

​          'data': _controller.text

​        }).then((value) => showTipIfNeeded(value.toString()));

​      }),

​      Model("return to native page with data", () {

​        Map<String, Object> result = {'data': _controller.text};

​        BoostNavigator.instance.pop(result);

​        BoostChannel.instance

​            .sendEventToNative('TTT', {'data': _controller.text});

​      }),

2.5 iOS和flutter之间的参数传递

flutter部分
////接收消息
///声明一个用来存回调的对象
VoidCallback removeListener;

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

///然后在退出的时候(比如dispose中)移除监听者
removeListener?.call();
/// 发送消息给native
BoostChannel.instance.sendEventToNative("eventToNative",{"key1":"value1"});
iOS部分
@property (nonatomic, copy) FBVoidCallback removeListener;


    _removeListener = [[FlutterBoost instance] addEventListener:^(NSString *name, NSDictionary *arguments) {
        self->_label.text = arguments[@"data"];
    } forName:@"TTT"];
    
    
    [[FlutterBoost instance] sendResultToFlutterWithPageName:@"TTTT" arguments:@{
        @"aaa": @"1212"
    }];