flutter嵌入原生view

一、iOS端(Swift实现)

1. 新建原生view(NativeView.swift)

import Foundation
import Flutterclass NativeView: NSObject, FlutterPlatformView {private var _view: UIViewinit(frame: CGRect,viewIdentifier viewId: Int64,arguments args: Any?,binaryMessenger messenger: FlutterBinaryMessenger) {_view = UIView()super.init()}func view() -> UIView {self._view}
}

2. 新建工厂方法(NativeFactory.swift)

  1. flutter层,每次将UiKitView重新加入widget树时,都会触发create方法
  2. UiKitViewcreationParams属性会传递到createargs
  3. create方法内的framex=0, y=0, width=0, height=0,所以在flutter层获取的widget宽高传递到args
import Foundation
import Flutterclass NativeFactory: NSObject, FlutterPlatformViewFactory {private var messenger: FlutterBinaryMessengerinit(messenger:FlutterBinaryMessenger) {self.messenger = messengersuper.init()}func create(withFrame frame: CGRect, viewIdentifier viewId: Int64, arguments args: Any?) -> FlutterPlatformView {return NativeView(frame: frame,viewIdentifier: viewId,arguments: args,binaryMessenger: messenger)}func createArgsCodec() -> FlutterMessageCodec & NSObjectProtocol {return FlutterStandardMessageCodec.sharedInstance()}}

3. 注册原生view(AppDelegate.swift)

此处举例为AppDelegate处添加,也可在插件内添加

