FlutterBoost 实现Flutter页面内嵌iOS view

在使用Flutter混合开发中会遇到一些原生比Flutter优秀的控件,不想使用Flutter的控件,想在Flutter中使用原生控件。这时就会用到 Flutter页面中内嵌 原生view,这里简单介绍一个 内嵌 iOS 的view。

注:这里使用了 FlutterBoost。网上大部分都是代码执行不起来,本案例起码可以正常使用。

  • 原生部分
    这里开始在原生部分进行处理
  • 自定义 view FlutterIosTextLabel
bash 复制代码
#import <Foundation/Foundation.h>
#import <Flutter/Flutter.h>

NS_ASSUME_NONNULL_BEGIN

@interface FlutterIosTextLabel : 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
bash 复制代码
#import "FlutterIosTextLabel.h"

@implementation FlutterIosTextLabel

//在这里只是创建了一个UILabel
- (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.backgroundColor = [UIColor yellowColor];
      self.label.textColor = [UIColor redColor];
      self.label.textAlignment = NSTextAlignmentCenter;
      self.label.numberOfLines = 0;
      NSDictionary *dict = (NSDictionary *)args;
      NSString *textValue = dict[@"content"];
      self.label.text = [NSString stringWithFormat:@"我是iOSView \n在显示:%@", textValue];
  }
  return self;
}

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

@end
  • 创建 FlutterIosTextLabelFactory
bash 复制代码
#import <Foundation/Foundation.h>
#import <Flutter/Flutter.h>


NS_ASSUME_NONNULL_BEGIN

@interface FlutterIosTextLabelFactory : NSObject<FlutterPlatformViewFactory>

- (instancetype)initWithMessenger:(NSObject<FlutterBinaryMessenger>*)messenger;


@end

NS_ASSUME_NONNULL_END
bash 复制代码
#import "FlutterIosTextLabelFactory.h"
#import "FlutterIosTextLabel.h"



@implementation FlutterIosTextLabelFactory
{
    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 [[FlutterIosTextLabel alloc] initWithFrame:frame viewIdentifier:viewId arguments:args binaryMessenger:_messenger];
}

-(NSObject<FlutterMessageCodec> *)createArgsCodec{
    return [FlutterStandardMessageCodec sharedInstance];
}
  • 创建 FlutterIosTextLabelPlugin
bash 复制代码
#import <Foundation/Foundation.h>
#import <Flutter/Flutter.h>

NS_ASSUME_NONNULL_BEGIN

@interface FlutterIosTextLabelPlugin : NSObject<FlutterPlugin>
+ (void)registerWithRegistrar:(nonnull NSObject<FlutterPluginRegistrar> *)registrar;
@end

NS_ASSUME_NONNULL_END
bash 复制代码
#import "FlutterIosTextLabelPlugin.h"
#import "FlutterIosTextLabelFactory.h"

@implementation FlutterIosTextLabelPlugin

+ (void)registerWithRegistrar:(nonnull NSObject<FlutterPluginRegistrar> *)registrar {
    
    //注册插件
    //注册 FlutterIosTextLabelFactory
    //custom_platform_view 为flutter 调用此  textLabel 的标识
    [registrar registerViewFactory:[[FlutterIosTextLabelFactory alloc] initWithMessenger:registrar.messenger] withId:@"custom_platform_view"];
}
@end

到此原生已经集成完成一半,重点是接下来部分。

在 AppDelegate 中集成使用

修改AppDelegate.h:修改继承为FlutterAppDelegate,并删除window属性,因为FlutterAppDelegate中已经自带window属性

bash 复制代码
#import <UIKit/UIKit.h>
#import <Flutter/Flutter.h>

@interface AppDelegate : FlutterAppDelegate
@end

AppDelegate.m中引入相关头文件

bash 复制代码
#import "FlutterIosTextLabel.h"
#import "GeneratedPluginRegistrant.h"
#import "FlutterIosTextLabelPlugin.h"

在AppDelegate.m中注册插件,在引入 flutter_boost的情况下,需要等 flutter_boost初始化完成后,用FlutterEngine对插件进行初始化。

bash 复制代码
@interface AppDelegate ()

@end

@implementation AppDelegate


- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    HYFlutterBoostDelegate* delegate = [[HYFlutterBoostDelegate alloc]init];
    
    self.window = [[UIWindow alloc]initWithFrame:[UIScreen mainScreen].bounds];
    self.window.backgroundColor = [UIColor whiteColor];
    
    
    HYTabBarController *tab = [[HYTabBarController alloc]init];

    self.window.rootViewController = tab;
    [self.window makeKeyAndVisible];
    
    
    [FlutterBoost.instance setup:application delegate:delegate callback:^(FlutterEngine *engine) {
        NSLog(@"FlutterBoost 开始操作");
        // 使用 MethodChannel
        [HYFlutterNavChannel start];
        [HYFlutterCommonChannel start];

        
        // 初始化Flutter内嵌iOSView插件
//        NSObject<FlutterPluginRegistrar> *registrar = [engine registrarForPlugin:@"custom_platform_view_plugin"];
//        FlutterIosTextLabelFactory *factory = [[FlutterIosTextLabelFactory alloc] initWithMessenger:registrar.messenger];
//        [registrar registerViewFactory:factory withId:@"custom_platform_view"];
        
        // 升级处理
        NSObject<FlutterPluginRegistrar> *registrar = [engine registrarForPlugin:@"custom_platform_view_plugin"];
        [FlutterIosTextLabelPlugin registerWithRegistrar:registrar];
        
    }];
    
    return YES;
}


@end

到此原生集成完毕,接下来在 Flutter中进行集成

  • Flutter 部分
dart 复制代码
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

class CMNativePage extends StatelessWidget {
  const CMNativePage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text("详情"),
      ),
      body: const 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(),
    );
  }
}

注册路由

dart 复制代码
static const String nativaPage = '/nativaPage';
dart 复制代码
 nativaPage: (settings, uniqued) {
      return MaterialPageRoute(
          settings: settings,
          builder: (_) {
            return const CMNativePage();
          });
    },

在Flutter地方使用

dart 复制代码
 TextButton(
            child: const Text("加载原生控件"),
            onPressed: () {
              BoostNavigator.instance
                  .push(HYRouter.nativaPage, arguments: {"home": "home页面传递数值"});
              // showBottomWidget(context, const CMNativePage());
            },
          ),

到此Flutter中也完成集成。

如果想要某些弹出样式,自己再进行处理。这里只是简单的使用Flutter 内嵌 iOS原生view。

注意事项

  1. FlutterIosTextLabelFactory中的createArgsCodec方法一定不能遗漏,否则会导致传值不成功。类型也一定要和Dart部分的native.dart->IOSCompositionWidget-> UiKitView-> creationParamsCodec保持一致。否则会导致崩溃。
  2. 使用官方文档中的写法是没有问题,但是本案例中使用了flutter_boost,再跟着官网集成就会出现问题。需要更flutter_boost初始化完成,再对FlutterEngine对插件进行初始化。
  3. 其中withId:xxx,xxx代表控件的ID,需要和Dart部分的IOSCompositionWidget中的viewType保持一致。命名为:custom_platform_view
  4. 其中registrarForPlugin:xxx,xxx代表插件的ID。命名为:custom_platform_view_plugin
相关推荐
恋猫de小郭4 小时前
iOS + AI ,国外一个叫 Rork Max 的项目打算替换掉 Xcode
android·前端·flutter
左手厨刀右手茼蒿6 小时前
Flutter for OpenHarmony:dart_console 打造炫酷命令行界面,绘制表格、控制光标与进度条(CLI 交互库) 深度解析与鸿蒙适配指南
flutter·交互·harmonyos·绘制
加农炮手Jinx6 小时前
Flutter for OpenHarmony 实战:疯狂头像 App(三)— 复合动画与交互反馈 — 让 UI 跃动起来
flutter·ui·交互·harmonyos·鸿蒙
王码码20356 小时前
lutter for OpenHarmony 实战之基础组件:第六十二篇 SystemChannels — 探秘 Flutter 与系统交互的捷径
flutter·microsoft·交互·harmonyos
RaidenLiu8 小时前
别再手写 MethodChannel 了:Flutter Pigeon 工程级实践与架构设计
前端·flutter·前端框架
Bowen_J11 小时前
HarmonyOS 主流跨平台开发框架对比: ArkUI、Flutter、React Native、KMP、UniApp
flutter·react native·harmonyos
kevinli13 小时前
available没你想象中的可靠
ios·编译原理
九狼JIULANG14 小时前
Flutter SSE 流式响应用 Dio 实现 OpenAI 兼容接口的逐 Token 输出
flutter
恋猫de小郭1 天前
你是不是觉得 R8 很讨厌,但 Android 为什么选择 R8 ?也许你对 R8 还不够了解
android·前端·flutter
前端不太难1 天前
Flutter 页面切换后为什么会“状态丢失”或“状态常驻”?
flutter·状态模式