惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

IT之家
IT之家
The GitHub Blog
The GitHub Blog
美团技术团队
Security Latest
Security Latest
The Cloudflare Blog
D
DataBreaches.Net
Microsoft Azure Blog
Microsoft Azure Blog
V
Visual Studio Blog
宝玉的分享
宝玉的分享
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
T
The Exploit Database - CXSecurity.com
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
W
WeLiveSecurity
P
Proofpoint News Feed
V
Vulnerabilities – Threatpost
Schneier on Security
Schneier on Security
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
S
Security Affairs
腾讯CDC
H
Hacker News: Front Page
Microsoft Security Blog
Microsoft Security Blog
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
博客园 - 三生石上(FineUI控件)
C
Check Point Blog
S
Security @ Cisco Blogs
Google DeepMind News
Google DeepMind News
Cisco Talos Blog
Cisco Talos Blog
云风的 BLOG
云风的 BLOG
M
MIT News - Artificial intelligence
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Security Archives - TechRepublic
Security Archives - TechRepublic
I
InfoQ
量子位
Apple Machine Learning Research
Apple Machine Learning Research
AWS News Blog
AWS News Blog
TaoSecurity Blog
TaoSecurity Blog
月光博客
月光博客
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
aimingoo的专栏
aimingoo的专栏
S
SegmentFault 最新的问题
A
Arctic Wolf
Hacker News: Ask HN
Hacker News: Ask HN
D
Docker
Hugging Face - Blog
Hugging Face - Blog
I
Intezer
雷峰网
雷峰网
Engineering at Meta
Engineering at Meta
WordPress大学
WordPress大学
SecWiki News
SecWiki News
N
News and Events Feed by Topic

DEV Community

