Ohhnews

分类导航

$ cd ..
foojay原文

Mac原生构建、实时协议与开放问题数降至350以下

#mac原生构建#websocket#grpc#graphql#广告api

目录

开放问题数降至350以下 本周发布的内容

从截图构建界面,以及更简化的Initializr
值得了解的较小修复
关于贡献的说明
即将推出的亮点
总结

[LOADING...]

本周我们的工作焦点遍布各处,涵盖了桌面端、变现、通信、媒体等多个方向。这与我们的路线图一致:打造一个真正实现Java未能实现的承诺——"一次编写,随处运行"的通用平台。

但在深入介绍新功能之前,有一个数字让我特别自豪……

开放问题数降至350以下

当前开放问题数已低于350(撰写本文时为332)。这是我们主动梳理问题追踪列表的结果:关闭已修复的问题、复现未确认的问题,并直接修复了一批问题。本周关闭的部分报告自2015年起就处于打开状态。过程中我们偶尔会分心(看到老旧报告很难忍住不立即修复),但方向是明确的:我们希望这个数字持续下降,而且要大幅下降。

我们从最古老的问题开始,逐步向后排查。你可能还记得,当我们开始追踪这一数据时,突破500大关曾是一个重要里程碑——而那仅仅是几周前的事!

本周发布的内容

每一重大功能都有其深度教程。以下是概览,附有完整文章链接。

你的应用现在是原生Mac应用

你现有的Codename One应用无需任何移植工作即可立即以100%原生Mac应用的形式发布。无需重写、无需捆绑JVM、无需Electron外壳:你当前的项目能像生成iPhone应用一样,通过相同的Metal渲染器和经过实战检验的原生管道生成精炼的原生Mac二进制文件。而且它看起来就像真正的Mac应用,而非窗口化的手机应用:原生标题栏、原生菜单栏、交互式滚动条、桌面通知都一应俱全。本周功能中的两项在此一并呈现:下方示例使用稍后介绍的新广告API,以原生Mac应用形式运行,而代码与iOS和Android构建相同:

[LOADING...]

完整教程(包括新的桌面菜单和快捷方式API以及Mac签名提示)请参阅 你的Codename One应用,现在是原生Mac应用

核心中的WebSocket

com.codename1.io.WebSocket 现已成为框架的一部分,无需 cn1lib,并在每个端口上原生实现。建立实时连接只需一行流畅的代码:

$ java
WebSocket ws = WebSocket.build("wss://chat.example.com/room/general")
    .onConnect(() -> Log.p("connected"))
    .onTextMessage(text -> Display.getInstance()
        .callSerially(() -> addBubble(text, false)))
    .connect();

这是下方GraphQL订阅功能的基础,并且足够可靠,我们的截图CI已将其用作设备渲染的传输层。使用它构建实时聊天的动手教程请参阅 核心中的WebSocket、gRPC和GraphQL

根据你的Schema生成类型安全的GraphQL客户端

cn1:generate-graphql 将GraphQL Schema转换为类型安全客户端:你只需声明一个针对操作(operations)的接口,构建过程会自动生成实现,无需你编写任何HTTP管道。使用 @Subscription 可以通过新的核心WebSocket获取实时服务器推送更新:

$ java
@GraphQLClient("https://swapi.example.com/graphql")
public interface StarWarsApi {
    @Query("query HeroName($episode: Episode) { hero(episode: $episode) { name } }")
    void hero(@Var("episode") Episode episode,
              OnComplete<GraphQLResponse> callback);

    @Subscription("subscription OnReview($ep: Episode!) { reviewAdded(episode: $ep) { stars } }")
    GraphQLSubscription onReview(@Var("ep") Episode ep,
                                 GraphQLSubscription.Handler handler);
}

注意 Episode 是真正的枚举类型:枚举绑定已随此工作一同落地到JSON/XML映射器中,也修复了 @Mapped 用户长期以来的一个缺口。完整教程在 核心中的WebSocket、gRPC和GraphQL

无需protoc的gRPC客户端

cn1:generate-grpc 对proto3执行相同操作。指向你的 .proto 文件,它会生成消息、二进制protobuf编解码器和客户端,采用与Envoy及现代gRPC服务器兼容的标准gRPC-Web有线协议。无需安装 protoc,无需原生依赖;调用服务如下:

