FlutterBoost 实现Flutter页面内嵌iOS view

news/2024/7/20 21:11:22 标签: ios, flutter, cocoa

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

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

  • 原生部分
    这里开始在原生部分进行处理
  • 自定义 view FlutterIosTextLabel
#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
#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
#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
#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
#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
#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属性

#import <UIKit/UIKit.h>
#import <Flutter/Flutter.h>

@interface AppDelegate : FlutterAppDelegate
@end

AppDelegate.m中引入相关头文件

#import "FlutterIosTextLabel.h"
#import "GeneratedPluginRegistrant.h"
#import "FlutterIosTextLabelPlugin.h"

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

@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 部分
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

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

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text("详情"),
      ),
      body: const Center(
        child: IOSCompositionWidget(),
      ),
    );
  }
}

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

  
  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(),
    );
  }
}

注册路由

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

在Flutter地方使用

 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

http://www.niftyadmin.cn/n/4944088.html

相关文章

Apache Doris 2.0.0 版本正式发布:盲测性能 10 倍提升,更统一多样的极速分析体验

亲爱的社区小伙伴们&#xff0c;我们很高兴地向大家宣布&#xff0c;Apache Doris 2.0.0 版本已于 2023 年 8 月 11 日正式发布&#xff0c;有超过 275 位贡献者为 Apache Doris 提交了超过 4100 个优化与修复。 在 2.0.0 版本中&#xff0c;Apache Doris 在标准 Benchmark 数…

UI和API自动化测试的失败原因

一、UI自动化失败原因&#xff1a; 界面发生了变化&#xff0c;但是脚本没有更新脚本中的等待时间太短了&#xff0c;导致元素还没出来就被判定为失败了网络因素&#xff0c;网络如果太慢的话&#xff0c;界面元素的显示就会滞后执行的时候突然弹出一个窗口影响了元素的定位Ag…

神经网络基础-神经网络补充概念-39-梯度消失与梯度爆炸

简介 梯度消失和梯度爆炸是在深度神经网络中训练过程中可能出现的问题&#xff0c;导致模型难以训练或无法收敛。这些问题与反向传播算法中的梯度计算有关。 概念 梯度消失&#xff08;Gradient Vanishing&#xff09;&#xff1a;在深层神经网络中&#xff0c;特别是具有很…

第7章 C控制语句:分支和跳转

本章介绍以下内容&#xff1a; 关键字&#xff1a;if、else、switch、continue、break、case、default、goto 运算符&#xff1a;&&、||、?: 函数&#xff1a;getchar()、putchar()、ctype.h系列 如何使用if和if else语句&#xff0c;如何嵌套它们 在更复杂的测试表达…

Buidler 专访|读懂波卡黑客松获胜产品和工具的创新

「2023 夏季波卡黑客松」大赛在上个月圆满落幕。对于参赛者而言&#xff0c;这是赛事的终点&#xff0c;亦是初创项目发展的新征程。为了给更多初创项目提供发展路径的范式参考&#xff0c;OneBlock 社区特别邀请了本届波卡黑客松大赛的冠军团队参与专访&#xff0c;分享他们自…

Spring三级缓存解决循环依赖问题

一、Bean对象的创建过程 一般的Bean对象如下&#xff1a;首先通过构造器构造一个普通对象&#xff0c;然后进行依赖注入&#xff0c;再进行一些初始化操作&#xff0c;初始化后根据AOP生成代理对象&#xff0c;最后再放入单例池map&#xff0c;这个单例池map就是一级缓存。 …

DAY3,ARM(LED点灯实验)

1.汇编实现开发板三盏灯点亮熄灭&#xff1b; .text .global _start _start: /**********LED123点灯**************/RCC_INIT:1使能PE10 PF10 PE8RCC..寄存器,E[4]1 F[5]1 0x50000a28ldr r0,0x50000a28ldr r1,[r0]orr r1,r1,#(0x3 << 4)str r1,[r0]LED1_INET:2初始化LED…

Visualizing and Understanding Convolutional Networks阅读笔记

Visualizing and Understanding Convolutional Networks阅读笔记 摘要1. 前言 [ 1 ] ^{[1]} [1]2. 使用反卷积网络可视化3. 卷积网络可视化 [ 2 ] ^{[2]} [2]3.1 特征可视化3.2 训练过程中特征的演化3.3 特征不变性3.4 架构选择3.5 遮挡敏感性 参考文章 摘要 CNN模型已经取得了…