将Flutter Module集成到iOS工程中

2022-07-18  本文已影响0人  handsome丶亮

1. Flutter环境搭建

1.1. 环境

1.2. 下载Flutter库文件

1.3. 下载安装Android Studio

1.4. 配置环境变量:

export PATH=~/Documents/flutter/bin:$PATH
export PUB_HOSTED_URL=https://pub.flutter-io.cn
export FLUTTER_STORAGE_BASE_URL=https://storage.flutter-io.cn

其中export PATH = 此处为flutter库文件安装路径/bin:$PATH。

1.5. 测试Flutter环境

1.6. 解决flutter doctor(flutter运行环境检测)的问题

2. 创建Flutter模块项目

2.1. Flutter模块项目创建

flutter_boost:
  git:
   url: 'https://github.com/alibaba/flutter_boost.git'
   ref: 'v3.0-null-safety-release.2.1'

2.2. Flutter模块项目代码

import 'package:flutter/material.dart';

/// flutter首页
class CMHomePage extends StatelessWidget {
  const CMHomePage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: TextButton(
            onPressed: () => _pushNativeViewController(),
            child: const Text("首页跳转原生界面")
        ),
      ),
    );
  }

  // 跳转原生界面
  _pushNativeViewController() {
    BoostNavigator.instance.push("TestViewController");
  }

}
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

/// flutter我的
class CMMinePage extends StatefulWidget {
  final String data;
  const CMMinePage({Key? key, required this.data}) : super(key: key);

  @override
  State<CMMinePage> createState() => _CMMinePageState();
}

class _CMMinePageState extends State<CMMinePage> {
  MethodChannel eventChannel = const MethodChannel('com.flutterToNative.test');

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Text("flutter我的,传输数据为:${widget.data}")
      ),
    );
  }
  
}
import 'package:cmcc_test_module/home.dart';
import 'package:flutter/material.dart';
import 'package:flutter_boost/flutter_boost.dart';
import 'mine.dart';
import 'home.dart';

// BoostFlutterBinding用于接管Flutter App的生命周期,必须得接入的
class CustomFlutterBinding extends WidgetsFlutterBinding with BoostFlutterBinding {
}

void main() {
  CustomFlutterBinding();
  runApp(const MyApp());
}

class MyApp extends StatefulWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  ///路由表
  static Map<String, FlutterBoostRouteFactory> routerMap = {
    'homePage': (settings, uniqueId) {
      return PageRouteBuilder<dynamic>(
          settings: settings,
          pageBuilder: (_, __, ___) {
            return const CMHomePage();
          });
    },
    'minePage': (settings, uniqueId) {
      return PageRouteBuilder<dynamic>(
          settings: settings,
          pageBuilder: (_, __, ___) {
            Map<String, dynamic>? map = settings.arguments as Map<String, dynamic>?;
            String data = map?['data'] as String ?? "";
            return CMMinePage(
              data: data,
            );
      });
    },
  };

  Route<dynamic>? routeFactory(RouteSettings settings, String? uniqueId) {
    FlutterBoostRouteFactory? func = routerMap[settings.name];
    if (func == null) {
      return null;
    }
    return func(settings, uniqueId);
  }

  Widget appBuilder(Widget home) {
    return MaterialApp(home: home, debugShowCheckedModeBanner: false);
  }

  @override
  Widget build(BuildContext context) {
    return FlutterBoostApp(
      routeFactory,
      appBuilder: appBuilder,
    );
  }

}

3. 集成Flutter工程到iOS工程中

platform:ios,'9.0'

flutter_application_path = './FlutterModule/cmcc_test_module'
load File.join(flutter_application_path, '.ios', 'Flutter', 'podhelper.rb')

target 'FlutterTest' do
install_all_flutter_pods(flutter_application_path)
end
//
//  BoostDelegate.h
//  FlutterTest
//
//  Created by mac on 2022/7/13.
//
//  原生界面跳转Flutter界面代理

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

NS_ASSUME_NONNULL_BEGIN

@interface BoostDelegate : NSObject<FlutterBoostDelegate>

// 设置导航控制器(外部必须设置,否则会导致无法跳转)
@property (nonatomic, strong) UINavigationController *navigationController;

// 创建单例
+ (instancetype)sharedInstance;

@end

NS_ASSUME_NONNULL_END

BoostDelegate.m

//
//  BoostDelegate.m
//  FlutterTest
//
//  Created by mac on 2022/7/13.
//

#import "BoostDelegate.h"

@implementation BoostDelegate

// 创建单例
+ (instancetype)sharedInstance{
    static BoostDelegate *myInstance = nil;
    if(myInstance == nil){
        myInstance = [[BoostDelegate alloc] init];
    }
    return myInstance;
}