$ java
GreeterGrpc g = GreeterGrpc.of("https://api.example.com");
HelloRequest req = new HelloRequest();
req.name = "world";
g.sayHello(req, "Bearer " + token, response -> {
    if (response.isOk()) {
        renderGreeting(response.getResponseData().message);
    }
});

结合 cn1:generate-openapicn1:generate-graphql,这意味着只需一个Maven目标即可为几乎任何后端生成类型安全的客户端。从proto文件到运行调用的完整教程在 核心中的WebSocket、gRPC和GraphQL

全新广告API

原有的广告支持通过三种死胡同式的遗留机制悄然腐朽。一个新的可插拔、格式完整的 com.codename1.ads 子系统取代了它们,内置现代AdMob参考提供商、GDPR同意及iOS应用透明跟踪,以及一个模拟器占位提供商,让你无需设备即可测试每种格式。用户最常询问的激励广告现在只需以下简短代码:

$ java
RewardedAd ad = new RewardedAd("your-rewarded-ad-unit-id");
ad.setAdListener(new AdListener() {
    public void onLoaded() {
        ad.show(reward ->
            grantCoins(reward.getType(), reward.getAmount()));
    }
});
ad.load();

关于横幅广告、原生广告、开屏广告及提供商SPI的完整说明请参阅 全新广告API,从零构建

后台执行与推送

基于约束的后台工作、前台服务、推送主题、共享内容处理以及更丰富的本地通知API,所有这些都可在模拟器中使用,方便你在桌面端调试这些流程。你只需描述工作需要什么条件,而非指定轮询时间:

$ java
WorkRequest req = WorkRequest.builder("daily-sync", SyncWorker.class)
    .setRequiresNetwork(true)
    .setRequiresCharging(true)
    .setPeriodic(6 * 60 * 60 * 1000L)
    .build();
BackgroundWork.schedule(req);

从进度通知和内联回复到推送主题和共享内容的完整教程,请参阅 后台工作、推送主题与更丰富的通知

从截图构建界面,以及更简化的Initializr

生成的应用自带一个位于 .claude/skills/ 下的 codename-one 智能体技能(agent skill),因此在你项目中工作的AI智能体已经知道如何构建、测试和截图Codename One界面。PR #5161 教给它最常见的设计任务:"让这个界面看起来像这个模型图。"

