Flutter 热更新及动态UI生成

2023-10-27

本系列相关文章:
Flutter 热更新及动态UI生成
Lua 15分钟快速上手(上)
Lua 15分钟快速上手(下)
Lua与C语言的互相调用
LuaDardo中Dart与Lua的相互调用

问题

由于Dart语言在Flutter上关闭了反射,且语言本身也缺乏动态能力,因此在Flutter上实现热更新或动态UI较为困难。

目前已有的一些动态方案:

  • 利用原生框架更新
  • 桥接动态脚本语言
  • 修改引擎(动态桥接增强版)
  • XML/JSON配置UI

以上方案,在我看来都不可取!原因这就来一一分析。

利用原生框架更新,实际上就是更新Flutter框架相关的二进制。Flutter应用发布出来的产物主要包括 libflutter.solibapp.soflutterAssets,这样,就可以通过Android端原生平台网络请求,动态下发并加载这些产物,从而实现动态更新。

那么为什么这种方案不可取呢?主要原因在于iOS 的应用商店不允许动态下发和加载二进制产物,包括动态库之类的,故此方案只能在Android端实现。我们学习和使用Flutter,其中最重要的一点就是要有跨平台思维,当然,这要求我们技术面要足够广泛,不能像原生开发一样局限于一隅。我们思考一个Flutter技术方案,首要思考的是能不能通用,如果不能通用,只能在一端使用,那么该方案就是没有意义的。Flutter的优势和生命力,在于跨平台,任何方案,如果使Flutter失去跨平台,那还不如使用原生技术开发,实现起来又成熟又快,还去瞎折腾Flutter干啥,岂不是浪费生命?

不管走多远,千万别忘了我们为什么出发的!

我们再来看一下桥接动态脚本语言的方案。本质上就是打包一个动态脚本语言Runtime,目前有打包JavaScript的,有打包Lua的。这些Runtime其实就是打包成C语言的一个动态库,看起来可行,其实与Dart语言交互十分困难。Dart语言目前的FFI接口能力非常弱,并不像Java的JNI一样成熟,通常只能Dart 调用C语言,C反过来调用Dart十分困难,因此它并不是互操作,只是单向调用。那么,通过FFI桥接Dart语言与目标语言(JS或Lua)互操作基本不可取。

那么再转换一下方向,通过Java 的JNI绑定脚本语言的Runtime是否可行呢?在Android原生上,通过JNI桥接Java语言与脚本语言是一种可行的方案,做得比较好的代表有Python的Kivy框架。Kivy就可以通过Python代码动态生成UI界面,但是作为Flutter,目标语言是Dart而不是Java,脚本语言能轻松反射Java类,但是与Dart交互仍然困难,要想交互,主要可以通过序列化,相当于Flutter插件机制一样,大量频繁操作,性能是一个问题。而且代码也很缺乏灵活性。

其实在此方案之上,还有一种增强方案,那就是修改Flutter引擎。Dart语言虚拟机本身是C++开发的,按理说,脚本语言通过C/C++与Dart交互是很容易的,就像Java JNI一样,这只是因为Dart的虚拟机并未暴露内部的C++接口,通过修改引擎,暴露接口,可以方便脚本语言直接调用Dart类。但此方案更不可取。目前Dart语言本身迭代就十分频繁了,变化也大,且其虚拟机十分复杂,可以遇见的,后续几乎无法维护自己拉取的引擎分支。

最后,我们来看一下,基于XML/JSON配置文件动态生成UI的方案。此方案对某些局部样式可能频繁变化的界面,其实是可行的,相当于应用主题一样。它的主要问题在于功能单一,只能针对特定模版的UI,且不能写逻辑,不灵活。

探索

以上分析了一些主要的动态化更新思路,这里给出我正在探索的解决方案。那就是 LuaDardo库。

LuaDardo是我用Dart语言编写的Lua虚拟机,它的名字是由葡萄牙语的两个单词组成,可以翻译成“镖中月”。