Authentication Security Deep Dive: From Brute Force to Salted Hashing (With Java Examples) Why AI Systems Don’t Fail — They Drift Spilling beans for how i learn for exam😁"Reinforcement Learning Cheat Sheet" I Replaced Chrome with Safari for AI Browser Automation. Here's What Broke (and What Finally Worked) How Python Borrows Other People's Work The $40 Architecture: Processing 1 Billion API Requests with 99.99% Uptime Vibe Coding: A Workflow Guide (From Zero to SaaS) Most webhook security guides protect the wrong side. The scary part is delivery. Headless CMS for TanStack Start: Build a Blog with Cosmic EU Age Verification App "Hacked in 2 Minutes" — What Actually Happened Comfy Cloud’s delete function does not actually remove files Running AI Models on GPU Cloud Servers: A Beginner Guide Event-driven media intelligence with AWS Step Functions and Bedrock I scored 500 AI prompts across 8 quality dimensions — here's what broke How to Call Google Gemini API from Next.js (Free Tier, No Backend Needed) The Portal Protocol: Reclaiming Human Connection in the Age of AI How to Fix Your Team's Scattered Knowledge Problem With a Self-Hosted Forum Intro to tc Cloud Functors: A Graph-First Mental Model for the Modern Cloud Designing Multi-Tenant Backends With Both Ownership and Team Access I Built a Neumorphic CSS Library with 77+ Components — Here's What I Learned PostgreSQL Performance Optimization: Why Connection Pooling Is Critical at Scale Cómo construí un SaaS multi-rubro para gestionar expensas en Argentina con FastAPI + Vue 3 🚀 I Built an Ethical Hacking Scanner Tool – Open Source Project I Replaced /usage and /context in Claude Code With a Single Statusline A Pythonic Way to Handle Emails (IMAP/SMTP) with Auto-Discovery and AI-Ready Design I Collected 8.9 Million Polymarket Price Points — Here's What I Found About How Markets Really Move EcoTrack AI — Carbon Footprint Tracker & Dashboard Everyone's Using AI. No One Agrees How. 5 self-hosted ebook managers worth trying in 2026 Building Your First AI Agent with LangChain: From Chatbot to Autonomous Assistant Common SOC 2 Failures (Real World) Stop Vibe-Checking Your AI App: A Practical Guide to Evals How to Use SonarQube and SonarScanner Locally to Level Up Your Code Quality Your Next To-Do App Is Dead — I Replaced Mine with an OpenClaw AI Sign a Nostr event in 60 lines of Python using coincurve — no nostr-sdk, no nbxplorer, no rust toolchain ITGC Audit Explained Like You’re in Big 4 Patch Tuesday abril 2026: Microsoft parcha 163 vulnerabilidades y un zero-day en SharePoint Stop scraping everything: a better way to track competitor price changes Listing on MCPize + the Official MCP Registry while routing payments OUTSIDE the marketplace — how I kept 100% of my x402 revenue Building an AI-Powered Risk Intelligence System Using Serverless Architecture Why We Ripped Function Overloading Out of Our AI Toolchain Testing AI-Generated Code: How to Actually Know If It Works SaaS Churn Is Killing Your Business. Here Is What to Do About It (Without a Support Team) The Speed of AI Is No Longer Linear - And Self-Improving Models Are Why How to Implement RBAC for MCP Tools: A Practical Guide for Engineering Teams From Standard Quote to Persuasive Proposal: AI Automation for Arborists I built a CLI that scaffolds complete multi-tenant SaaS apps Axios CVE-2025–62718: The Silent SSRF Bug That Could Be Hiding in Your Node.js App Right Now The dashboard that ended our friendship Data Pipelines Explained Simply (and How to Build Them with Python) The Hidden Cost of AI Systems Nobody Talks About. undefined vs undeclared, and how typeof behaves Switching from file-based jobs to NATS/Kafka in Rust without changing code io_uring Adventures: Rust Servers That Love Syscalls Why Agentic AI is Killing the Traditional Database The POUR principles of web accessibility for developers and designers Quantum Neural Network 3D — A Deep Dive into Interactive WebGL Visualization How To Install Caveman In Codex On macOS And Windows Automation Pipeline Reliability: Why Your Workflow Breaks When Nobody Is Watching I Built an 'Open World' AI Coding Agent — It Works From ANY Folder From Freelancing to Product: A Tech Service Company's SaaS Transformation China's AI Giants: Adding Tencent Hunyuan & ByteDance Doubao to AI University (74 Providers) On the Vibe Coders and Their Lies clerk: Auto-Summarize Your Claude Code Sessions AI Weekly — 2026/04/10–04/17 | The Model Lockdown Is Here, but the Toolchain Is the Real Battleground AI 週報 — 2026/04/10–2026/04/17 模型封鎖潮來了,但工具鏈才是真戰場 Maybe this is how Open-Source apps are born... 🚀 Fine-Tune LLMs with LoRA and QLoRA: 2026 Guide tRPC v11 + Next.js App Router: End-to-End Type Safety Without the Boilerplate ShadCN UI in 2026: Why I Stopped Installing Component Libraries and Started Owning My Components SaaS Billing in React Server Components: Stripe + Supabase Without a Single `useEffect` Join our DEV Weekend Challenge — $1,000 in Prizes Across TEN winners! Submissions Due April 20 at 6:59 AM UTC. Implementing FSRS Spaced Repetition in Flutter + Supabase — Adding Memory Science to an AI Learning App "I Texted My Localhost From the Train — Claude Code Fixed the Bug Before I Got Home" I Built a Sales Prep AI and It Went Deeper Than Expected Design to Code #2: One JSON, Eleven Outputs Solving the 100M-Row Problem: A Summary Table Pattern for High-Volume Push Notification Logs Flutter Web With Wasm: What Actually Changes For Developers I Built 50 Royalty-Free Soundtracks for My Side Project in a Weekend Using AI Music Generation The Vibe Coding Security Checklist: 7 Things to Check Before You Ship Stop Letting Googlebot Guess Fix Your React App's SEO Right Desconstruindo o Streaming do LinkedIn: Como Criar um Engine de Extração de Vídeo de Alta Performance com HLS e FFmpeg (EDA Part-1) EDA (Exploratory Data Analysis) Explained With Real Life — Why Looking at Your Data Is the Most Important Step in Machine Learning Brand Relationship Management at Scale: Our 4-Touch Outreach System for 200+ Brands Why String.fromEnvironment() Might Return an Empty String in Dart JGuardrails 1.0.0 — Hardening Java LLM Apps Against Jailbreaks, Toxicity, and Prompt Injection Plan and Schedule a Full Week of Threads Content From One Claude Conversation Coding Cat Oran Ep3, Five Tables Changed Everything Updated: BFF Pattern I'm done watching freelancers get buried by 200 proposals. So I'm building the alternative. This is my first post BFS Algorithm in Java Step by Step Tutorial with Examples Tracking LLM Pricing Monthly: An Open Dataset for 22 AI Models How We Measure Content ROI on a Comparison Site: Revenue Attribution Without Perfect Data Introducing Nova AI Ops: The AI-Native Operating System for SRE Teams I built a free desktop video downloader for Windows — Grabbit How Talkie OCR Helps Vision-Impaired & Dyslexic Users Read the World Around Them VRCFaceTracking安装和iPhone面捕配置教程,有bug Even CrowdStrike Can't See Your Agents The Automation Gold Rush: What n8n Workflows and Claude Are Opening Up for Developers Right Now
NFC, Crypto, Biometrics, And A New Build Cloud
Shai Almog · 2026-05-29 · via DEV Community

