Flutter

前言

flutter 算是当前最火热的跨端技术了,能够使用同一套代码轻松接入到 iOS 及 Android 甚至是 Web,那么把 flutter 集成到原有的项目中一定是当前最快速及有效的应用 flutter 的方案。下面我记录一下我集成 flutter 及阿里的开源项目 flutter_boost 的方法。

集成 flutter

本例子代码集成到github 集成环境

flutter: 1.5.8
flutter_boost 0.1.54
1
2

新建及配置项目

新建一个 flutter 项目,项目必须是 flutter 混编到已有项目的模式

flutter create -t module flutter_module
1

新建一个 iOS 项目,或修改原有的 iOS 项目,在 Podfile 中修改

target 'firstApp' do
  ...
  flutter_application_path = './flutter_module'
  eval(File.read(File.join(flutter_application_path, '.ios', 'Flutter', 'podhelper.rb')), binding)
  ...
end
1
2
3
4
5
6

'./flutter_module'是本地 flutter 项目的地址,我的 flutter 项目就在 iOS 项目的目录下(跟 Podfile 文件同级),也可以使用绝对地址,然后运行pod install

然后在项目的 Build Parse 的 Run Script 中添加

"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh" build
"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh" embed
1
2

没有 Run Script 的点击+新建一个,然后启动 iOS 项目。

修改 iOS 代码

在 AppDelega.m 中

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    ...
    [GeneratedPluginRegistrant registerWithRegistry:self];
    return YES;
}
1
2
3
4
5

添加按钮到 ViewController.m

- (void)viewDidLoad {
    [super viewDidLoad];
    UIButton *fbutton = [UIButton buttonWithType:UIButtonTypeCustom];
    [fbutton addTarget:self
               action:@selector(routerTo)
     forControlEvents:UIControlEventTouchUpInside];
    [fbutton setTitle:@"通过Flutter跳转" forState:UIControlStateNormal];
    [fbutton setBackgroundColor:[UIColor blueColor]];
    fbutton.frame = CGRectMake(80.0, 410.0, 160.0, 40.0);
    [self.view addSubview:fbutton];
}
1
2
3
4
5
6
7
8
9
10
11

在 ViewController.m 中添加按钮点击事件并 push 到 flutter 页面,并在 flutter 页面上方添加一个按钮返回到 Native 页面