// 跳转原生界面api,Flutter界面跳转原生界面,会自动调用此方法
-(void)pushNativeRoute:(NSString *)pageName arguments:(NSDictionary *)arguments {
    // 是否有动画
    BOOL animated = [arguments[@"animated"] boolValue];
    // 弹出方式
    BOOL present = [arguments[@"present"] boolValue];
    // 这里根据pageName来判断生成哪个vc
    UIViewController *vc;
    if ([pageName isEqualToString:@"TestViewController"]) {
        vc = [TestViewController new];
    }else{
        // 没有找到,则创建一个控制器作为容错
        vc = [UIViewController new];
    }
    if (present) {
        [self.navigationController presentViewController:vc animated:animated completion:^{
        }];
    } else {
        [self.navigationController pushViewController:vc animated:YES];
    }
}

// 当框架的withContainer为true的时候,会调用此方法来做原生的push
-(void)pushFlutterRoute:(FlutterBoostRouteOptions *)options {
    // 创建Flutter控制器
    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);
    }
}

// 当pop调用涉及到原生容器的时候,此方法将会被调用
-(void)popRoute:(FlutterBoostRouteOptions *)options {
    // 取出控制器
    FBFlutterViewContainer *vc = (id)self.navigationController.presentedViewController;
    // 判断控制器是否为Flutter控制器
    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.m
//  FlutterTest
//
//  Created by mac on 2022/7/13.
//

#import "AppDelegate.h"
#import <FlutterPluginRegistrant/FlutterPluginRegistrant-umbrella.h>
#import "BoostDelegate.h"
#import <flutter_boost/FlutterBoost.h>
#import "ViewController.h"

@interface AppDelegate ()

@end

@implementation AppDelegate


- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // 初始化window
    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
    ViewController *vc = [ViewController new];
    UINavigationController *navigation = [[UINavigationController alloc] initWithRootViewController:vc];
    self.window.rootViewController = navigation;
    [self.window makeKeyAndVisible];
    self.window.backgroundColor = [UIColor whiteColor];
    
    // 初始化FlutterBoost
    BoostDelegate *delegate = [BoostDelegate sharedInstance];
    delegate.navigationController = navigation;
    [[FlutterBoost instance] setup:application delegate:delegate callback:^(FlutterEngine *engine) {
    }];
    return YES;
}

@end
//
//  ViewController.m
//  FlutterTest
//
//  Created by mac on 2022/7/13.
//

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

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    self.view.backgroundColor = [UIColor whiteColor];
    
    UIButton *pushHomePageButton = [UIButton buttonWithType:UIButtonTypeSystem];
    pushHomePageButton.frame = CGRectMake(100, 200, 200, 100);
    [pushHomePageButton setTitleColor:[UIColor redColor] forState:UIControlStateNormal];
    [pushHomePageButton setTitle:@"跳转到Flutter首页" forState:UIControlStateNormal];
    [pushHomePageButton addTarget:self action:@selector(pushFlutterHomePage) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:pushHomePageButton];
    
    UIButton *pushMinePageButton = [UIButton buttonWithType:UIButtonTypeSystem];
    pushMinePageButton.frame = CGRectMake(100, 100, 200, 100);
    [pushMinePageButton setTitleColor:[UIColor blueColor] forState:UIControlStateNormal];
    [pushMinePageButton setTitle:@"跳转到Flutter我的" forState:UIControlStateNormal];
    [pushMinePageButton addTarget:self action:@selector(pushFlutterMinePage) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:pushMinePageButton];
}

// 跳转Flutter首页
- (void)pushFlutterHomePage {
    FlutterBoostRouteOptions *options = [FlutterBoostRouteOptions new];
    // 此处填写的页面名称,需要在Flutter Module项目中main的路由表中有对应的路由名称,否则会导致匹配不上跳转失败
    options.pageName = @"homePage";
    options.arguments = @{@"animated": @(YES)};
    options.completion = ^(BOOL completion) {
    };
    [[FlutterBoost instance] open:options];
    options.onPageFinished = ^(NSDictionary *dic) {
        NSLog(@"%@", dic);
    };
}

// 跳转Flutter我的
- (void)pushFlutterMinePage {
    FlutterBoostRouteOptions *options = [FlutterBoostRouteOptions new];
    options.pageName = @"minePage";
    options.arguments = @{@"animated": @(YES), @"data": @"原生界面参数传递"};
    options.completion = ^(BOOL completion) {
    };
    [[FlutterBoost instance] open:options];
    options.onPageFinished = ^(NSDictionary *dic) {
        NSLog(@"%@", dic);
    };
}

@end
//
//  TestViewController.m
//  FlutterTest
//
//  Created by mac on 2022/7/18.
//

#import "TestViewController.h"

@interface TestViewController ()

@end

@implementation TestViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    self.view.backgroundColor = [UIColor redColor];
}

@end

附:Demo下载

上一篇下一篇

猜你喜欢

热点阅读