NFC, Crypto, Biometrics, And A New Build Cloud

Last week was about defaults. This week is about device APIs moving into the framework core, a small simulator change that revolutionizes Bluetooth development, and a preview of the new Build Cloud UI we would love your feedback on. There is a handful of other things in here too — and the Metal default flip I trailed last week is in a different state than I expected, which is worth a word at the end.

What is Codename One? Codename One is an open-source framework for building native iOS, Android, desktop, and web apps from a single Java or Kotlin codebase. Learn more at codenameone.com.

A new Build Cloud UI — preview

The single most visible change this week sits behind the Build Cloud login. The console we have been serving for years is being replaced. The new UI is live now here, alongside the current console you can still find here. We want eyes and feedback on it before we flip the default.

New Build Cloud console — Builds page, dark theme

The whole console is written in Java 17 against the Codename One UI framework, then compiled to JavaScript via our JavaScript port and served as static assets from inside the Build Cloud. Same Form, Container, BoxLayout, Toolbar, theme.css you would write for a phone build.

This is the same playbook the Initializr, the Playground, and the Skin Designer already follow. Four non-trivial Codename One apps shipping to the browser as production tooling. If you wondered whether the JavaScript port could carry a complex application UI, this is the most direct answer we can give.

Device APIs become first-class

The bigger structural change this week is that three new APIs that used to live in cn1libs or weren't available at all are now built into the framework core: biometrics, cryptography, and NFC. The unifying idea is that you should not have to add a cn1lib to do work this fundamental. The cn1lib model is still useful for genuinely third-party functionality and for features that make less sense in the core. The existing cn1libs that we are subsuming continue to work unchanged on projects that already depend on them — but the bar for what lives in core just moved.

Biometrics — PR #4987

