第三代GUI构建器:一个工作区覆盖所有表单
[LOADING...]
我们再次重建了 Codename One GUI 构建器。这是它的第三代。有意思的不是又一个拖放界面,而是我们保留了什么、Maven 打破了什么,以及为什么可视化编辑器必须理解整个项目,而不是一次打开一个生成的表单。
与 Steve Hannah 构建的第二代相比,这是一次规模更小的重写。他的引导式布局工作仍然是基础。PR #5523 用 Maven 优先的 Codename One 应用替换了外围外壳,让你无需离开工作区即可在表单、CSS 和 Java 之间切换。
本周一览
- 第三代 GUI 构建器 现在是一个项目工作区,通过
mvn cn1:guibuilder启动。 - 应用加固 在平台构建拆分之前应用重命名、字符串加密和选定的控制流变换。后续文章将于周六发布。
- iOS 设备端调试器 不再在复用的局部槽位被误认为对象时崩溃。
- 平台状态和 Linux 视频 现在会报告跳过的测试,而不是将其计为通过。同一工作还修复了三个 GStreamer 缺陷。
- Google 登录 升级到 7.1 版本,因此 Apple Silicon 模拟器可以获得真正的 arm64 模拟器切片。
- ParparVM 内存回收 现在会在小对象峰值过后将多余的 BiBOP 页面归还给操作系统。
- 缺失和遗留的 URL 现在会指向恢复页面,而不是赤裸裸的 404。
三代构建器,三个不同的项目
第一个 GUI 构建器源自我们在 Sun Microsystems 开发的工具。它将表单存储在资源文件中,并生成一个中央状态机。当 Codename One 仍然面向大约 2 MB 内存的功能机时,这个模型是合理的。
第二代将表单分离为可读的 .gui XML 和配套的 Java。Steve 在 LayeredLayout 之上构建了自动布局,包括智能边距、兄弟引用、尺寸匹配、基线对齐和多选。对于现代应用来说,这是一个好得多的模型,但编辑器仍然从选定的表单打开。
最后一个假设在 Maven 迁移后变得痛苦。一个 Maven 项目在 src/main/guibuilder 下有表单,在 src/main/java 下有 Java,在 src/main/css/theme.css 下有样式。为每个生成的表单启动一个单独的编辑器,使得导航成为可视化工具中最慢的部分。
[LOADING...]
第三代将工作单元从文件改为项目。它扫描每个 .gui 文件,将其保存在左侧面板中,在中心渲染选定的表单,并在右侧显示其属性、布局和事件。
[LOADING...]
一个 Maven 目标即可打开项目
创建表单并从项目根目录打开编辑器:
第一个目标创建属于版本控制的成对文件:
第二个目标通过 Maven 解析 com.codenameone:codenameone-guibuilder,并将项目绑定传递给编辑器。IntelliJ IDEA、NetBeans、Eclipse 和 Visual Studio Code 现在都提供了调用同一目标的快捷键。编辑器本身仍然是 Java 8 构件,因此它可以在已经构建应用的 JDK 上运行。
切换表单不再启动另一个进程。表单选项卡由 src/main/guibuilder 的递归扫描支持,因此一个有二十个表单的项目就像一个有二十个表单的项目,而不是二十个互不相关的编辑器会话。
引导式布局在重写中幸存下来
我们没有用绝对坐标替换 Steve 的布局模型。在自动布局模式下放置的组件仍然是 LayeredLayout 子项,其边距可以引用父组件或另一个命名组件。
这是构建器演示项目中裁剪后的表单:
这些名称很重要。以对象指针形式存储的引导会在保存并重新加载后消失。以组件名称存储的引导会保留在磁盘上,这意味着模型必须拒绝重复名称,并在重命名、删除或粘贴组件时更新引用。
画布在你拖拽时添加关系。它可以对齐边缘、中心和文本基线。调整大小可以保持首选尺寸、填充父容器、保持固定或匹配另一个组件。同一个画布可以从手机竖屏切换到桌面宽度,这使得糟糕的关系在到达设备之前就能显现。
[LOADING...]
上面的移动不是存储为一组新的绝对坐标。它改变了 primary 和 description 之间的关系,然后让 LayeredLayout 为当前画布解析结果。
[LOADING...]
CSS 属于画布旁边
第二代构建器和旧资源编辑器是独立的工具。用户在我们 2016 年 GUI 构建器文章中的评论要求编辑器读取项目 CSS 并直接渲染它。第三代终于将其视为正常的工作流程。
点击 CSS,项目样式表会在实时表单旁边打开:
[LOADING...]
该窗格编辑真正的 src/main/css/theme.css。编辑去抖后,CSS 编译器安装新主题并重建预览。选择器变更会在相应元素上直观呈现:
没有第二个需要同步的主题模型。为画布着色的样式表就是 Maven 为应用编译的样式表。
生成的 Java 可见,但不可随意丢弃
Code 按钮会在同一工作区中打开配套的 Java 源码:
[LOADING...]
生成代码和用户代码有不同的归属:
嵌入式编辑器保护生成区域,而不是等到保存时覆盖它。事件处理程序留在用户区域并在重新生成后幸存。这消除了一个旧的时序问题,即一个 IDE 在保存时生成源码,而另一个 IDE 等待下一次构建。
.gui 文件仍然是纯 XML。你可以在拉取请求中审查它,并且无需专有数据库即可恢复它。当前编辑器在打开时不会监视手动编辑的 .gui 文件,因此请在外部编辑后使用 Refresh。
平台拆分前的一个加固策略
PR #5527 添加了一个开源加固引擎,它在合并后的应用成为 Android、iOS、JavaScript、Windows、Linux 或 JavaSE 输出之前运行。目标是获得 DexGuard 级别的抵抗力,而不会保护一个平台却让其他平台暴露在外。
该策略有意感知平台。Android 保留 R8 作为其唯一的重命名工具。JavaScript 跳过字符串加密,因为其原生桥接可以持有实时字符串引用。ParparVM 跳过与其优化器冲突的控制流变换。公共流水线仍然提供一个构建提示、一份报告和一个与崩溃保护关联的构建特定映射。
周六的 应用加固深度解析 涵盖了确切的平台矩阵、字符串加密排除项、保留规则、retrace 生命周期和本地构建边界。它还将加固与 App Shield 以及仍在审查中的加密数据库工作区分开来。
断点不再解引用一个随机局部变量
PR #5536 修复了当 NetBeans 在断点处请求局部变量时可能导致 iOS 应用崩溃的 signal 11 崩溃。一个调试器表为每个 JVM 槽位存储一个地址,但每个声明的局部变量占一行。将槽位复用于 int 后再用于对象,可能会将对象行与四个字节的整数存储配对,然后将其作为八个字节的对象指针解引用。
生成的表现在每行存储一个地址。帧进入会清除过期的调试器侧信道,对象引用在原生代码解引用之前会通过 Darwin 内存读取检查。同一 PR 还添加了真正的线程枚举、延迟断点重放、作用域局部变量和现成的设备端调试操作。
该 PR 围绕生成的 C 和 JDWP 代理添加了 66 个测试。它没有包含连接设备的调试会话,因此合并证明了策略和生成代码,而不是每个 IDE 和设备组合。
跳过的测试不是通过
PR #5538 发现截图跳过标记使用输出名称,而报告解析器只查看 Java 类名。标记消失了,周围的开始和结束行将测试计为通过。
纠正该映射暴露了 watchOS 上 11 个隐藏跳过、tvOS 上 6 个,以及其他每个平台上两到三个。未知标记现在会使报告契约失败,而不是消失。
同样的调查修复了 Linux VideoIO。CI 镜像缺少它声称要测试的编解码器插件。GStreamer 返回了一个部分流水线加上一个缺失元素的错误,但该平台忽略了该错误。读取器还向暂停的流水线请求普通样本,而解码帧仍然是预滚动缓冲区。Linux 现在安装编解码器、拒绝部分流水线、正确拉取预滚动帧,并且只报告 GStreamer 注册表中存在的编码器和解码器。
Google 登录现在可以在 arm64 模拟器中运行
PR #5544 将 iOS Google 登录集成从旧捆绑的 5.x 框架迁移到 GoogleSignIn 7.1。旧框架有 arm64 设备切片,但没有 arm64 模拟器切片。在 Apple Silicon Mac 上,链接器选择了设备切片并拒绝了它。
7.1 版本从源码为所选 SDK 构建。原生桥接现在使用完成处理器和当前令牌 API。我们停在 7.1,因为后续版本引入了 Swift 依赖,会强制将模块化头文件放入每个生成的 Podfile,包括与 Google 登录无关的项目。
小对象页面可以归还给操作系统
ParparVM 的 BiBOP 分配器按大小类别隔离小对象。在 PR #5540 之前,空页面永远留在该分配器中。因此,小对象的临时峰值可能会在之后排挤图像缓冲区、Metal 纹理或字形图集,即使小对象已被回收。
收集器现在保留一个 4 MB 的热池,并释放多余页面的槽位区域。在 Apple 平台上,它使用 MADV_FREE_REUSABLE,这会减少用于内存压力的 phys_footprint 值。一个受控集成测试预热了 192 MB 的 256 字节对象,然后分配了两组相同的大缓冲区集。测得的峰值从 466,224 KB 下降到 287,824 KB,而基准测试的几何平均值相对于无释放对照组保持在 1.0031。
Arm64 保留每个 64 KB 分配器页面的大约四分之一,因为其 16 KB 系统页面也包含分配器头。移动该头需要更大的分配器重新设计。
已退役的 URL 现在有了有用的去处
PR #5546 为旧插件和 Ant 时代链接添加了一个 /download/ 兼容性页面。新项目转到 Initializr 和入门指南。现有遗留项目转到 Maven 迁移指南。
通用 404 页面现在提供搜索以及指向设置、文档、演示、定价、社区和遗留下载的直接路由。它被标记为 noindex, nofollow;普通页面保持可索引。受约束的 _redirects 文件没有改变。
Initializr 现在通过 PR #5533 在 Codename One 7.0.265 上生成项目。
应用周边的工作是应用的一部分
GUI 构建器重写是关于让控制贴近你交付的构件。表单、CSS、生成的 Java 和响应式行为现在共享一个可检查的工作区。调试器、平台报告、内存分配器、登录桥接和恢复页面都消除了工具链之前隐藏真实状态的地方。
安全也遵循同样的方向。上周 App Shield 将最终信任决策从手机移到了后端。周六的 应用加固文章 涵盖了二进制层。开放的 可移植加密数据库 PR 解决了静态数据问题,目前仍在审查中。
这些控制解决不同的问题。它们共同将 Codename One 推向在每个边界都有安全默认值:二进制中的可读代码、调用服务器的被修改客户端,以及磁盘上的明文数据。与一个名字响亮的大复选框相比,这才是更有用的安全领先优势。
这篇文章 The Third-Generation GUI Builder: One Workspace for Every Form 首次出现在 foojay 上。