美文网首页Android
在集成flutter_boost的情况下实现Flutter页面内

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

作者: handsome丶亮 | 来源:发表于2022-07-20 11:26 被阅读0次

    在集成了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下载

    相关文章

      网友评论

        本文标题:在集成flutter_boost的情况下实现Flutter页面内

        本文链接:https://www.haomeiwen.com/subject/ucseirtx.html