该任务的难点在于智能体没有客观的衡量标准来评估接近程度。现有的截图测试仅能将渲染结果与系统自己生成的基准进行比较,这衡量的是一致性而非正确性。新的 CompareToMockup 工具是一个纯JDK的单文件CLI,它会对渲染结果与目标图像进行评分并输出相似度百分比:一个 STRUCTURAL 分数(基于SSIM的感知度量,对矢量模型图的字体和抗锯齿噪声具有鲁棒性)和一个 PIXEL 分数(在框架自身的三通道"相同像素"容差范围内的像素比例)。它支持区域模式,以免设备边框影响分数;支持 --diff 热力图;以及 --min 门槛。这为智能体提供了真实的信号:渲染 → 评分 → 查看热力图 → 调整 → 重复,直到分数不再增长。配套的 DesignImport 工具可将Figma、Sketch或Adobe XD文件(以及经过 PR #5168 后,来自HTML或React模型图的 tokens.css)转换为初始的 theme.css,使智能体从已有基础进行调整而非从零开始。该技能现在还能通过 UpdateSkills 工具自我更新,因此几个月前生成的项目可以拉取最新的指导,而非携带一份冻结的副本。

智能体现在可以自动将技能更新到最新版本,并描述Codename One GUI的内容。这一点很有价值,因为它们可以审查自己的工作,无需使用视觉识别——后者既更昂贵又不够准确。我们还增加了检查组件对齐的功能,这往往是LLM难以处理的问题。此外还有一个新的linter,我认为将来也应开放给人类开发者。目前你可以像智能体一样查看并使用所有这些工具,但它们更偏向CLI方式。

PR #5168 还围绕Codename One设计语言重建了Initializr(用于搭建新项目的工具),并进行了精简,使其更易于上手。它首先展示核心内容(主类、包名、Java/Kotlin切换开关),将IDE设置、本地化、Java版本和当前设置放在可折叠卡片中,底部有实时预览和单个生成按钮。原来的四模板选择器被替换为Java/Kotlin切换开关,并移除了强调色、圆角按钮和自定义CSS控制。背后的项目模型没有变化,因此生成的项目与之前相同;这纯粹是为了降低上手门槛。

[LOADING...]

值得了解的较小修复

其中几个直接来自问题跟踪器的梳理:

  • cubic-bezier() 动画现在符合CSS标准。 PR #5122 修复了 #1524Motion.createCubicBezierMotion 此前将其控制点直接馈入一维多项式,导致曲线与所基于的CSS cubic-bezier() 不匹配。现在已修正,因此某些动画的表现可能有所不同。
  • X轴上的始终弹性效果。 PR #5112 关闭了 #1399(第二大古老的开放问题,提交于2015年3月):setAlwaysTensile(true) 现在也适用于水平方向,而不仅仅是垂直方向。这意味着在X轴滚动时也能看到橡皮筋效果。
  • 验证高亮在切换焦点时触发。 PR #5123 关闭了 #1459:当一个字段的值无效时,点击其他字段后该字段会高亮,而不再仅限于按下虚拟键盘的“下一个”/“回车”键。
  • EncodedImage.dispose() 现在真正释放内存。 PR #5127 使 dispose() 释放解码后的图像数据及编码字节(此前为空操作),并增加了 isDisposed()。关闭 #3733
  • NetworkManager.ping()。 PR #5130 添加了 ping(url, timeoutMillis),这是一个真实的服务器可达性探测,与设备端的 isConnected() 配合使用。关闭 #3669
  • ImageViewer 拖动冒泡。 PR #5132:在缩放级别为1的 ImageViewer 上垂直拖动现在会向上冒泡给父容器,而非被吞没。关闭 #3700。这意味着你现在可以在可滚动Y容器中放置多个图像查看器。
  • Graphics.isVisible()。 PR #5129 添加了一个裁剪交集原语,使缩放画布可以剔除屏幕外内容并跳过解码/缩放。关闭 #3846
  • 截图区块现在覆盖peer组件。 PR #5107ios.blockScreenshotsOnEnterBackground=true 此前隐藏了渲染表面,但让peer组件(例如 BrowserComponentWKWebView)在应用切换器快照中仍然可见。已修复。
  • 更好的站点搜索。 PR #5090 将站内搜索索引按最新优先排序,并阻止了庞大的开发者指南页面压制所有其他结果。我们还使搜索结果中的博客文章旁边显示了日期,并新增提示说明我们不搜索开发者指南/Javadoc。

关于贡献的说明

我们不再接受社区拉取请求(pull requests)。我们希望精确说明原因,因为很容易对此过度解读。

这并非关于AI生成的PR。我们不会审查贡献的编写方式。

真正的原因是机械性的:我们的CI无法在来自fork的PR上正确运行。截图管道、设备运行器和协议测试都需要凭据和特定设置,fork的PR无法获得这些,因此社区PR无法通过与我们自身代码相同的验证关卡。这个问题不易解决,否则会给我们的流程带来重大安全漏洞。最近,一个看似完全安全的改动悄悄通过了审查,却触发了CI回归,导致构建中断。责任在我们,而非贡献者,但这让我们确信,合并无法完全验证的代码并非明智之举。

因此,我们以另一种方式敞开大门。请继续提交问题(issues)。 附带测试用例的清晰问题对我们来说不难处理,正如上面数字所显示,我们正在积极处理跟踪列表。如果你有修复方案,请在问题中描述、附上失败用例,我们将自行通过CI完成。

对于多年来向我们发送过补丁的人们,尤其是近期贡献者:感谢你们。你们的努力是真实的,我们非常感激;这一决定关乎我们的管道,而非你们的工作。

即将推出的亮点

后续将发布四篇深度教程,每天一篇:

  • 周六。 原生Mac构建与更深入的桌面集成。PR #5053#5136#5170
  • 周日。 核心中的WebSocket、gRPC和GraphQL。PR #5133#5099#5141
  • 周一。 全新广告API。PR #5169
  • 周二。 后台工作、推送主题与更丰富的通知。PR #5142。## 总结 问题追踪器位于此处,是目前与我们联系的最佳途径。讨论论坛在这里,Build Cloud 控制台位于 /console/PlaygroundInitializrSkin Designer 的地址保持不变。

本文最初发布于 foojay,标题为 Mac Native Builds, Live Protocols, And Open Issues Under 350