- (void)routerTo{
    FlutterViewController *flutterViewController = [[FlutterViewController alloc] init];
    UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
    [button addTarget:self
               action:@selector(handleButtonAction)
     forControlEvents:UIControlEventTouchUpInside];
    [button setTitle:@"返回" forState:UIControlStateNormal];
    [button setBackgroundColor:[UIColor blueColor]];
    button.frame = CGRectMake(80.0, 210.0, 160.0, 40.0);
    [flutterViewController.view addSubview:button];
    flutterViewController.view.backgroundColor = [UIColor cyanColor];
    [flutterViewController setInitialRoute:@"route1"];
    [self presentViewController:flutterViewController animated:NO completion:nil];
}
- (void)handleButtonAction{
    [self dismissViewControllerAnimated:YES completion:nil];
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

主要用了 presentViewController 及 dismissViewControllerAnimated 方法进行跳转及返回。

预览:

flutter跳转

iOS 集成 flutter_boost

flutter 配置 flutter_boost

下载 flutter_boost,在 pubspec.yaml 添加

flutter_boost: 0.1.54
1

执行flutter pub get

在 lib/main.dart 文件中修改: 添加

FlutterBoost.singleton.registerPageBuilders({
  'first': (pageName, params, _) => MyHomePage(),
  'second': (pageName, params, _) => SecondPage(),
});
1
2
3
4

及在 MaterialApp 中修改

builder: FlutterBoost.init(),
1

完整代码大致如下:

import 'package:flutter_boost/flutter_boost.dart';
  ...
  void initState() {
    // TODO: implement initState
    super.initState();
    FlutterBoost.singleton.registerPageBuilders({
      'first': (pageName, params, _) => MyHomePage(),
      'second': (pageName, params, _) => SecondPage(),
    });
  }
  
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      builder: FlutterBoost.init(),
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
  ...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

修改 iOS 代码

新建 MyFlutterRoute.h 文件

#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#import <flutter_boost/FlutterBoost.h>

NS_ASSUME_NONNULL_BEGIN

@protocol FLBPlatform;
@interface MyFlutterRouter : NSObject<FLBPlatform>
@property (nonatomic,strong) UINavigationController *navigationController;
@end

NS_ASSUME_NONNULL_END
1
2
3
4
5
6
7
8
9
10
11
12

新建 MyFlutterRoute.m 文件

#import "MyFlutterRouter.h"
#import <flutter_boost/FlutterBoost.h>

@interface MyFlutterRouter()
@end

@implementation MyFlutterRouter


- (void)open:(NSString *)name
   urlParams:(NSDictionary *)params
        exts:(NSDictionary *)exts
  completion:(void (^)(BOOL))completion
{
    BOOL animated = [exts[@"animated"] boolValue];
    FLBFlutterViewContainer *vc = FLBFlutterViewContainer.new;
//    self.navigationController=[[UINavigationController alloc]initWithRootViewController:vc];
    [vc setName:name params:params];
    [self.navigationController pushViewController:vc animated:animated];
    if(completion) completion(YES);
}

- (void)present:(NSString *)name
      urlParams:(NSDictionary *)params
           exts:(NSDictionary *)exts
     completion:(void (^)(BOOL))completion
{
    BOOL animated = [exts[@"animated"] boolValue];
    FLBFlutterViewContainer *vc = FLBFlutterViewContainer.new;
    [vc setName:name params:params];
    [self.navigationController presentViewController:vc animated:animated completion:^{
        if(completion) completion(YES);
    }];
}

- (void)close:(NSString *)uid
       result:(NSDictionary *)result
         exts:(NSDictionary *)exts
   completion:(void (^)(BOOL))completion
{
    BOOL animated = [exts[@"animated"] boolValue];
    animated = YES;
    FLBFlutterViewContainer *vc = (id)self.navigationController.presentedViewController;
    if([vc isKindOfClass:FLBFlutterViewContainer.class] && [vc.uniqueIDString isEqual: uid]){
        [vc dismissViewControllerAnimated:animated completion:^{}];
    }else{
        [self.navigationController popViewControllerAnimated:animated];
    }
}
@end
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50

在 AppDelega.h 中添加 flutter_boost 并继承 FLBFlutterAppDelegate

#import <UIKit/UIKit.h>
#import <Flutter/Flutter.h>
#import <flutter_boost/FlutterBoost.h>
#import "ViewController.h"
@interface AppDelegate : FLBFlutterAppDelegate <UIApplicationDelegate>
@property (strong, nonatomic) UIWindow *window;
//用来保存app的路由
@property (strong, nonatomic) UINavigationController *navController;
@end
1
2
3
4
5
6
7
8
9

然后在 AppDelega.m 中修改

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

    // 代码是将首页指向ViewController并初始化UINavigationController
    UIWindow *window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
    self.window = window;
    ViewController *vc = [ViewController new];
    UINavigationController *nav=[[UINavigationController alloc] initWithRootViewController:vc];
    [nav setNavigationBarHidden:(YES) animated:(NO)];
    self.window.rootViewController =nav;
    [self.window makeKeyAndVisible];

    // 初始化flutter_boost并给MyFlutterRouter初始化navigationController
    MyFlutterRouter *router = [MyFlutterRouter new];
    router.navigationController=nav;
    [FlutterBoostPlugin.sharedInstance startFlutterWithPlatform:router
                                                        onStart:^(FlutterEngine *fvc){
     }];
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

然后在 ViewController 中添加按钮并添加跳转事件

...
    UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
    [button addTarget:self
               action:@selector(flutterBoostRoute)
     forControlEvents:UIControlEventTouchUpInside];
    [button setTitle:@"通过Flutter Boost跳转" forState:UIControlStateNormal];
    [button setBackgroundColor:[UIColor blueColor]];
    button.frame = CGRectMake(80.0, 210.0, 200.0, 40.0);
    [self.view addSubview:button];
...
- (void)flutterBoostRoute{
    //通过FlutterBoostPlugin插件跳转,最终会调用MyFlutterRoute的open方法
    //或者present方法(urlParams传参@{@"present":YES,kPageCallBackId:@"MycallbackId#1"})
    [FlutterBoostPlugin open:@"second" urlParams:@{kPageCallBackId:@"MycallbackId#1"} exts:@{@"animated":@(YES)} onPageFinished:^(NSDictionary *result) {
        NSLog(@"call me when page finished, and your result is:%@", result);
    } completion:^(BOOL f) {
        NSLog(@"page is opened");
    }];
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

效果:

flutter跳转

Last Updated: 8/12/2020, 1:34:59 PM