在集成flutter_boost的情况下实现Flutter页面内嵌iOSView

在集成了flutter_boost后,实现了flutter页面和iOS页面之间的互相跳转。如果我们又想在flutter页面中内嵌iOSView,我们需要怎么做?

1. Dart部分

  • 1.1. 新建native.dart,flutter混合原生view界面
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

/// flutter混合原生view
class CMNativePage extends StatelessWidget {
  const CMNativePage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return const Scaffold(
      body: Center(
        child: IOSCompositionWidget()
      ),
    );
  }
}

class IOSCompositionWidget extends StatelessWidget {
  const IOSCompositionWidget({super.key});

  @override
  Widget build(BuildContext context) {
    // This is used in the platform side to register the view.
    const String viewType = 'custom_platform_view';
    // Pass parameters to the platform side.
    final Map<String, dynamic> creationParams = {'content': 'Flutter传给IOSView的参数'};

    return UiKitView(
      viewType: viewType,
      creationParams: creationParams,
      creationParamsCodec: const StandardMessageCodec(),
    );
  }
}
  • 1.2. 在main.dart的路由表中,增加nativePage。供iOS原生进行跳转
'nativePage': (settings, uniqueId) {
      return PageRouteBuilder<dynamic>(
          settings: settings,
          pageBuilder: (_, __, ___) {
            return const CMNativePage();
          });
    },

2. iOS部分

  • 2.1. 新建FLNativeViewFLNativeViewFactory
    FLNativeView.h
#import <Foundation/Foundation.h>
#import <Flutter/Flutter.h>

NS_ASSUME_NONNULL_BEGIN

@interface FLNativeViewFactory : NSObject <FlutterPlatformViewFactory>
- (instancetype)initWithMessenger:(NSObject<FlutterBinaryMessenger>*)messenger;
@end

@interface FLNativeView : NSObject <FlutterPlatformView>

@property (nonatomic, strong) UILabel *label;

- (instancetype)initWithFrame:(CGRect)frame viewIdentifier:(int64_t)viewId arguments:(id _Nullable)args binaryMessenger:(NSObject<FlutterBinaryMessenger>*)messenger;

@end

NS_ASSUME_NONNULL_END

FLNativeView.m

#import "FLNativeView.h"

@implementation FLNativeViewFactory {
  NSObject<FlutterBinaryMessenger> *_messenger;
}

- (instancetype)initWithMessenger:(NSObject<FlutterBinaryMessenger>*)messenger {
  self = [super init];
  if (self) {
    _messenger = messenger;
  }
  return self;
}

- (NSObject<FlutterPlatformView>*)createWithFrame:(CGRect)frame viewIdentifier:(int64_t)viewId arguments:(id _Nullable)args {
  return [[FLNativeView alloc] initWithFrame:frame viewIdentifier:viewId arguments:args binaryMessenger:_messenger];
}

-(NSObject<FlutterMessageCodec> *)createArgsCodec{
    return [FlutterStandardMessageCodec sharedInstance];
}

@end

@implementation FLNativeView

- (instancetype)initWithFrame:(CGRect)frame viewIdentifier:(int64_t)viewId arguments:(id _Nullable)args binaryMessenger:(NSObject<FlutterBinaryMessenger>*)messenger {
  if (self = [super init]) {
      self.label = [UILabel new];
      self.label.textColor = [UIColor redColor];
      NSDictionary *dict = (NSDictionary *)args;
      NSString *textValue = dict[@"content"];
      self.label.text = [NSString stringWithFormat:@"我是iOS View,传值:%@", textValue];
  }
  return self;
}

- (nonnull UIView *)view {
    return self.label;
}

@end
  • 2.2. 其中FLNativeViewFactory中的createArgsCodec方法一定不能遗漏,否则会导致传值不成功。类型也一定要和Dart部分的native.dart->IOSCompositionWidget-> UiKitView-> creationParamsCodec保持一致。否则会导致崩溃:
  • 2.3. 修改AppDelegate.h:修改继承为FlutterAppDelegate,并删除window属性,因为FlutterAppDelegate中已经自带window属性