Touch ID, Face ID, and Android BiometricPrompt are now in com.codename1.security.Biometrics. The API uses simpler semantics compared to the original fingerprint API (that predated face scanning but didn't rename the API). You can use canAuthenticate() to gate access, then an authenticate(...) call that returns an AsyncResource, typed BiometricError codes on the failure path.

Biometrics b = Biometrics.getInstance();
if (!b.canAuthenticate()) {
    // No hardware, or no enrolled biometrics
    return;
}
b.authenticate("Unlock your account").onResult((success, err) -> {
    if (err != null) {
        BiometricError code = ((BiometricException) err).getError();
        switch (code) {
            case USER_CANCELED:  return;
            case LOCKED_OUT:     fallToPassword(); return;
            case NOT_ENROLLED:   askToEnroll(); return;
            default:             fallToPassword();
        }
    } else {
        unlock();
    }
});

On iOS this wraps LocalAuthentication.framework; on Android API 29+ it uses BiometricPrompt and on API 23-28 it keeps the legacy FingerprintManager path through a reflection adapter. The build servers and local build handle permissions and framework linking seamlessly so you don't need to do anything and don't need to add a build hint. It just works.

The Java SE simulator has a new Simulate -> Biometric Simulation submenu with an Available toggle, per-modality enrollment, and a configurable outcome for the next authenticate(...) call. So you can exercise every code branch — success, user cancel, locked-out, no-hardware — without leaving the simulator.

If you have been depending on the venerable FingerprintScanner cn1lib, it continues to work unchanged. New code should reach for com.codename1.security.Biometrics.

Cryptography — PR #4994

Routine cryptography (hashing, MAC, symmetric and asymmetric encryption, signing, JWT, OTP) is now in com.codename1.security and ships with the framework. The pure-Java algorithms (Hash, Hmac, Base32, the JWT and OTP machinery) produce identical output on every supported platform. The bits that need real keys — AES, RSA, ECDSA, SecureRandom — route through each port's native crypto provider so you get hardware-backed primitives where the device offers them.

A typical AES-GCM round-trip:

SecretKey key   = KeyGenerator.aes(256);
byte[]    nonce = SecureRandom.bytes(12);
byte[]    enc   = Cipher.aesEncrypt(Cipher.AES_GCM, key, nonce, null,
                                    "secret".getBytes("UTF-8"));
byte[]    dec   = Cipher.aesDecrypt(Cipher.AES_GCM, key, nonce, null, enc);

A SHA-256 hash:

byte[] digest = Hash.sha256("hello".getBytes("UTF-8"));
String hex    = Hash.toHex(digest);

A signed JWT:

byte[] hsKey  = KeyGenerator.hmac(256);
String token  = Jwt.signHs256(hsKey)
                   .claim("sub", "user-42")
                   .claim("exp", System.currentTimeMillis() / 1000 + 3600)
                   .compact();

Jwt parsed    = Jwt.verifyHs256(token, hsKey);   // throws on bad signature
String sub    = parsed.getClaim("sub").asString();

And a TOTP that lines up with Google Authenticator / Authy:

byte[] sharedSecret = Base32.decode("JBSWY3DPEHPK3PXP");
String code         = Otp.totp(sharedSecret);    // current 30s window
boolean ok          = Otp.verifyTotp(code, sharedSecret, /* drift */ 1);

The PR also ships a matching UI widget — com.codename1.components.OtpField — a segmented, auto-advancing OTP input with paste distribution and a completion listener, so the "enter your 6-digit code" screen is now half a dozen lines of glue:

OtpField otp = new OtpField(6);
otp.setCompleteListener(code -> {
    if (Otp.verifyTotp(code, sharedSecret, 1)) {
        proceed();
    } else {
        otp.setError("Wrong code");
    }
});
form.add(otp);

We deliberately chose conservative defaults: AES/GCM/NoPadding for new authenticated AES, RSA/ECB/OAEPWithSHA-256AndMGF1Padding for new RSA, constant-time HMAC compare, a bias-free intBelow(n) on SecureRandom. The MD5 / SHA-1 / PKCS#1 / ECB transformations are still there because real apps still need to interoperate with legacy systems, but the documentation calls them out as interop-only.

NFC — PR #4996

com.codename1.nfc is the third addition. A single Nfc entry point, an NdefMessage / NdefRecord pair with typed factories (createUri, createText, createMime, createExternal, createApplicationRecord), per-technology Tag subclasses (IsoDep, MifareClassic, MifareUltralight, NfcA, NfcB, NfcF, NfcV), and a HostCardEmulationService base class for emulating a contactless card.

Reading an NDEF URI tag — the "tap a poster" pattern:

Nfc nfc = Nfc.getInstance();
if (!nfc.canRead()) return;             // no NFC hardware / NFC disabled

nfc.readTag(new NfcReadOptions()
        .setNdefOnly(true)
        .setAlertMessage("Hold near the poster"))
   .onResult((tag, err) -> {
        if (err != null) return;
        tag.readNdef().onResult((msg, e) -> {
            if (e == null) {
                String url = msg.getFirstRecord().getUriPayload();
                Display.getInstance().execute(url);
            }
        });
   });

Exchanging APDUs with an EMV / transit card:

nfc.readTag(new NfcReadOptions()
        .setTechFilter(TagType.ISO_DEP)
        .setIsoSelectAids(myAid))
   .onResult((tag, err) -> {
        if (err != null) return;
        IsoDep iso = tag.getIsoDep();
        if (iso == null) return;
        iso.transceive(myCommandApdu).onResult((resp, e) -> {
            if (ApduResponse.isSuccess(resp)) {
                /* parse response */
            }
        });
   });

Acting as a contactless card via Host Card Emulation:

class LoyaltyCard extends HostCardEmulationService {
    public String[] getAids() { return new String[] { "F0010203040506" }; }
    public byte[] processCommand(byte[] apdu) {
        return ApduResponse.withStatus(loyaltyId.getBytes("UTF-8"),
                                       ApduResponse.swSuccess());
    }
}
Nfc.getInstance().registerHostCardEmulationService(new LoyaltyCard());

Android uses NfcAdapter foreground dispatch / reader-mode and HostApduService; both manifest entries are auto-injected by the Maven plugin and the build daemon when this class is referenced. iOS uses Core NFC (NFCNDEFReaderSession, NFCTagReaderSession) for reading and CardSession (iOS 17.4+, EU only) for HCE; the NFCReaderUsageDescription plist entry and entitlements are auto-injected by the build server and local builds (again seamless is the key). The Java SE simulator has a Simulate -> NFC menu (I feel like I'm repeating myself), that lets you tap a virtual tag, edit its NDEF payload, and fire APDUs at any registered HostCardEmulationService, so you can sit at your desk and drive every code path without a card or a reader.

On platforms that do not have NFC (desktop deploy, the JavaScript port) the base class is returned and reports the device as unsupported, so application code does not need platform if statements — always gate on canRead() and you are fine.

cn1libs can now own simulator menus — and that changes Bluetooth

PR #4988 is one of those small-looking changes that opens up a whole category of UX. The Java SE simulator now scans every jar on its classpath for META-INF/codenameone/simulator-hooks.properties and lets any cn1lib contribute its own menu items. The cn1lib does not reference any Swing types — the data file just names a name=... for the menu group and a series of itemN entries pointing at public static no-arg methods, each with an optional labelN. The simulator does the rest.

A skeletal hook file:

name=Bluetooth
namespace=bluetooth

item1=com.example.bt.sim.Hooks#toggleAdapter
label1=Toggle adapter on/off

item2=com.example.bt.sim.Hooks#addDemoPeripheral
label2=Add demo peripheral

Drop that file inside a cn1lib's javase/ module and the next time the simulator starts you get a Bluetooth menu with two items in it, each running on the CN1 EDT, with Toggle adapter on/off and Add demo peripheral doing exactly what their names say. Each entry is also callable cross-platform via CN.execute("bluetooth:item1"), which is what makes the same hook usable from a screenshot test or a scripted demo. Items without a labelN are API-only — registered with the executor but hidden from the menu — which is what test suites use to prime scripted state.

We picked the data-driven shape on purpose. We are going to rewrite the simulator UX over the coming year, and we did not want cn1libs to either depend on JMenu / JMenuItem directly or have to be recompiled when the simulator's UI shell changes. The neutral SimulatorHook record (menuName, label, Runnable) is the contract; the UI on top of it is replaceable.

Bluetooth that you can actually debug

The reason the simulator hook landed this week is that we have been working on the bluetoothle-codenameone cn1lib in parallel, and the cn1lib needs the hook to be genuinely good. The result is a Bluetooth debugging story that is materially nicer than what you get out of the box on either native platform.

The library now has two backends: a real BLE backend that talks to actual hardware (CoreBluetooth on iOS, BluetoothLeScanner / BluetoothGatt on Android, the new native desktop bridge on Java SE) and a fully in-memory simulator.

To be clear, the simulator now connects to the hardware bluetooth on your device and starts scanning for real devices. I debugged bluetooth devices from my Mac using IntelliJ/IDEA and was able to see real devices!!!

The cn1lib's simulator-hooks.properties ships with seven hooks that put the simulator in the simulator's menu bar:

Bluetooth
├── Toggle adapter on/off
├── Add demo peripheral
├── Disconnect all peripherals
├── Push demo notification
├── Clear peripherals
├── Switch backend → native BLE (real hardware)
└── Switch backend → simulator

So a typical Bluetooth iteration loop looks like this:

  1. Open your app in the Java SE simulator. The simulator backend is on by default.
  2. Open Bluetooth -> Add demo peripheral. Your scan picks up a fake peripheral. Step through your discovery code.
  3. Open Bluetooth → Push demo notification. Your characteristic listener fires. Step through your handler.
  4. Open Bluetooth → Toggle adapter on/off. Your "adapter off" branch runs. Step through it.
  5. When you are happy with the in-simulator behaviour, open Bluetooth → Switch backend → native BLE (real hardware) and your laptop's actual Bluetooth radio takes over. Same app, same code, real peripherals.

Compare that to the conventional Bluetooth iteration loop on iOS or Android. You need a real device. You need a real peripheral. The simulator does not have a BLE stack at all on iOS, and Android's emulator has a partial one that does not match real hardware. You end up doing every change on device, with cables, and the moment something goes wrong you have to figure out whether the bug is in your code, the peripheral firmware, the OS BLE stack, or some interaction between all three.

With the cn1-bluetooth simulator backend, the first four of those variables collapse to one: your code. When it works in the simulator and it does not work on device, you have narrowed the problem down to the platform BLE stack or the peripheral, which is a tractable problem. When it does not work in the simulator either, you are debugging your own code, on your own laptop.

If you have a cn1lib of your own that would benefit from a "Simulate → Whatever" menu — fake GPS coords, scripted push notifications, deterministic camera frames — the hook file is the simplest way to ship it. Two lines of properties, one public static no-arg method, and the simulator has the affordance built in.

In-app purchase consistency — PR #4990

A forum report of submitReceipt being invoked repeatedly turned into three closely related fixes in Purchase.synchronizeReceipts. All three had the same root cause: code that worked when the App Store / Play Store filled in every field, and quietly misbehaved when one of them was null.

  1. removePendingPurchase matched only on transactionId. When a receipt's transactionId was null (a real case on some restored Android purchases) the call silently no-op'd, the receipt stayed in the pending queue, the recursion at the end of synchronizeReceipts pulled the same receipt again, and the same receipt got re-submitted forever. The fix matches on the receipt itself with a fallback tuple of (sku, storeCode, purchaseDate, orderData) when transactionId is null on either side.
  2. The recursive synchronizeReceipts(0, callback) re-registered the caller's SuccessCallback on every iteration, so a queue of N pending receipts caused the user's callback to fire N times. The recursive call now passes null since the original callback is already in synchronizeReceiptsCallbacks.
  3. The callback flush itself fired even when the queue had not actually drained, which masked the duplicate-submit problem at the surface and made it look like the callback was the bug.

None of this is dramatic in isolation, but the symptom — a subscription that gets re-validated against the server every few seconds — looks identical to a server bug, and it has cost real developers real hours. The fix is shipped and the regression tests cover the null-transactionId path so this exact shape does not come back.

UTF-8: JDK-compatible replace semantics + a NEON ASCII fast path — PR #4989

String.getBytes("UTF-8") and new String(bytes, "UTF-8") on iOS were behind the standard JDK in two ways. The decoder threw RuntimeException("Decoding Error") on malformed input — the rest of the Java world emits U+FFFD per maximal subpart and keeps going. The encoder dropped through to a 1-byte-per-char stub on non-Apple builds, and there was a silent ISO-8859-2 → NSISOLatin1 alias that hid encoding errors when NSString rejected the input.

The new decoder is a Hoehrmann DFA with JDK-compatible REPLACE semantics: one U+FFFD per maximal subpart violation, truncated trailing sequences also emit a U+FFFD. The encoder is a portable UTF-16 → UTF-8 with surrogate-pair joining; the Apple path now uses it directly so NSString is no longer involved in the common case. And the encoder gains a real implementation for the POSIX / test fallback in place of the old TODO stub.

The fun part is the SIMD work. The ASCII prefix scan (vmaxvq_u8) and the u8 → u16 widen (vmovl_u8) are gated on __ARM_NEON and only kick in for inputs ≥ 64 bytes. A standalone microbenchmark shows roughly 53× speedup over the scalar DFA on ASCII-heavy payloads. The integration-level benchmark cannot see this number because allocating a fresh char[] per call dominates on ParparVM, but the helpers carry their weight on the parser-style hot paths the SIMD work was added for (JSON parsing, log scanning, the kind of text that is mostly ASCII with the occasional non-ASCII codepoint).

If your app parses a lot of UTF-8 — and most apps do, because most network APIs are JSON over HTTP — this lands as a quiet but measurable speedup, and as one fewer place where iOS behaves subtly differently from the simulator.

Two long-standing JVM fixes

PR #4980 — Iterative GC mark to fix iOS stack overflow on deep graphs

Issue #3136 has been around for a long time. The ParparVM garbage collector's mark phase was recursive: for every reachable reference it followed, it pushed a stack frame, so a long linked-list chain or any deep object graph could blow the GC's own stack and crash the app. The reproducer was simple — build a LinkedList with 50000 nodes, force a GC — but the symptom on real apps was opaque: an unexplained iOS-only crash on the largest customer datasets, often weeks after the data structure was introduced.

The fix replaces the recursive mark with an iterative one over an explicit work stack. The stack lives on the heap and grows as needed, so the only ceiling now is real memory. Long linked-lists, deep trees, deeply nested JSON parsed into POJOs — all of these used to be a latent crash on iOS and now they are not.

PR #4985 — Don't rely on C arg eval order in PUTFIELD / MULTIANEWARRAY

Issue #3108 is the other one. Several PUTFIELD and MULTIANEWARRAY translation paths emitted C code that depended on argument evaluation order. C does not specify an evaluation order for function arguments. Different compilers, different optimisation levels, sometimes the same compiler at different -O levels produced different orderings, and the visible result was occasional, "miscompiled", "field was assigned the wrong value", "array dimension came out negative" bugs that nobody could reproduce reliably.

The fix is unglamorous: hoist the operand evaluations into named local variables before the storing call, so the evaluation order is fixed by the C abstract machine instead of being left to the compiler. The kind of thing where the code change is small, the testing is hard, and the symptom is "the platform feels more solid" rather than any specific feature.

I am calling these out separately from the rest because both are issues you have probably bumped into without realising it, and both are the kind of plumbing that does not show up in a feature list but quietly raises the floor under every app on iOS.

Hardware keyboard and mouse on iOS and Android — PR #4982

Issue #3498 has been on the wishlist since iPadOS started shipping with proper trackpad support and since Android pivoted to position itself as the OS Google wants on Chromebooks. The framework already exposed pointerHover* and the full keyboard event surface, but the ports did not deliver hover events at all and dropped a depressing number of hardware-keyboard keystrokes — F-keys, Esc, Tab, Home / End, PgUp / PgDn, Insert all arrived as keyPressed(0) on Android, and Enter was silently dropped unless you set sendEnterKey=true.

This PR forwards ACTION_HOVER_ENTER/MOVE/EXIT on Android into the framework's hover surface, replaces the built-in keyboard map lookup with the attached device's actual key map, includes CTRL / FN / CAPS in the meta state, and lights up the equivalent paths on iOS. Result: BT mouse, BT keyboard, stylus hover, Chromebook trackpad, iPad Magic Keyboard — all of these now do what an end user expects. Buttons highlight on hover. Tab moves focus. F-keys produce F-key codes. Cmd-C copies. Esc dismisses dialogs.

This is structural for two reasons. Android wants to replace ChromeOS for the laptop form factor, which means our Android apps are going to land on laptop-shaped devices with attached keyboards and trackpads more often than they ever have, and they need to behave like real desktop apps when they do. And iPad apps with a Magic Keyboard are increasingly indistinguishable from desktop apps in user expectation. Codename One's whole pitch is "write once, run on every screen" — the screen got a keyboard, and now we handle it.

Expanded CSS gradients and blurs — PR #4957

The CSS compiler used to reject anything past two-stop linear gradients at the four cardinal angles and two-stop radial gradients at the center, falling back to a CEF-rasterised bitmap for everything else. filter and backdrop-filter were ignored entirely. The bitmap fallback worked but it cost you the GPU path and it could not scale with the component.

This PR moves the full CSS gradient range and filter: blur(...) into native primitives end-to-end. You get multi-stop linear and radial gradients, conic gradients, repeating linear and repeating radial, the full shape and extent grammar, and Gaussian blur on both filter and backdrop-filter. Drawn on the GPU. Composable with everything else.

.HeroCard {
    background: conic-gradient(from 30deg, #ff7a00, #ff2d95, #6750a4, #ff7a00);
    border-radius: 24px;
    filter: blur(0.5px);
}

.GlassDialog {
    background: rgba(255, 255, 255, 0.18);
    backdrop-filter: blur(18px);
    border-radius: 28px;
}

The above is the kind of thing you would write today on a modern web stack. Codename One now compiles it down to the Metal / GL / Android Canvas / Swing path on the platform you are targeting, without an offscreen bitmap in the middle. Combined with the iOS Modern and Material 3 native themes we shipped three weeks ago and the accent palette overrides we shipped last week, you can put together a genuinely modern UI in pure CSS now.

On Metal: the community got there first

I said previously that I wanted to flip ios.metal=true to the default this week. That flip did not happen — and I want to be clear about why, because the reason is the best version of what we are trying to be.

The community got there first. The combination of bug reports, screenshots from real apps, and pull requests against issues people found themselves did the work of a paid QA pass. The remaining regression list is much shorter than I expected it to be a week ago. Most of the items left are subtle (specific blend modes against specific backdrops, a clip-under-rotation edge case the diagnostic test from PR #4924 has already localised, one corner case in font fallback when the device locale changes mid-session). None are showstoppers.

So instead of forcing the flip on a deadline, we are now going to flip it when the regression list reads zero. That will not be very long — within one to three weeks at the pace we are closing things — and the apps that flip first will land on a Metal default that has been tested against more real screens than any rendering migration we have done before.

If you are one of the developers who flipped the hint, took screenshots, and filed issues over the past two weeks: thank you. Keep doing it. The Metal pipeline is going to ship as the default in materially better shape than it would have without you. If you have not flipped it yet, the build hint is still ios.metal=true. We would still love your screens through it.

Wrapping up

This was a week about lifting the floor. NFC, biometrics, and cryptography are no longer optional add-ons. The simulator-hook framework opens up a class of cn1lib UX — Bluetooth being the first and largest beneficiary — that is genuinely hard to assemble on either native platform out of the box. Two of the JVM's longest-standing iOS-only bugs are finally retired. UTF-8 behaves like the standard JDK and is faster where it matters. Hardware keyboards and trackpads behave like real desktop apps would. CSS covers what a modern web stack covers.

And the Build Cloud preview is sitting on the server right now, waiting for you to break it. Please do.

A specific thank-you to the long list of community testers on the Metal pipeline (you know who you are; we are tracking the issues to a thank-you note in the next post), to Dave who submitted #3136 with the 50,000-node LinkedList repro that finally made the GC mark a one-day fix instead of a one-month investigation.

Issue tracker is here, the Playground, Initializr, and Skin Designer are all still the easiest places to see what the JavaScript port is capable of carrying. The Build Cloud preview is at /console/ on cloud.codenameone.com once you are signed in.