Lua本身是巴西人开发的一种以嵌入其他宿主语言为目标的简洁的高性能脚本语言,Lua在葡萄牙语中是月亮的意思。该语言多用于游戏开发,用Lua脚本编写业务逻辑,然后调用底层C++游戏引擎实现渲染。

Lua语言设计十分精巧,通过一个栈完成对宿主语言的互操作。LuaDardo直接使用Dart语言编写Lua虚拟机,这可以让我们以高性能的方式完成Lua与Dart语言的互操作。只需要对Flutter的Widget进行一定封装,将Dart类绑定到Lua语言中,即可使用Lua脚本编写UI界面。

另外,LuaDardo直接基于Dart开发,天然的具备跨平台能力,只要有Flutter的地方,就能使用。即使是Flutter的桌面应用,亦可具备这种动态脚本能力。

LuaDardo本身定位是基于Dart语言的虚拟机,我们要用Lua写Flutter界面,还需要对Flutter控件的封装扩展。

flutter_lua_dardo 就是一个这样的扩展库。该库主要用于包装Flutter接口和控件,这使得Flutter能够在需要经常改变UI风格的地方使用远程脚本动态地更新和生成界面。

请注意,flutter_lua_dardo 只是一个实验性的探索。它只封装了几个简单的Widget。欢迎其他人为Lua封装更多的Widget。

另外的,LuaDardo库已完成了大部分工作,只是Lua 自带的标准库尚未完全编写完毕,协程库、OS库、IO库等尚未开始。

例子

用法

新建 Lua 脚本 test.lua:

function getContent1()
    return Row:new({
        children={
            GestureDetector:new({
                onTap=function()
                    flutter.debugPrint("--------------onTap--------------")
                end,

                child=Text:new("click here")}),
            Text:new("label1"),
            Text:new("label2"),
            Text:new("label3"),
        },
        mainAxisAlign=MainAxisAlign.spaceEvenly,
    })
end

function getContent2()
    return Column:new({
        children={
            Row:new({
                children={Text:new("Hello"),Text:new("Flutter")},
                mainAxisAlign=MainAxisAlign.spaceAround
            }),
            Image:network('https://gitee.com/arcticfox1919/ImageHosting/raw/master/img/flutter_lua_test.png'
                ,{fit=BoxFit.cover})
        },
        mainAxisSize=MainAxisSize.min,
        crossAxisAlign=CrossAxisAlign.center
    })
end

添加依赖 pubspec.yaml

dependencies:
  flutter_lua_dardo: ^0.0.2

添加Dart代码:

class _MyHomePageState extends State<MyHomePage> {
  LuaState _ls;
  bool isChange = false;
    
  @override
  void initState() {
    loadLua();
    super.initState();
  }
  
  // 加载Lua虚拟机
  void loadLua() async {
    String src = await rootBundle.loadString('assets/test.lua');
    try {
      LuaState ls = LuaState.newState();
      ls.openLibs();
      FlutterLua.open(ls);
      FlutterWidget.open(ls);
      ls.doString(src);
      setState(() {
        _ls = ls;
      });
    } catch (e) {
      print(e);
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Container(
        alignment: Alignment.center,
        child: _ls == null
            ? CircularProgressIndicator()
             // 调用Lua函数,创建UI
            : FlutterWidget.findViewByName<Widget>(
            _ls, isChange ? "getContent2" : "getContent1"),
      ),
      floatingActionButton: FloatingActionButton(
        child: Icon(CupertinoIcons.arrow_swap),
        onPressed: (){
          setState(() {
            isChange = !isChange;
          });
        },
      ),
    );
  }
}

要了解如何绑定Dart类到Lua,你可以查看这个 示例.

关于 LuaDardo库, 请查看 这里.