#import <UIKit/UIKit.h>
#import <Flutter/Flutter.h>

@interface AppDelegate : FlutterAppDelegate

@end
  • 2.4. 在AppDelegate.m中引入头文件
#import "FLNativeView.h"
#import "GeneratedPluginRegistrant.h"
  • 2.5. 在AppDelegate.m中注册插件,注意这里有非常大的坑。官方文档中是这么写的:
- (BOOL)application:(UIApplication *)application
    didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
  [GeneratedPluginRegistrant registerWithRegistry:self];
  NSObject<FlutterPluginRegistrar>* registrar = [self registrarForPlugin:@"plugin-name"];
  FLNativeViewFactory* factory = [[FLNativeViewFactory alloc] initWithMessenger:registrar.messenger];
  [[self registrarForPlugin:@"<plugin-name>"] registerViewFactory:factory withId:@"<platform-view-type>"];
  return [super application:application didFinishLaunchingWithOptions:launchOptions];
}

这样写本身是没问题的,但是在引入flutter_boost的情况下,就不能这么写了!正确的做法是,需要等flutter_boost初始化完成后,用FlutterEngine对插件进行初始化!代码如下:

- (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 = (UINavigationController *)self.window.rootViewController;
    [[FlutterBoost instance] setup:application delegate:delegate callback:^(FlutterEngine *engine) {
        // 初始化Flutter内嵌iOSView插件
        NSObject<FlutterPluginRegistrar> *registrar = [engine registrarForPlugin:@"custom_platform_view_plugin"];
        FLNativeViewFactory *factory = [[FLNativeViewFactory alloc] initWithMessenger:registrar.messenger];
        [registrar registerViewFactory:factory withId:@"custom_platform_view"];
    }];
    
    return YES;
}

如果按照官方相同的写法,跳转过去会一直是一个空白页面,不会有原生组件嵌入其中。这个问题,我查了很久网上都没有相关资料,希望能帮到后面遇到坑的人~

  • 其中withId:xxx,xxx代表控件的ID,需要和Dart部分的IOSCompositionWidget中的viewType保持一致。命名为:custom_platform_view
  • 其中registrarForPlugin:xxx,xxx代表插件的ID。命名为:custom_platform_view_plugin
  • 2.6. 在ViewController.m测试页面中,增加跳转Flutter页面的按钮和跳转方法
- (void)viewDidLoad {
    [super viewDidLoad];
    self.view.backgroundColor = [UIColor whiteColor];
  
    UIButton *pushFlutterNativePageButton = [UIButton buttonWithType:UIButtonTypeSystem];
    pushFlutterNativePageButton.frame = CGRectMake(100, 300, 300, 100);
    [pushFlutterNativePageButton setTitleColor:[UIColor blueColor] forState:UIControlStateNormal];
    [pushFlutterNativePageButton setTitle:@"跳转到Flutter混合原生view界面" forState:UIControlStateNormal];
    [pushFlutterNativePageButton addTarget:self action:@selector(pushFlutterNativePage) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:pushFlutterNativePageButton];
    
}

// 跳转Flutter混合原生view界面
- (void)pushFlutterNativePage{
    FlutterBoostRouteOptions *options = [FlutterBoostRouteOptions new];
    options.pageName = @"nativePage";
    options.arguments = @{@"animated": @(YES)};
    options.completion = ^(BOOL completion) {
    };
    [[FlutterBoost instance] open:options];
    options.onPageFinished = ^(NSDictionary *dic) {
        NSLog(@"%@", dic);
    };
}
  • 2.7. 最后重新执行pod install,重新将FlutterModule导入到项目中。运行iOS项目,跳转后得到正确结果:

3. 参考文档

附:Demo下载

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,284评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,115评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,614评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,671评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,699评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,562评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,309评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,223评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,668评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,859评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,981评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,705评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,310评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,904评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,023评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,146评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,933评论 2 355

推荐阅读更多精彩内容