@objc class AppDelegate: FlutterAppDelegate {override func application(_ application: UIApplication,didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {// 其他代码GeneratedPluginRegistrant.register(with: self)let registrar:FlutterPluginRegistrar = self.registrar(forPlugin: "com.example.app.common_channel")!let factory = NativeFactory(messenger: registrar.messenger())registrar.register(instance.factory!, withId: "common_channel_native_view")}
}

此处的common_channel_native_view 需要牢记,会在flutter层使用

4. 嵌入flutter

UiKitView(viewType: "common_channel_native_view",creationParamsCodec: const StandardMessageCodec(),onPlatformViewCreated: (int viewId) {},creationParams: {},
)
  1. creationParamecreationParamsCodec需要同时使用
  2. 此处的viewId 是由flutter进行分配的,每次从widget树上移除再添加都会触发重分配,也会调用原生层工厂类的create方法

二、场景分析

1. 接入某摄像头设备

假设插件为:camera_plugin

摄像头设备提供的sdk对于直播和历史视频播放提供了封装的view (假设直播realView、历史视频historyView),即相关的画面播放、声音播放、实时对讲对需要通过sdk提供的view来完成。

生成三种methodChannel

  1. camera_plugin :处理通用的方法,如sdk初始化、下载录像、生成另外两种methodChannel等不涉及view的功能
  2. camera_plugin_\(camId):处理realView相关的方法
  3. camera_plugin_history_\(camId):处理historyView相关的方法

共用一个eventChannel

  • CameraPlugin.swift
public class CameraPlugin: NSObject, FlutterPlugin {public static let instance: LeCameraPlugin = LeCameraPlugin()private var factory: NativeFactory?private var eventSink: FlutterEventSink?;public static func register(with registrar: FlutterPluginRegistrar) {let channel = FlutterMethodChannel(name: "camera_plugin", binaryMessenger: registrar.messenger())let eventChannel = FlutterEventChannel(name: "camera_plugin_event", binaryMessenger: registrar.messenger())registrar.addMethodCallDelegate(instance, channel: channel)eventChannel.setStreamHandler(SwiftStreamHandler())instance.factory = NativeFactory(messenger: registrar.messenger())registrar.register(instance.factory!, withId: "camera_plugin_control")}class SwiftStreamHandler: NSObject, FlutterStreamHandler {func onListen(withArguments arguments: Any?, eventSink events: @escaping FlutterEventSink) -> FlutterError? {instance.eventSink = events// 将events传递给工厂类instance.factory?.updateEventSink(eventSink: events)return nil}func onCancel(withArguments arguments: Any?) -> FlutterError? {instance.eventSink = nilinstance.factory?.updateEventSink(eventSink: nil)return nil}}public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {switch call.method {case "prepare":self.prepare(argument: call.arguments, result: result)...default:result(FlutterMethodNotImplemented)}}// 根据设备ID,为不同的设备的realView和historyView生成methodChannelpublic func prepare(argument: Any?, result: @escaping FlutterResult) {if argument == nil {result(false)return}let arg = argument as! Dictionary<String, String>let camId = arg["camId"]if camId != nil {// 主要为此处factory?.createChannel(whithCamId: camId!)result(true)} else {result(false)}}
}
  • NativeFactory.swift
class NativeFactory: NSObject, FlutterPlatformViewFactory {private var messenger: FlutterBinaryMessengerprivate var eventSink:FlutterEventSink?private var camerasMethodChannel: [String: FlutterMethodChannel] = [:]private var camerasHistoryMethodChannel: [String: FlutterMethodChannel] = [:]init(messenger:FlutterBinaryMessenger) {self.messenger = messengersuper.init()}func createChannel(whithCamId camId: String) {if camerasMethodChannel[camId] == nil {let methodChannel = FlutterMethodChannel(name: "camera_plugin_\(camId)", binaryMessenger: messenger)camerasMethodChannel[camId] = methodChannel}if camerasHistoryMethodChannel[camId] == nil {let methodChannel = FlutterMethodChannel(name: "camera_plugin_history_\(camId)", binaryMessenger: messenger)camerasHistoryMethodChannel[camId] = methodChannel}}func updateEventSink(eventSink: FlutterEventSink?) {self.eventSink = eventSink}func create(withFrame frame: CGRect, viewIdentifier viewId: Int64, arguments args: Any?) -> FlutterPlatformView {let data = args as! Dictionary<String, Any>let camId = data["camId"] as! String// 判断是否为history,缺省为否let type = data["history"] as? Boollet methodChannel: FlutterMethodChannel?if type == true {if camerasHistoryMethodChannel[camId] == nil {createChannel(whithCamId: camId)}methodChannel = camerasHistoryMethodChannel[camId]return NativeHistoryView(frame: frame,viewIdentifier: viewId,arguments: args,binaryMessenger: messenger, methodChannel: methodChannel!) { key, payload in// 结构体自定义self.eventSink?(["key": key,"payload": payload])}} else {if camerasMethodChannel[camId] == nil {createChannel(whithCamId: camId)}methodChannel = camerasMethodChannel[camId]return NativeView(frame: frame,viewIdentifier: viewId,arguments: args,binaryMessenger: messenger, methodChannel: methodChannel!) { key, payload in// 结构体自定义self.eventSink?(["key": key,"payload": payload])}}}func createArgsCodec() -> FlutterMessageCodec & NSObjectProtocol {return FlutterStandardMessageCodec.sharedInstance()}}
  • 其他
  1. NativeHistoryViewNativeView就可以正常使用methodChanneleventChannel
  2. flutter 直接使用UiKitView即可
UiKitView(viewType: "camera_plugin_control",creationParamsCodec: const StandardMessageCodec(),onPlatformViewCreated: (int viewId) {},creationParams: {'camId': widget.mo.deviceId,'width': widget.width.ceil(),'height': widget.height.ceil(),},
)
  1. 一级页面有UiKitView时,二级页面也存在UiKitView时且共用同一个methodChannel,此时从二级页面回到一级页面时需要将UiKitViewwidget树上重新添加,以便将methodChannel重新绑定到UiKitView

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/808410.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

从文件夹(包含子文件夹)找到的包含特定关键词的 Word 文档复制到一个新的文件夹中

import os import glob import shutildef find_and_copy_docs(root_dir, keyword, target_dir):"""在指定的目录及其子目录下查找包含特定关键词的 Word 文档&#xff0c;并将它们复制到目标文件夹。参数:root_dir: 要搜索的根目录路径。keyword: 需要匹配的关键…

make/makefile学习

文章目录 1、makefile函数1.1、字符串替换函数&#xff1a;subst1.2、模式字符串替换函数&#xff1a;patsubst1.3、去空格函数&#xff1a;strip1.4、查找字符串函数&#xff1a;findstring 2、、:、&#xff1f;区别 1、makefile函数 1.1、字符串替换函数&#xff1a;subst …

TS中,PropType导入报错is a type and must be imported using a type-only import...

报错信息&#xff1a; PropType is a type and must be imported using a type-only import when verbatimModuleSyntax is enabled.ts(1484) (alias) type PropType<T> PropConstructor<T> | PropConstructor<T>[] import PropType问题分析&#xff1a; …

《QT实用小工具·二十》存款/贷款计算器

1、概述 源码放在文章末尾 该项目实现了用于存款和贷款的计算器的功能&#xff0c;如下图所示&#xff1a; 项目部分代码如下&#xff1a; #ifndef WIDGET_H #define WIDGET_H#include <QWidget>namespace Ui { class Widget; }class Widget : public QWidget {Q_OBJ…

构造函数,原型对象,对象实例 以及原型链的关系

当我们使用构造函数new的方式创建实例对象&#xff0c;此时构造函数的.prototype属性就是实例对象的原型对象&#xff0c;实例对象可以通过.__proto__来访问到原型对象&#xff0c;同时实例对象会继承原型对象的属性方法。 构造函数和原型对象的关系其实是被包含的关系&#x…

【电子通识】普通电阻、敏感电阻、可调电阻的种类和特点

电阻的作用 在【分立元件】理解电阻 中我们知道电阻是在电路中对电流产生阻碍作用的元件。电阻是电子产品中最基本、最常用的电子元件之一。 有各产品的电路板中基本都有电阻器&#xff0c;通常起限流、滤波或分压等作用。实际上&#xff0c;电阻器的种类很多&#xff0c;根据其…

中服云数字孪生平台 3.0 版全新升级!不仅更好看,而且更好用!

近日&#xff0c;中服云数字孪生平台迎来版本升级。中服云数字孪生平台 3.0 版&#xff0c;以物联网平台 数据中台为基础&#xff0c;以 2D/3D 为展示形式&#xff0c;旨在打造一个从设备数据到孪生应用的一站式数智化平台。 中服云数字孪生平台架构 新版升级 功能急速迭代 …

vue-router(进阶版)

前言 相信大家也是从我的路由初级篇那边过来的,没看的话也可以先从初级开始看,可以提高后续的理解能力 路由初级篇的链接 别的也就不多说了,直接开始 路由的主体构成 前言 之前的路由写法虽然可以使用但是会导致main.js过于臃肿,所以后续基本不会再这么使用了, 初始化路由 创…

4.Hexo 页面属性和模板设置

Frontmatter frontmatter基本上是可以定义的有关不同文件的信息&#xff0c;本质上是元数据 frontmatter是我们可以分配给每个内容页面的信息 在Hexo中创建文件时&#xff0c;Hexo主题可以使用该信息以不同的方式显示该内容 当在Hexo创建了一个文件&#xff0c;在source文件夹…

【JavaWeb】Tomcat服务器

目录 动态网站动态网站的特点 程序架构B/S与C/S的比较B/S技术的工作原理URL 什么是Web服务器 Web服务器、服务端、服务器的区别和联系什么是TomcatTomcat服务器的安装与配置解压缩版本Tomcat的配置添加系统变量&#xff0c;名称为CATALINA_HOME&#xff0c;值为Tomcat的安装目录…

Go-学会string的基本使用

本节重点&#xff1a; 学会 sting 的基本使用 字符串在 Go 中值得特别提及&#xff0c;因为与其他语言相比&#xff0c;string 的实现方式同其他语言略有不同。 什么是字符串&#xff1f; 字符串是 Go 中的字节切片。可以通过将一组字符括在双引号中来创建字符串" "…

OpenTelemetry——What is OpenTelemetry

What is OpenTelemetry? 什么是 OpenTelemetry&#xff1f; A short explanation of what OpenTelemetry is and isn’t. 对 OpenTelemetry 是什么和不是什么的简短说明 OpenTelemetry is an Observability framework and toolkit designed to create and manage telemetry d…

Qt中播放GIF动画

在Qt应用程序中&#xff0c;如果你想在QLabel控件上播放GIF动画&#xff0c;可以使用QMovie类与QLabel配合来实现。以下是详细步骤和代码示例&#xff1a; 步骤1&#xff1a;引入必要的头文件 首先&#xff0c;在你的源代码文件中包含QMovie和QLabel相关的头文件&#xff1a;…

Vue组合式函数,详细解析

什么是“组合式函数”&#xff1f;​ 在 Vue 应用的概念中&#xff0c;“组合式函数”(Composables) 是一个利用 Vue 的组合式 API 来封装和复用有状态逻辑的函数。 当构建前端应用时&#xff0c;我们常常需要复用公共任务的逻辑。例如为了在不同地方格式化时间&#xff0c;我们…

AONMIX和WAKEUPMIX的区别

在 ARM 芯片中&#xff0c;术语 AONMIX 指的是 i.MX 93 处理器的输入/输出多路复用控制器。让我们来详细了解一下&#xff1a; i.MX 93 处理器&#xff1a; i.MX 93 是恩智浦半导体公司开发的一种基于 ARM 的处理器。它通常用于各种嵌入式系统和应用。 IOMUX&#xff08;输入/…

js手写并发请求控制

关键点 new promise 一经创建&#xff0c;立即执行 使用 Promise.resolve().then 可以把任务加到微任务队列&#xff0c;防止立即执行迭代方法 微任务处理过程中&#xff0c;产生的新的执行微任务&#xff0c;会在同一事件循环内&#xff0c;追加到微任务队列里 使用 race 在…

【微命令】git 如何修改某个分支的名字(git branch -m newbranch)

简要信息&#xff0c;快速记录 命令 # 切换到某个需要修改的分支 git checkout oldbranch# 修改分支名字 git branch -m newbranch假设作为git设计者&#xff0c;要用来修改branch的命令&#xff0c;那么就是 git branch作为前缀&#xff0c;然后进一步修改的命令是branch相关…

gradio简单搭建——关键词简单筛选【2024-4-11优化】

gradio简单搭建——关键词简单筛选[2024-4-11 优化] 新的思路&#xff1a;标签自动标注界面搭建优化数据处理与生成过程交互界面展示 新的思路&#xff1a;标签自动标注 针对通过关键词&#xff0c;在文本数据中体现出主体的工作类型这一任务&#xff0c;这里使用展示工具grad…

2012年认证杯SPSSPRO杯数学建模A题(第二阶段)蜘蛛网全过程文档及程序

2012年认证杯SPSSPRO杯数学建模 A题 蜘蛛网 原题再现&#xff1a; 第二阶段问题   现在我们假设一个具体的环境。假设有一个凸多边形的区域&#xff0c;蜘蛛准备在这个区域&#xff08;或其一部分&#xff09;上结一张网。   问题一&#xff1a; 在区域的边界上安置有若干…

leetcode解题思路分析(一百五十五)1352 - 1358 题

最后 K 个数的乘积 请你实现一个「数字乘积类」ProductOfNumbers&#xff0c;要求支持下述两种方法&#xff1a; add(int num) 将数字 num 添加到当前数字列表的最后面。 getProduct(int k) 返回当前数字列表中&#xff0c;最后 k 个数字的乘积。 你可以假设当前列表中始终 至少…