关注我的公众号:编程之路从0到1
编程之路从0到1

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Flutter 热更新及动态UI生成 的相关文章

  • Flutter Firebase 身份验证:启动延迟

    我在应用程序中使用 Provider 和流 FirebaseAuth instance onAuthStateChanged 来决定启动时重定向到哪里 但是尽管用户已经登录 从之前的启动 但应用程序在登录屏幕上启动 几乎 1 秒后重定向到主
  • Dart/Flutter 如何编译到 Android?

    我找不到任何具体的资源 Dart 是否被编译到 JVM 或者 Google 的团队是否编译了 Dart VM 以在 JVM 上运行 然后在 JVM 内的 Dart VM 中运行 Dart 前者更有意义 并且符合 无桥 的口号 但后者似乎更符
  • Flutter Web URL 路由不适用于真实域

    我正在尝试使用一个网址来获取参数并将该参数分配给网络文件内的变量 例如 我的域名是 example com 在这个网站中我需要用户的 ID 我想制作 example com id 123 并获取 123 id 并给出变量 123 值 在 f
  • 在 Flutter 中的组件顶部覆盖一条线

    I have the following layout in one of my components and would like to put a line on top of that like this 这是我当前的代码 并且已经在
  • Flutter showDialog、AlertDialog背景渐变。

    对于颜色 我可以使用dialogBackgroundColor给予的财产AlertDialog背景我自己的颜色 我本来想用Gradient作为我的背景 我该如何使用它 DecoratedBox是需要的东西 但我不知道该用什么包裹起来 谁能给
  • 如何在 Android 中嵌入的 Flutter 应用中使用 --dart-define

    我将 Flutter 应用程序作为模块嵌入到现有的 Android 应用程序中 https flutter dev docs development add to app android project setup https flutte
  • 如何停止抖动中的计时器?

    我在 flutter 中创建了一个计时器 一切正常 现在我不知道如何在启动计时器后关闭它 文档说你可以通过调用取消它void cancel 但我不明白其实现 我该怎么称呼它 这是正确的方法吗 static const timeout con
  • 如何在flutter上关注android tv应用程序中的列表视图项目

    我想在 flutter 中构建一个 android 电视应用程序 几乎所有事情都已完成 但一个问题是我无法集中注意力 例如一些弹出效果或边框更改任何告诉用户您现在正在使用此项目的内容 我们在列表视图中迭代的项目 我想要在应用程序中看到的图像
  • 在Flutter中,如何使按钮和文本字段具有相同的高度?

    我知道TextField has TextStyle 其中有一个height财产 这只是一个基于的乘数fontSize 但是如何使所有小部件具有相同的高度 无论字体大小 此外 是否有以下等效方法 在几乎任何其他编程语言中 btnLogin
  • 使用键和值从地图创建小部件列表

    如果我说一个SimpleDialog 它接受children 我想从一个填充它Map
  • 所有侧面的 ElevatedButton 填充不会修改

    我有一个具有以下属性的 ElevatedButton 我在这里附上一张照片 https i stack imgur com oH3pO png https i stack imgur com oH3pO png ElevatedButton
  • flutter:如何使用共享首选项保存 List

    如何持久保存一个列表List
  • 非抽象类“InternalSelectableMathState”缺少这些成员的实现[关闭]

    Closed 这个问题需要调试细节 help minimal reproducible example 目前不接受答案 C src flutter pub cache hosted pub dartlang org flutter math
  • DraggableScrollableSheet 拖动时不会给出工作表的当前位置

    在flutter中我们有一个小部件可拖动可滚动表 现在我想要子元素拖动时的当前位置或当前大小 目前还没有办法获得该值 它在其构建器方法中提供了 ScrollController 但那是在列表滚动时而不是在拖动列表时 那么还有另一种方法可以跟
  • 是否可以从图像中获取图像 GPS 位置坐标?

    我正在构建一个 Flutter 应用程序 用户可以在其中发布照片及其位置 用户可以从相机或图库中获取图片 如果用户从相机拍照 我可以使用设备的 GPS 位置来设置图片的位置 我正在尝试根据图片的元数据获取图片的 GSP 位置 但是 我还没有
  • Flutter - 删除 ListView 中项目之间的空间

    我正在使用 ListView builder 函数来创建项目列表 然而 iOS 中每个项目之间的空间很大 截图 你知道如何删除项目吗 看来是默认的 因为我没有添加它 code 列表显示 return Scaffold body ListVi
  • Dart / flutter:DropdownButton 在值更改时导致异常

    我已经使用写了一个相当广泛的表格DropdownButton and TextField小部件 这个概念是我有一个StatefulWidget 其中的类State
  • 如何检测颤振中的滑动

    我尝试使用 flutter 的滑动检测器插件来实现向右滑动导航到新屏幕 但它不起作用 不会引发任何错误 并且在调试它时永远不会命中断点 我研究了 GestureDector 但我不确定它是否适用于向右滑动的场景 我们希望它在屏幕上的任何位置
  • Flutter:从 Hive 盒创建对象流

    我正在尝试访问一些在整个应用程序中更改和访问的用户设置 为此 我使用 Hive 从框中检索用户设置 我想通过转动UserSettings对象检索自Hive box settings get userID 到一个流中 该流将被馈送到Strea
  • 如何将资产图像转换为文件?

    有没有办法将资产图像用作文件 我需要一个文件 以便可以使用它通过 http 在互联网上进行测试 我尝试过 Stackoverflow com 的一些答案 如何使用 image file 加载图像 https stackoverflow co

随机推荐

  • 毕业设计-基于机器视觉的直道车道线识别技术-OpenCV

    目录 前言 课题背景和意义 实现技术思路 一 边缘检测 二 ROI 区域确定 三 基于 Hough 变换车道线识别 四 车道线拟合 代码部分 实现效果图样例 最后 前言 大四是整个大学期间最忙碌的时光 一边要忙着备考或实习为毕业后面临的就业
  • 关于微信H5自动播放视频-canvas实现逐帧动画效果加音频

    项目需求 用户进入页面自动播放一段小视频 解决方案一 利用 JS reload 之后执行 video play 和 video autoplay 都只能在WEB段实现 但是到了移动端就执行不了 因为项目应用了微信的JS SDK 所以只需要做
  • dereferencing type-punned pointer will break strict-aliasing rules

    最近遇到了一个编译告警 严格别名和类型双关 整理一下相关的材料 strict aliasing 以下问题摘自1 I have the following questions If I leave the code with this war
  • FFmpeg入门详解之70:获取音视频流信息(Metadata)

    用FFmpeg获取视频流 音频流的信息 编码格式 分辨率 帧率 播放时长 简介 我们经常需要知道一个媒体文件所包含的媒体流的信息 比如文件格式 播放时长 码率 视音频编码格式 视频分辨率 帧率 音频属性等信息 如何使用FFmpeg API获
  • 猿人学js混淆-源码乱码解法总结

    猿人学js混淆 源码乱码解法总结 网址 解法 心得 网址 js混淆 源码乱码网址 解法 我是在360浏览器下打开网址 进入审查元素 打开第2页 发现请求网址为 http match yuanrenxue com api match 1 pa
  • 阿里云Redis开发规范

    开发十年 就只剩下这套Java开发体系了 gt gt gt 一 键值设计 1 key名设计 1 建议 可读性和可管理性 以业务名 或数据库名 为前缀 防止key冲突 用冒号分隔 比如业务名 表名 id ugc video 1 2 建议 简洁
  • 十. Kubernetes 核心配置文件与kubelet命令

    目录 一 核心组件与对应的配置文件 二 kubelet 配置文件 常用命令 一 核心组件与对应的配置文件 在使用k8s时 内部有多个核心组件例如用来接收请求的apiServer 解析请求存储etcd的ControllerManage 用来存
  • C++模板类的使用以及运算符重载的实现

    一 类模板及运算符重载的实现 如同函数模板一样 使用类模板使用户可以为类定义一种模式 使得类中的某些数据成员 某些成员函数的参数 某些成员函数的返回值能取任意类型 类模板是对一批仅仅成员数据类型不同的类的抽象 程序员只要为这一批类所组成的整
  • 简明区块链原理

    链客 专为开发者而生 有问必答 此文章来自区块链技术社区 未经允许拒绝转载 区块链 应有特质 使用了具有 哈希链 下文有解释 形式的数据结构保存基础数据 有多个结点参与系统运行 分布式 通过一定的协议或算法对于基础数据的一致性达成共识 共识
  • R语言优雅的修改列名称

    说实话 我一直没有搞懂R语言的dpyr包的rename是怎么用的 很奇怪 我一直用不好这个函数 或者说 我就不太喜欢他这个更改表格列名称的方式 但是我今天在stackoverflow上看到了一个人是这么用的 非常的amazing 介绍 在修
  • JAVA中Object类的toString()方法

    toString public String toString 返回该对象的字符串表示 通常 toString 方法会返回一个 以文本方式表示 此对象的字符串 结果应是一个简明但易于读懂的信息表达式 建议所有子类都重写此方法 Object
  • vxe-table 固定列滚动完成后没有对齐

    vxe table 固定列滚动完成后没有对齐 默认情况下 虚拟滚动是自动开启的 当行数超过设置的 scroll y gt 时 就会自动触发虚拟渲染 即只渲染可视区内的数据 所以要想将性能达到最优 应该确保可视区内的显示条数尽可能减少 建议在
  • C/C++临时变量详解

    临时变量 临时变量是一种只在调用期间有效 且具有常性的变量 Date d1 2022 报错 因为该语句会先将2022赋值给临时变量 而临时变量是const的 无法直接赋值给d1 因为这是权限的放大 不合法 这段代码就是正确的 const D
  • Java中Robot类详解

    概述 Java中Robot类位于java awt Robot 该类用于为测试自动化 自运行演示程序和其他需要控制鼠标和键盘的应用程序生成本机系统输入事件 Robot类的主要目的是便于Java平台实现自动测试 Robot可以模拟鼠标和键盘的输
  • Confluence 6 缓存性能优化

    Confluence 的运行状态与缓存状态有这密切的关系 针对 Confluence 的管理员来说 尤其是大型站点的 Confluence 管理员 设置好缓存尤其显得关键 希望修改缓存的大小 进入 gt 基本配置 General Confi
  • 并行求和算法实现

    题目描述 有 N N N 个处理器 现对 N N N 个数求和 要求每个处理器中都保持全和 有两个算法可以实现 蝶式求和算法 重复计算元素的求和 共需要 l
  • cefsharp 在高DPI下闪烁的问题

    今天有客户朋友说程序在他的surface下界面很闪烁 搜索了相关的资料 初步判定是DPI引起的问题 但也有可能是cefsharp 51版本在WIN10上面没有禁用GPU加速 苦于没有环境测试 所以抱着尝试的心态让他做了如下设置 结果程序正常
  • js数组或对象除去重复元素的四种方法

    1 利用对象的属性名来存储不重复的元素或者说利用对象的属性名来筛选重复的元素 let arr 0 2 2 3 4 5 3 3 5 4 l a p l p a let obj let arrs let arrLength arr length
  • STM32 电机教程 14 - BLDC 电机速度闭环控制

    前言 无刷直流 Brushless Direct Current BLDC 电机是一种正快速普及的电机类型 它可在家用电器 汽车 航空航天 消费品 医疗 工业自动化设备和仪器等行业中使用 正如名称指出的那样 BLDC 电机不用电刷来换向 而
  • Flutter 热更新及动态UI生成

    本系列相关文章 Flutter 热更新及动态UI生成 Lua 15分钟快速上手 上 Lua 15分钟快速上手 下 Lua与C语言的互相调用 LuaDardo中Dart与Lua的相互调用 问题 由于Dart语言在Flutter上关闭了反射 且