<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Shai Almog</title>
    <description>The latest articles on DEV Community by Shai Almog (@codenameone).</description>
    <link>https://dev.to/codenameone</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F417973%2Fa7b22dd9-5565-48f5-bfab-7e5035b3888f.png</url>
      <title>DEV Community: Shai Almog</title>
      <link>https://dev.to/codenameone</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/codenameone"/>
    <language>en</language>
    <item>
      <title>Metal Default, A New Build Cloud, And A New Format</title>
      <dc:creator>Shai Almog</dc:creator>
      <pubDate>Fri, 05 Jun 2026 13:58:05 +0000</pubDate>
      <link>https://dev.to/codenameone/metal-default-a-new-build-cloud-and-a-new-format-11hg</link>
      <guid>https://dev.to/codenameone/metal-default-a-new-build-cloud-and-a-new-format-11hg</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frctg7vunb375n1qvxfii.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frctg7vunb375n1qvxfii.jpg" alt="Metal Default, A New Build Cloud, And A New Format" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This week's release post looks different on purpose. The Friday omnibus has been getting longer and longer, and that has been working against us in two ways. SEO ignores 5,000 word pages that cover twelve unrelated topics, so the actual material gets buried instead of indexed against the queries that should find it. And when a single release post covers ten things, it becomes hard to point a colleague at "that one Codename One change from a few weeks ago" without scrolling for ten minutes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What is Codename One?&lt;/strong&gt; 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 &lt;a href="https://www.codenameone.com/" rel="noopener noreferrer"&gt;codenameone.com&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;So from this week onwards the Friday post is the short one. A quick set of headline items, a "what is coming next" list, and that is it. The specific features get their own posts over the following days, with their own slugs, their own searchable titles, and their own discussion threads. The weekly post lives at the top of the homepage as the index; the deeper posts back-link to it; and you can read whichever ones are actually relevant to your project.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Important:&lt;/strong&gt; it seems that if developer mode is on in your device you might get an information dialog on the right side of your UI. &lt;a href="https://github.com/codenameone/CodenameOne/issues/5108" rel="noopener noreferrer"&gt;This issue&lt;/a&gt; explains how you can turn it off.&lt;/p&gt;

&lt;p&gt;If you only have thirty seconds, here is what changed this week.&lt;/p&gt;

&lt;h2&gt;
  
  
  Metal is the default on iOS
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/codenameone/CodenameOne/pull/5065" rel="noopener noreferrer"&gt;PR #5065&lt;/a&gt; flips the &lt;code&gt;ios.metal=true&lt;/code&gt; build hint to the default. New iOS builds now link against &lt;code&gt;CAMetalLayer&lt;/code&gt; instead of the deprecated &lt;code&gt;CAEAGLLayer&lt;/code&gt;. We mentioned this &lt;a href="https://www.codenameone.com/blog/metal-and-skins/" rel="noopener noreferrer"&gt;three weeks ago in Metal and Skins&lt;/a&gt;, decided to push it back by one week &lt;a href="https://www.codenameone.com/blog/nfc-crypto-biometrics-and-build-cloud/" rel="noopener noreferrer"&gt;last week&lt;/a&gt; because a couple of regressions still needed work, and shipped it this week with that list at zero.&lt;/p&gt;

&lt;p&gt;If you have not rebuilt since this commit, your next cloud build picks Metal up automatically. No hint to add, no setting to change. The build server flipped at the same time so local builds and cloud builds match.&lt;/p&gt;

&lt;p&gt;If you need to opt out for any reason, the hint still works in reverse:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ios.metal=false
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A few things worth a glance on your first Metal build: gradient fidelity (multi-stop, conic, and repeating gradients now hit the GPU directly through &lt;a href="https://github.com/codenameone/CodenameOne/pull/4957" rel="noopener noreferrer"&gt;PR #4957&lt;/a&gt;), the color space (sRGB by default, flip to &lt;code&gt;displayP3&lt;/code&gt; via &lt;code&gt;ios.metal.colorSpace&lt;/code&gt; if your assets are wide gamut), and anything that draws &lt;code&gt;filter: blur(...)&lt;/code&gt; or &lt;code&gt;backdrop-filter&lt;/code&gt;. Everything else should look unchanged. That is the point.&lt;/p&gt;

&lt;p&gt;A specific thank you to the community testers who flipped the hint over the past three weeks, took screenshots, and filed issues against real apps. The Metal default landed in materially better shape than it would have without you.&lt;/p&gt;

&lt;h2&gt;
  
  
  The new Build Cloud console is now the default link
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://www.codenameone.com/blog/nfc-crypto-biometrics-and-build-cloud/#a-new-build-cloud-ui--preview" rel="noopener noreferrer"&gt;preview of the new Build Cloud UI&lt;/a&gt; went up last week. The bugs you found are fixed, and as of this PR every Dashboard link on the website now points at the new console:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://cloud.codenameone.com/console/index.html
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The navigation Dashboard link in the header, the Sign Up CTA on the pricing page, and the entries on the site map all moved. Old bookmarks still work; the &lt;a href="https://cloud.codenameone.com/secure/index.html" rel="noopener noreferrer"&gt;legacy console&lt;/a&gt; stays online for the time being so you can fall back to it if something is missing or wrong in the new UI. Please tell us when you hit one of those things, because the goal is to retire the legacy URL eventually.&lt;/p&gt;

&lt;p&gt;Historical blog posts that mention the &lt;code&gt;/secure/&lt;/code&gt; URL in their text were left alone.&lt;/p&gt;

&lt;h2&gt;
  
  
  Upcoming attractions
&lt;/h2&gt;

&lt;p&gt;Three deeper posts will follow this one over the next week, each one bundling several related PRs under a single theme so the index stays small. Dates are best effort.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Developer workflow (Saturday).&lt;/strong&gt; On-device debugging on iOS and Android, and JUnit 5 tests for Codename One apps. Codename One always had on-device debugging in the technical sense; you just had to drop into Xcode or Android Studio and jump through a depressing number of hoops. The new pipeline wires JDWP through to the real device so &lt;code&gt;jdb&lt;/code&gt;, IntelliJ, VS Code, Eclipse, or NetBeans just attaches. The JUnit half lets you write standard &lt;code&gt;@Test&lt;/code&gt; methods against the simulator with first-class annotations for the visual configuration (&lt;code&gt;@Theme&lt;/code&gt;, &lt;code&gt;@DarkMode&lt;/code&gt;, &lt;code&gt;@LargerText&lt;/code&gt;, &lt;code&gt;@Orientation&lt;/code&gt;, &lt;code&gt;@RTL&lt;/code&gt;). PRs &lt;a href="https://github.com/codenameone/CodenameOne/pull/4999" rel="noopener noreferrer"&gt;#4999&lt;/a&gt;, &lt;a href="https://github.com/codenameone/CodenameOne/pull/5012" rel="noopener noreferrer"&gt;#5012&lt;/a&gt;, &lt;a href="https://github.com/codenameone/CodenameOne/pull/5032" rel="noopener noreferrer"&gt;#5032&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Platform APIs in the core (Monday).&lt;/strong&gt; Four things that move from "you need a cn1lib for this" to "it is in the framework": built-in WiFi / Bonjour / USB / network-type APIs, a modern OIDC + WebAuthn passkey identity stack (&lt;code&gt;ASWebAuthenticationSession&lt;/code&gt; on iOS, Custom Tabs on Android), share-sheet result callbacks, and a &lt;code&gt;com.codename1.ai&lt;/code&gt; package with &lt;code&gt;LlmClient&lt;/code&gt; for OpenAI / Anthropic / Gemini / Ollama plus a streaming &lt;code&gt;ChatView&lt;/code&gt;, &lt;code&gt;SpeechRecognizer&lt;/code&gt; / &lt;code&gt;TextToSpeech&lt;/code&gt;, and the new ML Kit cn1libs. All four share the same scanner-driven auto-injection of Android permissions and iOS entitlements that NFC and biometrics moved to two weeks ago. PRs &lt;a href="https://github.com/codenameone/CodenameOne/pull/5021" rel="noopener noreferrer"&gt;#5021&lt;/a&gt;, &lt;a href="https://github.com/codenameone/CodenameOne/pull/5018" rel="noopener noreferrer"&gt;#5018&lt;/a&gt;, &lt;a href="https://github.com/codenameone/CodenameOne/pull/5039" rel="noopener noreferrer"&gt;#5039&lt;/a&gt;, &lt;a href="https://github.com/codenameone/CodenameOne/pull/5036" rel="noopener noreferrer"&gt;#5036&lt;/a&gt;, &lt;a href="https://github.com/codenameone/CodenameOne/pull/5035" rel="noopener noreferrer"&gt;#5035&lt;/a&gt;, &lt;a href="https://github.com/codenameone/CodenameOne/pull/5057" rel="noopener noreferrer"&gt;#5057&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Build-time codegen (Wednesday).&lt;/strong&gt; The architectural one. A reusable bytecode &lt;code&gt;AnnotationProcessor&lt;/code&gt; SPI in the Maven plugin, the declarative router (&lt;code&gt;@Route("/path")&lt;/code&gt;, deep links, route guards, per-tab navigation shells) that is its first concrete consumer, then a SQLite ORM (&lt;code&gt;@Entity&lt;/code&gt; / &lt;code&gt;@Id&lt;/code&gt; / &lt;code&gt;@Column&lt;/code&gt;), a JSON / XML mapper (&lt;code&gt;@Mapped&lt;/code&gt; / &lt;code&gt;@JsonProperty&lt;/code&gt; / &lt;code&gt;@XmlElement&lt;/code&gt;), a component binder (&lt;code&gt;@Bindable&lt;/code&gt; / &lt;code&gt;@Bind&lt;/code&gt;) with field-level validation, and the build-time SVG / Lottie transcoder that emits Codename One &lt;code&gt;Image&lt;/code&gt; subclasses for every asset in &lt;code&gt;src/main/svg/&lt;/code&gt; or &lt;code&gt;src/main/lottie/&lt;/code&gt;. The grab-bag PR (&lt;a href="https://github.com/codenameone/CodenameOne/pull/5055" rel="noopener noreferrer"&gt;#5055&lt;/a&gt;, driven by porting a substantial mobile client app onto Codename One as the regression fixture) lands here too because the ORM and mapping work share the porting exercise that drove it. PRs &lt;a href="https://github.com/codenameone/CodenameOne/pull/5037" rel="noopener noreferrer"&gt;#5037&lt;/a&gt;, &lt;a href="https://github.com/codenameone/CodenameOne/pull/5047" rel="noopener noreferrer"&gt;#5047&lt;/a&gt;, &lt;a href="https://github.com/codenameone/CodenameOne/pull/5062" rel="noopener noreferrer"&gt;#5062&lt;/a&gt;, &lt;a href="https://github.com/codenameone/CodenameOne/pull/5055" rel="noopener noreferrer"&gt;#5055&lt;/a&gt;, &lt;a href="https://github.com/codenameone/CodenameOne/pull/5042" rel="noopener noreferrer"&gt;#5042&lt;/a&gt;, &lt;a href="https://github.com/codenameone/CodenameOne/pull/5049" rel="noopener noreferrer"&gt;#5049&lt;/a&gt;, &lt;a href="https://github.com/codenameone/CodenameOne/pull/5066" rel="noopener noreferrer"&gt;#5066&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Wrapping up
&lt;/h2&gt;

&lt;p&gt;That is the new format. Short post on Friday; deeper posts during the week; every change in its own place. Please tell us how it lands.&lt;/p&gt;

&lt;p&gt;Issue tracker is &lt;a href="https://github.com/codenameone/CodenameOne/issues" rel="noopener noreferrer"&gt;here&lt;/a&gt;, the discussion forum is &lt;a href="https://www.codenameone.com/discussion-forum.html" rel="noopener noreferrer"&gt;here&lt;/a&gt;, and the new Build Cloud console is at &lt;a href="https://cloud.codenameone.com/console/index.html" rel="noopener noreferrer"&gt;&lt;code&gt;/console/&lt;/code&gt;&lt;/a&gt;. The &lt;a href="https://www.codenameone.com/playground/" rel="noopener noreferrer"&gt;Playground&lt;/a&gt;, &lt;a href="https://www.codenameone.com/initializr/" rel="noopener noreferrer"&gt;Initializr&lt;/a&gt;, and &lt;a href="https://www.codenameone.com/skindesigner/" rel="noopener noreferrer"&gt;Skin Designer&lt;/a&gt; are all still where they were.&lt;/p&gt;

</description>
      <category>java</category>
      <category>mobile</category>
      <category>android</category>
      <category>ios</category>
    </item>
    <item>
      <title>NFC, Crypto, Biometrics, And A New Build Cloud</title>
      <dc:creator>Shai Almog</dc:creator>
      <pubDate>Fri, 29 May 2026 14:01:40 +0000</pubDate>
      <link>https://dev.to/codenameone/nfc-crypto-biometrics-and-a-new-build-cloud-119j</link>
      <guid>https://dev.to/codenameone/nfc-crypto-biometrics-and-a-new-build-cloud-119j</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh37kbs60d3zwq6v9b5j8.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh37kbs60d3zwq6v9b5j8.jpg" alt="NFC, Crypto, Biometrics, And A New Build Cloud" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;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 &lt;a href="https://www.codenameone.com/blog/skills-java17-and-theme-accents/" rel="noopener noreferrer"&gt;last week&lt;/a&gt; is in a different state than I expected, which is worth a word at the end.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What is Codename One?&lt;/strong&gt; 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 &lt;a href="https://www.codenameone.com/" rel="noopener noreferrer"&gt;codenameone.com&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  A new Build Cloud UI — preview
&lt;/h2&gt;

&lt;p&gt;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 &lt;em&gt;live now&lt;/em&gt; &lt;a href="https://cloud.codenameone.com/console/index.html" rel="noopener noreferrer"&gt;here&lt;/a&gt;, alongside the current console you can still find &lt;a href="https://cloud.codenameone.com/secure/index.html" rel="noopener noreferrer"&gt;here&lt;/a&gt;. We want eyes and feedback on it before we flip the default.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcpi1a8zmzp4oj1o3aqgs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcpi1a8zmzp4oj1o3aqgs.png" alt="New Build Cloud console — Builds page, dark theme" width="800" height="455"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;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 &lt;code&gt;Form&lt;/code&gt;, &lt;code&gt;Container&lt;/code&gt;, &lt;code&gt;BoxLayout&lt;/code&gt;, &lt;code&gt;Toolbar&lt;/code&gt;, &lt;code&gt;theme.css&lt;/code&gt; you would write for a phone build. &lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;h2&gt;
  
  
  Device APIs become first-class
&lt;/h2&gt;

&lt;p&gt;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: &lt;strong&gt;biometrics&lt;/strong&gt;, &lt;strong&gt;cryptography&lt;/strong&gt;, and &lt;strong&gt;NFC&lt;/strong&gt;. 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.&lt;/p&gt;

&lt;h3&gt;
  
  
  Biometrics — &lt;a href="https://github.com/codenameone/CodenameOne/pull/4987" rel="noopener noreferrer"&gt;PR #4987&lt;/a&gt;
&lt;/h3&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;Biometrics&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Biometrics&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getInstance&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(!&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;canAuthenticate&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// No hardware, or no enrolled biometrics&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;authenticate&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Unlock your account"&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;onResult&lt;/span&gt;&lt;span class="o"&gt;((&lt;/span&gt;&lt;span class="n"&gt;success&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;BiometricError&lt;/span&gt; &lt;span class="n"&gt;code&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;((&lt;/span&gt;&lt;span class="nc"&gt;BiometricException&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;getError&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;switch&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;code&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="nl"&gt;USER_CANCELED:&lt;/span&gt;  &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
            &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="nl"&gt;LOCKED_OUT:&lt;/span&gt;     &lt;span class="n"&gt;fallToPassword&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
            &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="nl"&gt;NOT_ENROLLED:&lt;/span&gt;   &lt;span class="n"&gt;askToEnroll&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
            &lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;             &lt;span class="n"&gt;fallToPassword&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;unlock&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On iOS this wraps &lt;code&gt;LocalAuthentication.framework&lt;/code&gt;; on Android API 29+ it uses &lt;code&gt;BiometricPrompt&lt;/code&gt; and on API 23-28 it keeps the legacy &lt;code&gt;FingerprintManager&lt;/code&gt; 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 &lt;strong&gt;just works&lt;/strong&gt;.&lt;/p&gt;

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

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

&lt;h3&gt;
  
  
  Cryptography — &lt;a href="https://github.com/codenameone/CodenameOne/pull/4994" rel="noopener noreferrer"&gt;PR #4994&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Routine cryptography (hashing, MAC, symmetric and asymmetric encryption, signing, JWT, OTP) is now in &lt;code&gt;com.codename1.security&lt;/code&gt; 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, &lt;code&gt;SecureRandom&lt;/code&gt; — route through each port's native crypto provider so you get hardware-backed primitives where the device offers them.&lt;/p&gt;

&lt;p&gt;A typical AES-GCM round-trip:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;SecretKey&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;KeyGenerator&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;aes&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;256&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt;    &lt;span class="n"&gt;nonce&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;SecureRandom&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;bytes&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt;    &lt;span class="n"&gt;enc&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Cipher&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;aesEncrypt&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Cipher&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;AES_GCM&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;nonce&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                                    &lt;span class="s"&gt;"secret"&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getBytes&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"UTF-8"&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt;    &lt;span class="n"&gt;dec&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Cipher&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;aesDecrypt&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Cipher&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;AES_GCM&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;nonce&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;enc&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A SHA-256 hash:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;digest&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Hash&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;sha256&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"hello"&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getBytes&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"UTF-8"&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;hex&lt;/span&gt;    &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Hash&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toHex&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;digest&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A signed JWT:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;hsKey&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;KeyGenerator&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;hmac&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;256&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;token&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Jwt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;signHs256&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hsKey&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                   &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;claim&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"sub"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"user-42"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                   &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;claim&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"exp"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;currentTimeMillis&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;3600&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                   &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;compact&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

&lt;span class="nc"&gt;Jwt&lt;/span&gt; &lt;span class="n"&gt;parsed&lt;/span&gt;    &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Jwt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;verifyHs256&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;hsKey&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;   &lt;span class="c1"&gt;// throws on bad signature&lt;/span&gt;
&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;sub&lt;/span&gt;    &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;parsed&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getClaim&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"sub"&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;asString&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And a TOTP that lines up with Google Authenticator / Authy:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;sharedSecret&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Base32&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;decode&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"JBSWY3DPEHPK3PXP"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;code&lt;/span&gt;         &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Otp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;totp&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sharedSecret&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;    &lt;span class="c1"&gt;// current 30s window&lt;/span&gt;
&lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="n"&gt;ok&lt;/span&gt;          &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Otp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;verifyTotp&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;code&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sharedSecret&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="cm"&gt;/* drift */&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The PR also ships a matching UI widget — &lt;code&gt;com.codename1.components.OtpField&lt;/code&gt; — 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:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;OtpField&lt;/span&gt; &lt;span class="n"&gt;otp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;OtpField&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;otp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setCompleteListener&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;code&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Otp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;verifyTotp&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;code&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sharedSecret&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;proceed&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;otp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setError&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Wrong code"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;});&lt;/span&gt;
&lt;span class="n"&gt;form&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;otp&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We deliberately chose conservative defaults: &lt;code&gt;AES/GCM/NoPadding&lt;/code&gt; for new authenticated AES, &lt;code&gt;RSA/ECB/OAEPWithSHA-256AndMGF1Padding&lt;/code&gt; for new RSA, constant-time HMAC compare, a bias-free &lt;code&gt;intBelow(n)&lt;/code&gt; on &lt;code&gt;SecureRandom&lt;/code&gt;. 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.&lt;/p&gt;

&lt;h3&gt;
  
  
  NFC — &lt;a href="https://github.com/codenameone/CodenameOne/pull/4996" rel="noopener noreferrer"&gt;PR #4996&lt;/a&gt;
&lt;/h3&gt;

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

&lt;p&gt;Reading an NDEF URI tag — the "tap a poster" pattern:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;Nfc&lt;/span&gt; &lt;span class="n"&gt;nfc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Nfc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getInstance&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(!&lt;/span&gt;&lt;span class="n"&gt;nfc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;canRead&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;             &lt;span class="c1"&gt;// no NFC hardware / NFC disabled&lt;/span&gt;

&lt;span class="n"&gt;nfc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;readTag&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;NfcReadOptions&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setNdefOnly&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setAlertMessage&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Hold near the poster"&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
   &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;onResult&lt;/span&gt;&lt;span class="o"&gt;((&lt;/span&gt;&lt;span class="n"&gt;tag&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;tag&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;readNdef&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;onResult&lt;/span&gt;&lt;span class="o"&gt;((&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getFirstRecord&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;getUriPayload&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
                &lt;span class="nc"&gt;Display&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getInstance&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;execute&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="o"&gt;});&lt;/span&gt;
   &lt;span class="o"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Exchanging APDUs with an EMV / transit card:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="n"&gt;nfc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;readTag&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;NfcReadOptions&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setTechFilter&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;TagType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ISO_DEP&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setIsoSelectAids&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;myAid&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
   &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;onResult&lt;/span&gt;&lt;span class="o"&gt;((&lt;/span&gt;&lt;span class="n"&gt;tag&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="nc"&gt;IsoDep&lt;/span&gt; &lt;span class="n"&gt;iso&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tag&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getIsoDep&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;iso&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;iso&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;transceive&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;myCommandApdu&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;onResult&lt;/span&gt;&lt;span class="o"&gt;((&lt;/span&gt;&lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ApduResponse&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isSuccess&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="cm"&gt;/* parse response */&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="o"&gt;});&lt;/span&gt;
   &lt;span class="o"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Acting as a contactless card via Host Card Emulation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;LoyaltyCard&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;HostCardEmulationService&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="nf"&gt;getAids&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="s"&gt;"F0010203040506"&lt;/span&gt; &lt;span class="o"&gt;};&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="nf"&gt;processCommand&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;apdu&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;ApduResponse&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;withStatus&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;loyaltyId&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getBytes&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"UTF-8"&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;
                                       &lt;span class="nc"&gt;ApduResponse&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;swSuccess&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="nc"&gt;Nfc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getInstance&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;registerHostCardEmulationService&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;LoyaltyCard&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Android uses &lt;code&gt;NfcAdapter&lt;/code&gt; foreground dispatch / reader-mode and &lt;code&gt;HostApduService&lt;/code&gt;; both manifest entries are auto-injected by the Maven plugin and the build daemon when this class is referenced. iOS uses &lt;code&gt;Core NFC&lt;/code&gt; (&lt;code&gt;NFCNDEFReaderSession&lt;/code&gt;, &lt;code&gt;NFCTagReaderSession&lt;/code&gt;) for reading and &lt;code&gt;CardSession&lt;/code&gt; (iOS 17.4+, EU only) for HCE; the &lt;code&gt;NFCReaderUsageDescription&lt;/code&gt; 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 &lt;strong&gt;Simulate -&amp;gt; NFC&lt;/strong&gt; 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 &lt;code&gt;HostCardEmulationService&lt;/code&gt;, so you can sit at your desk and drive every code path without a card or a reader.&lt;/p&gt;

&lt;p&gt;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 &lt;code&gt;if&lt;/code&gt; statements — always gate on &lt;code&gt;canRead()&lt;/code&gt; and you are fine.&lt;/p&gt;

&lt;h2&gt;
  
  
  cn1libs can now own simulator menus — and that changes Bluetooth
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/codenameone/CodenameOne/pull/4988" rel="noopener noreferrer"&gt;PR #4988&lt;/a&gt; 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 &lt;code&gt;META-INF/codenameone/simulator-hooks.properties&lt;/code&gt; and lets any cn1lib contribute its own menu items. The cn1lib does not reference any Swing types — the data file just names a &lt;code&gt;name=...&lt;/code&gt; for the menu group and a series of &lt;code&gt;itemN&lt;/code&gt; entries pointing at public static no-arg methods, each with an optional &lt;code&gt;labelN&lt;/code&gt;. The simulator does the rest.&lt;/p&gt;

&lt;p&gt;A skeletal hook file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight properties"&gt;&lt;code&gt;&lt;span class="py"&gt;name&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;Bluetooth&lt;/span&gt;
&lt;span class="py"&gt;namespace&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;bluetooth&lt;/span&gt;

&lt;span class="py"&gt;item1&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;com.example.bt.sim.Hooks#toggleAdapter&lt;/span&gt;
&lt;span class="py"&gt;label1&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;Toggle adapter on/off&lt;/span&gt;

&lt;span class="py"&gt;item2&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;com.example.bt.sim.Hooks#addDemoPeripheral&lt;/span&gt;
&lt;span class="py"&gt;label2&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;Add demo peripheral&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;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 &lt;code&gt;JMenu&lt;/code&gt; / &lt;code&gt;JMenuItem&lt;/code&gt; directly or have to be recompiled when the simulator's UI shell changes. The neutral &lt;code&gt;SimulatorHook&lt;/code&gt; record (&lt;code&gt;menuName&lt;/code&gt;, &lt;code&gt;label&lt;/code&gt;, &lt;code&gt;Runnable&lt;/code&gt;) is the contract; the UI on top of it is replaceable.&lt;/p&gt;

&lt;h3&gt;
  
  
  Bluetooth that you can actually debug
&lt;/h3&gt;

&lt;p&gt;The reason the simulator hook landed &lt;em&gt;this&lt;/em&gt; week is that we have been working on the &lt;a href="https://github.com/codenameone/bluetoothle-codenameone/" rel="noopener noreferrer"&gt;bluetoothle-codenameone&lt;/a&gt; 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.&lt;/p&gt;

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

&lt;p&gt;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 &lt;strong&gt;real devices&lt;/strong&gt;!!! &lt;/p&gt;

&lt;p&gt;The cn1lib's &lt;code&gt;simulator-hooks.properties&lt;/code&gt; ships with seven hooks that put the simulator in the simulator's menu bar:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;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
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So a typical Bluetooth iteration loop looks like this:&lt;/p&gt;

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

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;With the cn1-bluetooth simulator backend, the first four of those variables collapse to &lt;em&gt;one&lt;/em&gt;: 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.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;h2&gt;
  
  
  In-app purchase consistency — &lt;a href="https://github.com/codenameone/CodenameOne/pull/4990" rel="noopener noreferrer"&gt;PR #4990&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;A forum report of &lt;code&gt;submitReceipt&lt;/code&gt; being invoked repeatedly turned into three closely related fixes in &lt;code&gt;Purchase.synchronizeReceipts&lt;/code&gt;. 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.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;removePendingPurchase&lt;/code&gt; matched only on &lt;code&gt;transactionId&lt;/code&gt;. When a receipt's &lt;code&gt;transactionId&lt;/code&gt; 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 &lt;code&gt;synchronizeReceipts&lt;/code&gt; 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 &lt;code&gt;(sku, storeCode, purchaseDate, orderData)&lt;/code&gt; when &lt;code&gt;transactionId&lt;/code&gt; is null on either side.&lt;/li&gt;
&lt;li&gt;The recursive &lt;code&gt;synchronizeReceipts(0, callback)&lt;/code&gt; re-registered the caller's &lt;code&gt;SuccessCallback&lt;/code&gt; on every iteration, so a queue of &lt;em&gt;N&lt;/em&gt; pending receipts caused the user's callback to fire &lt;em&gt;N&lt;/em&gt; times. The recursive call now passes &lt;code&gt;null&lt;/code&gt; since the original callback is already in &lt;code&gt;synchronizeReceiptsCallbacks&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;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.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;h2&gt;
  
  
  UTF-8: JDK-compatible replace semantics + a NEON ASCII fast path — &lt;a href="https://github.com/codenameone/CodenameOne/pull/4989" rel="noopener noreferrer"&gt;PR #4989&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;String.getBytes("UTF-8")&lt;/code&gt; and &lt;code&gt;new String(bytes, "UTF-8")&lt;/code&gt; on iOS were behind the standard JDK in two ways. The decoder threw &lt;code&gt;RuntimeException("Decoding Error")&lt;/code&gt; on malformed input — the rest of the Java world emits &lt;code&gt;U+FFFD&lt;/code&gt; 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 &lt;code&gt;ISO-8859-2 → NSISOLatin1&lt;/code&gt; alias that hid encoding errors when &lt;code&gt;NSString&lt;/code&gt; rejected the input.&lt;/p&gt;

&lt;p&gt;The new decoder is a Hoehrmann DFA with JDK-compatible REPLACE semantics: one &lt;code&gt;U+FFFD&lt;/code&gt; per maximal subpart violation, truncated trailing sequences also emit a &lt;code&gt;U+FFFD&lt;/code&gt;. The encoder is a portable UTF-16 → UTF-8 with surrogate-pair joining; the Apple path now uses it directly so &lt;code&gt;NSString&lt;/code&gt; 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.&lt;/p&gt;

&lt;p&gt;The fun part is the SIMD work. The ASCII prefix scan (&lt;code&gt;vmaxvq_u8&lt;/code&gt;) and the &lt;code&gt;u8 → u16&lt;/code&gt; widen (&lt;code&gt;vmovl_u8&lt;/code&gt;) are gated on &lt;code&gt;__ARM_NEON&lt;/code&gt; and only kick in for inputs ≥ 64 bytes. A standalone microbenchmark shows roughly &lt;strong&gt;53× speedup&lt;/strong&gt; over the scalar DFA on ASCII-heavy payloads. The integration-level benchmark cannot see this number because allocating a fresh &lt;code&gt;char[]&lt;/code&gt; 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).&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;h2&gt;
  
  
  Two long-standing JVM fixes
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://github.com/codenameone/CodenameOne/pull/4980" rel="noopener noreferrer"&gt;PR #4980&lt;/a&gt; — Iterative GC mark to fix iOS stack overflow on deep graphs
&lt;/h3&gt;

&lt;p&gt;Issue &lt;a href="https://github.com/codenameone/CodenameOne/issues/3136" rel="noopener noreferrer"&gt;#3136&lt;/a&gt; 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 &lt;code&gt;LinkedList&lt;/code&gt; 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.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://github.com/codenameone/CodenameOne/pull/4985" rel="noopener noreferrer"&gt;PR #4985&lt;/a&gt; — Don't rely on C arg eval order in &lt;code&gt;PUTFIELD&lt;/code&gt; / &lt;code&gt;MULTIANEWARRAY&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Issue &lt;a href="https://github.com/codenameone/CodenameOne/issues/3108" rel="noopener noreferrer"&gt;#3108&lt;/a&gt; is the other one. Several &lt;code&gt;PUTFIELD&lt;/code&gt; and &lt;code&gt;MULTIANEWARRAY&lt;/code&gt; 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 &lt;code&gt;-O&lt;/code&gt; 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.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;h2&gt;
  
  
  Hardware keyboard and mouse on iOS and Android — &lt;a href="https://github.com/codenameone/CodenameOne/pull/4982" rel="noopener noreferrer"&gt;PR #4982&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Issue &lt;a href="https://github.com/codenameone/CodenameOne/issues/3498" rel="noopener noreferrer"&gt;#3498&lt;/a&gt; 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 &lt;code&gt;pointerHover*&lt;/code&gt; and the full keyboard event surface, but the &lt;em&gt;ports&lt;/em&gt; 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 &lt;code&gt;keyPressed(0)&lt;/code&gt; on Android, and Enter was silently dropped unless you set &lt;code&gt;sendEnterKey=true&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This PR forwards &lt;code&gt;ACTION_HOVER_ENTER/MOVE/EXIT&lt;/code&gt; 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.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;h2&gt;
  
  
  Expanded CSS gradients and blurs — &lt;a href="https://github.com/codenameone/CodenameOne/pull/4957" rel="noopener noreferrer"&gt;PR #4957&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;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. &lt;code&gt;filter&lt;/code&gt; and &lt;code&gt;backdrop-filter&lt;/code&gt; were ignored entirely. The bitmap fallback worked but it cost you the GPU path and it could not scale with the component.&lt;/p&gt;

&lt;p&gt;This PR moves the full CSS gradient range and &lt;code&gt;filter: blur(...)&lt;/code&gt; 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 &lt;code&gt;filter&lt;/code&gt; and &lt;code&gt;backdrop-filter&lt;/code&gt;. Drawn on the GPU. Composable with everything else.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.HeroCard&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;conic-gradient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="m"&gt;30deg&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;#ff7a00&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;#ff2d95&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;#6750a4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;#ff7a00&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nl"&gt;border-radius&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;24px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;blur&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0.5px&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.GlassDialog&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;rgba&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;255&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;255&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;255&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0.18&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="py"&gt;backdrop-filter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;blur&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;18px&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nl"&gt;border-radius&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;28px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;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 &lt;code&gt;Canvas&lt;/code&gt; / 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.&lt;/p&gt;

&lt;h2&gt;
  
  
  On Metal: the community got there first
&lt;/h2&gt;

&lt;p&gt;I said previously that I wanted to flip &lt;code&gt;ios.metal=true&lt;/code&gt; to the default &lt;em&gt;this&lt;/em&gt; 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.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;If you are one of the developers who flipped the hint, took screenshots, and filed issues over the past two weeks: &lt;strong&gt;thank you&lt;/strong&gt;. 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, &lt;a href="https://github.com/codenameone/CodenameOne/blob/master/docs/developer-guide/Working-With-iOS.asciidoc" rel="noopener noreferrer"&gt;the build hint is still&lt;/a&gt; &lt;code&gt;ios.metal=true&lt;/code&gt;. We would still love your screens through it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping up
&lt;/h2&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;And the Build Cloud preview is sitting on the server right now, waiting for you to break it. Please do.&lt;/p&gt;

&lt;p&gt;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 &lt;a href="https://github.com/codenameone/CodenameOne/issues/3136" rel="noopener noreferrer"&gt;#3136&lt;/a&gt; with the 50,000-node &lt;code&gt;LinkedList&lt;/code&gt; repro that finally made the GC mark a one-day fix instead of a one-month investigation.&lt;/p&gt;

&lt;p&gt;Issue tracker is &lt;a href="https://github.com/codenameone/CodenameOne/issues" rel="noopener noreferrer"&gt;here&lt;/a&gt;, the &lt;a href="https://www.codenameone.com/playground/" rel="noopener noreferrer"&gt;Playground&lt;/a&gt;, &lt;a href="https://www.codenameone.com/initializr/" rel="noopener noreferrer"&gt;Initializr&lt;/a&gt;, and &lt;a href="https://www.codenameone.com/skindesigner/" rel="noopener noreferrer"&gt;Skin Designer&lt;/a&gt; are all still the easiest places to see what the JavaScript port is capable of carrying. The Build Cloud preview is at &lt;code&gt;/console/&lt;/code&gt; on cloud.codenameone.com once you are signed in.&lt;/p&gt;

</description>
      <category>java</category>
      <category>mobile</category>
      <category>android</category>
      <category>ios</category>
    </item>
    <item>
      <title>Skills, Java 17, And Theme Accents</title>
      <dc:creator>Shai Almog</dc:creator>
      <pubDate>Fri, 22 May 2026 13:46:38 +0000</pubDate>
      <link>https://dev.to/codenameone/skills-java-17-and-theme-accents-59dp</link>
      <guid>https://dev.to/codenameone/skills-java-17-and-theme-accents-59dp</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frswozohfmrqn22vvjnl5.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frswozohfmrqn22vvjnl5.jpg" alt="Skills, Java 17, And Theme Accents"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Last week was about Metal and the Skin Designer. This week the headline items are about what a brand new project looks like when you generate it: the default JDK is Java 17, and every generated project ships with an &lt;code&gt;AGENTS.md&lt;/code&gt; authoring skill that lets any modern AI agent work on the project intelligently. There are also some other things worth covering: a runtime accent palette on the new native themes, three Metal follow-ups (one of which introduces a new matrix-correct translate API), the JDK 11+ String API gap closed, and iOS push permission that no longer fires at app launch.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What is Codename One?&lt;/strong&gt; 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 &lt;a href="https://www.codenameone.com/" rel="noopener noreferrer"&gt;codenameone.com&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Java 17 by default
&lt;/h2&gt;

&lt;p&gt;We changed the default projects generated by the Initializr to Java 17+ to focus on the future of Codename One. The existing Java 8 option in the Initializr is still selectable from the radio panel if you have a reason to use it. Pick whichever you want.&lt;/p&gt;

&lt;p&gt;The Java 17 path is the one we now recommend for new work. Generated projects build with any JDK from 17 onwards (we routinely test on 21 and 25); you do not need to install Java 17 specifically. The bigger picture of how Java 17 support works in the toolchain, including which language features land in your app code and how the iOS / Android ports handle the newer bytecode, was covered in &lt;a href="https://www.codenameone.com/blog/official-experimental-java-17-support/" rel="noopener noreferrer"&gt;Official Experimental Java 17 Support&lt;/a&gt; earlier this year. The change this week is the default and the wording: the &lt;em&gt;(Experimental)&lt;/em&gt; tag is gone, and Java 17 is now what you get unless you opt out.&lt;/p&gt;

&lt;h2&gt;
  
  
  AGENTS.md and the Codename One skill
&lt;/h2&gt;

&lt;p&gt;The other change in &lt;a href="https://github.com/codenameone/CodenameOne/pull/4946" rel="noopener noreferrer"&gt;PR #4946&lt;/a&gt; is that every Java 17 project the Initializr generates now ships an &lt;code&gt;AGENTS.md&lt;/code&gt; file at the project root and a Codename One authoring skill alongside it.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;AGENTS.md&lt;/code&gt; is the convention for handing project-specific context to any AI agent. Claude Code, Cursor, Codex, Aider; they all look for it. Codename One projects now ship one. The actual skill content lives under &lt;code&gt;.agent-skills/codename-one/&lt;/code&gt; (vendor-neutral) and the source for it is in the repo at &lt;a href="https://github.com/codenameone/CodenameOne/tree/master/scripts/initializr/common/src/main/resources/skill" rel="noopener noreferrer"&gt;&lt;code&gt;scripts/initializr/common/src/main/resources/skill&lt;/code&gt;&lt;/a&gt; if you want to read through it directly. There is also a thin stub at &lt;code&gt;.claude/skills/codename-one/SKILL.md&lt;/code&gt; so Claude Code's &lt;code&gt;/skills&lt;/code&gt; picker indexes it; the stub redirects to the same vendor-neutral content.&lt;/p&gt;

&lt;p&gt;We deliberately scoped this to Java 17 projects. The older Java 8 build had additional constraints (Java 5/8 source target, retrolambda, the historical bytecode rewrite rules) that made the "what can I actually use" answer noticeably more complicated. Restricting the skill to Java 17 lets us give agents a cleaner picture of the language level, the toolchain, and the build commands without spending half the SKILL.md on caveats. If you stay on Java 8, you keep the project layout you had; nothing changes for you.&lt;/p&gt;

&lt;p&gt;A few things the skill makes possible that I think are genuinely useful:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Agents can debug a Codename One app under &lt;code&gt;jdb&lt;/code&gt;.&lt;/strong&gt; This is the one I am most pleased with. The simulator is a regular JVM, so the standard Java Debugger attaches cleanly, but agents previously had no idea this workflow was available. The skill's &lt;code&gt;debugging.md&lt;/code&gt; reference walks through starting the simulator with the right &lt;code&gt;-Xrunjdwp&lt;/code&gt; flags, attaching &lt;code&gt;jdb&lt;/code&gt;, setting breakpoints, dumping locals, and stepping. The same workflow works in CI and any headless context where a graphical debugger is not an option. For an LLM that is otherwise reduced to "add a &lt;code&gt;println&lt;/code&gt; and hope", this is a much sharper tool.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Agents can check whether an API is part of the Codename One subset before they suggest it.&lt;/strong&gt; Codename One targets a Java 5/8 shaped JDK so the same bytecode translates to iOS, Android, and JavaScript. An agent that has only read regular Java idioms will routinely reach for &lt;code&gt;java.nio.file&lt;/code&gt;, &lt;code&gt;java.time&lt;/code&gt;, or pieces of &lt;code&gt;java.util.concurrent&lt;/code&gt; that the framework does not include. The skill ships a single-file &lt;code&gt;IsApiSupported.java&lt;/code&gt; tool that an agent can invoke to verify a class or method before writing code against it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Agents can validate a CSS snippet before applying it.&lt;/strong&gt; Codename One CSS is its own subset; rules that look fine to a browser developer get silently dropped by the compiler. The &lt;code&gt;IsCssValid.java&lt;/code&gt; tool lets the agent confirm the compiler will accept a snippet without booting the simulator.&lt;/p&gt;

&lt;p&gt;These three things together are most of why an agent that was previously polite-but-not-useful on a Codename One project is now actually productive on one. If you do not use agents, the same Markdown is one of the better tours of the framework's mental model that we have written; open &lt;code&gt;.agent-skills/codename-one/SKILL.md&lt;/code&gt; in any project you generate today and read top to bottom.&lt;/p&gt;

&lt;h2&gt;
  
  
  Native theme accents
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/codenameone/CodenameOne/pull/4884" rel="noopener noreferrer"&gt;PR #4884&lt;/a&gt; closes the loop on the new iOS Modern and Material 3 native themes &lt;a href="https://www.codenameone.com/blog/liquid-glass-material-3-modern-native-themes/" rel="noopener noreferrer"&gt;we shipped two weeks ago&lt;/a&gt;. The native themes now expose their accent palette as named theme constants, so rebranding your app to your own colours is a five-line CSS change instead of a fork.&lt;/p&gt;

&lt;p&gt;Override the constants inside the &lt;code&gt;#Constants&lt;/code&gt; block of your own &lt;code&gt;theme.css&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nf"&gt;#Constants&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="py"&gt;includeNativeBool&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="py"&gt;darkModeBool&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="py"&gt;--accent-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#ff2d95&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="py"&gt;--accent-color-dark&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#ff2d95&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="py"&gt;--accent-pressed-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#c71a75&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="py"&gt;--accent-on-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#ffffff&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is it. Every accent-bearing UIID picks up the new colour. Light and dark are independent (&lt;code&gt;--accent-color&lt;/code&gt; vs &lt;code&gt;--accent-color-dark&lt;/code&gt;), and partial overrides are fine; anything you do not redeclare stays at the framework default. Material 3 has a couple of additional container-tier constants for the elevated-surface tone; iOS ignores those.&lt;/p&gt;

&lt;p&gt;There is also a runtime path for dynamic theming (in-app accent toggles, branded flavours, A/B tests). It uses the same constants. The Native Themes chapter of the developer guide covers it in detail, along with the full iOS and Android constant tables and the places where the binding system intentionally does not apply: &lt;a href="https://github.com/codenameone/CodenameOne/blob/master/docs/developer-guide/Native-Themes.asciidoc#accent-palette-override" rel="noopener noreferrer"&gt;Accent palette override&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The point worth pulling out: the parts of theming that do not change per app (which UIIDs participate in the accent palette, which states they expose, which dark-mode counterparts they have) live inside the framework and stay there. The parts that do change per app (your colours) live in your project as five constants and nothing else. That is the whole reason this change exists.&lt;/p&gt;

&lt;h2&gt;
  
  
  Metal follow-ups
&lt;/h2&gt;

&lt;p&gt;Last week was about shipping the Metal renderer. This week is the follow-up week: three PRs, plus one new API on &lt;code&gt;Graphics&lt;/code&gt; that I think will quietly pay for itself many times over.&lt;/p&gt;

&lt;h3&gt;
  
  
  Per-axis scale decomposition (#4939, fixes #3302)
&lt;/h3&gt;

&lt;p&gt;Long-standing issue &lt;a href="https://github.com/codenameone/CodenameOne/issues/3302" rel="noopener noreferrer"&gt;#3302&lt;/a&gt; had a clear repro: &lt;code&gt;g.translate + g.scale(sx, sy) + fillShape&lt;/code&gt; with &lt;code&gt;sx != sy&lt;/code&gt; produced shapes that visibly drifted off the axis-aligned &lt;code&gt;drawRect&lt;/code&gt; and &lt;code&gt;drawLine&lt;/code&gt; calls the framework emitted alongside them. Triangles inscribed in rectangles escaped their bounding rect.&lt;/p&gt;

&lt;p&gt;The cause was that the legacy alpha-mask path rasterised the shape at a uniform scale (the diagonal ratio &lt;code&gt;h2/h1&lt;/code&gt;), then stretched the resulting texture non-uniformly through the GPU matrix to recover the requested aspect. The bbox math is exact in real numbers, but the texture is pixel-rounded at the intermediate uniform scale, so the stretch drifted the rasterised shape off the pixel grid that &lt;code&gt;drawRect&lt;/code&gt; and &lt;code&gt;drawLine&lt;/code&gt; were already on.&lt;/p&gt;

&lt;p&gt;The fix factors the user transform's 2x2 linear part by taking the column norms as &lt;code&gt;(sx, sy)&lt;/code&gt;, rasterises the path at &lt;code&gt;S(sx, sy)&lt;/code&gt; so the per-axis stretch happens at rasterisation time against a vector path rather than a pixel grid, and applies only the residual &lt;code&gt;transform * S(1/sx, 1/sy)&lt;/code&gt; on the GPU. The residual is pure rotation (and shear in the worst case), so no per-axis stretch happens at sample time and the alpha-mask texture lands on the same pixel grid as its &lt;code&gt;drawRect&lt;/code&gt; siblings.&lt;/p&gt;

&lt;p&gt;The change is gated to Metal; the GL ES2 path keeps its legacy branch so the existing GL goldens are byte-identical. A new &lt;code&gt;InscribedTriangleGrid&lt;/code&gt; screenshot test was registered with &lt;code&gt;Cn1ssDeviceRunner&lt;/code&gt; so the inscribed-triangle property is now visually verifiable in CI.&lt;/p&gt;

&lt;h3&gt;
  
  
  Clip-under-rotation diagnostic (#4924, towards #3921)
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/codenameone/CodenameOne/pull/4924" rel="noopener noreferrer"&gt;PR #4924&lt;/a&gt; does not fix a bug, it localises one. Issue &lt;a href="https://github.com/codenameone/CodenameOne/issues/3921" rel="noopener noreferrer"&gt;#3921&lt;/a&gt; is "clip-under-rotation behaves wrong on some ports", entangled with a &lt;code&gt;getClip&lt;/code&gt; / &lt;code&gt;setClip(int[])&lt;/code&gt; round-trip limitation the reporter himself called out as a separate issue. To split the two, we shipped a screenshot test that uses only &lt;code&gt;pushClip&lt;/code&gt; / &lt;code&gt;popClip&lt;/code&gt; and &lt;code&gt;rotateRadians&lt;/code&gt;. The clip becomes non-axis-aligned via &lt;code&gt;clipRect&lt;/code&gt; inside a 30-degree rotation, which forces the framework through its polygon-clip branch.&lt;/p&gt;

&lt;p&gt;The expected outcome is a 30-degree-tilted red fill that overlaps the navy outline at two diagonal corners and falls short at the other two. Two distinguishable failure modes are pre-labelled in the PR: the clip widened to its axis-aligned bbox (red exactly matches the navy outline), or the polygon clip dropped entirely (red fills the whole cell). When the iOS Metal cell of this test renders, we know within a glance which of the three behaviours we are looking at. The expected-failure cell is also a hypothesis: &lt;code&gt;ClipRect.m&lt;/code&gt;'s polygon initialiser stores &lt;code&gt;x = y = w = h = -1&lt;/code&gt;, and the Metal execute path then calls &lt;code&gt;CN1MetalSetScissor(0, 0, -2, -2)&lt;/code&gt;, whose &lt;code&gt;width &amp;lt;= 0 / height &amp;lt;= 0&lt;/code&gt; branch sets the scissor to the full framebuffer instead of the intended polygon. If the screenshot confirms the hypothesis, the fix is a one-line replacement of the polygon-scissor fallback.&lt;/p&gt;

&lt;h3&gt;
  
  
  iOS Metal colour space hint (#4909, fixes #4908)
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/codenameone/CodenameOne/pull/4909" rel="noopener noreferrer"&gt;PR #4909&lt;/a&gt; adds an &lt;code&gt;ios.metal.colorSpace&lt;/code&gt; build hint. Until this week, the Metal layer's &lt;code&gt;CAMetalLayer.colorspace&lt;/code&gt; was hard-coded to sRGB. For most apps that is right; sRGB is what your existing assets are authored in. But on iPhone XR and later, Apple's screens are wide-gamut (Display P3), and a marketing-led brand that ships P3 artwork was visibly losing saturation by being routed through the sRGB pipeline.&lt;/p&gt;

&lt;p&gt;Accepted values are &lt;code&gt;sRGB&lt;/code&gt; (default), &lt;code&gt;displayP3&lt;/code&gt;, &lt;code&gt;deviceRGB&lt;/code&gt;, &lt;code&gt;linearSRGB&lt;/code&gt;, &lt;code&gt;extendedSRGB&lt;/code&gt;, &lt;code&gt;extendedLinearSRGB&lt;/code&gt;, and &lt;code&gt;none&lt;/code&gt;. Set it in &lt;code&gt;codenameone_settings.properties&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight properties"&gt;&lt;code&gt;&lt;span class="py"&gt;codename1.arg.ios.metal.colorSpace&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;displayP3&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The hint is dormant when &lt;code&gt;ios.metal=false&lt;/code&gt;, so existing GL builds are unchanged. Unrecognised values produce a warning log and fall back to sRGB. Documented under &lt;a href="https://github.com/codenameone/CodenameOne/blob/master/docs/developer-guide/Working-With-iOS.asciidoc" rel="noopener noreferrer"&gt;Working-With-iOS.asciidoc&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  The new &lt;code&gt;translateMatrix&lt;/code&gt; API
&lt;/h3&gt;

&lt;p&gt;The Inscribed-Triangle-Grid test in #4939 also surfaced a quiet papercut in &lt;code&gt;Graphics&lt;/code&gt; that is worth pulling out as its own feature.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Graphics.translate(int, int)&lt;/code&gt; does not compose into the affine transform the way &lt;code&gt;scale()&lt;/code&gt; and &lt;code&gt;rotateRadians()&lt;/code&gt; do. It accumulates into a per-Graphics integer offset that is added to draw coordinates before the impl matrix is applied. That is a holdover from the very first version of the framework, when &lt;code&gt;Graphics&lt;/code&gt; did not have a matrix at all. Today the consequence is surprising: a subsequent &lt;code&gt;g.scale(sx, sy)&lt;/code&gt; multiplies the integer translate too, which means the same code produces visibly different positions depending on whether you scale before or after you translate.&lt;/p&gt;

&lt;p&gt;The new &lt;code&gt;Graphics.translateMatrix(float, float)&lt;/code&gt; composes the translation directly onto the impl matrix, in the same way &lt;code&gt;scale&lt;/code&gt; and &lt;code&gt;rotateRadians&lt;/code&gt; already do. The result is uniform "post-multiply translate onto the current transform" semantics across iOS (both GL and Metal), JavaSE, Android, and the JavaScript port. Same code, same on-screen position, whether you are drawing into a &lt;code&gt;Form&lt;/code&gt;'s &lt;code&gt;Graphics&lt;/code&gt; or a mutable &lt;code&gt;Image&lt;/code&gt;'s &lt;code&gt;Graphics&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Matrix-correct composition. Use this when you want translate to&lt;/span&gt;
&lt;span class="c1"&gt;// behave like scale and rotate (composed into the affine transform).&lt;/span&gt;
&lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;translateMatrix&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;centerX&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;centerY&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;rotateRadians&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;angle&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;scale&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sx&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sy&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;translateMatrix&lt;/span&gt;&lt;span class="o"&gt;(-&lt;/span&gt;&lt;span class="n"&gt;centerX&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;centerY&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;fillShape&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For app code writing affine-transform pipelines (the "translate to pivot, rotate, scale, translate back" idiom from Java2D and AWT), this is the API you want. &lt;code&gt;isTranslateMatrixSupported()&lt;/code&gt; returns true on every modern port. The old &lt;code&gt;translate(int, int)&lt;/code&gt; is not deprecated and is not going anywhere; half the framework's internal scrolling code is built on it. The new method is the one to reach for in new drawing code, particularly anything that combines translate with scale or rotate.&lt;/p&gt;

&lt;h2&gt;
  
  
  String API: &lt;code&gt;replace(CharSequence, CharSequence)&lt;/code&gt;, &lt;code&gt;replaceAll&lt;/code&gt;, &lt;code&gt;replaceFirst&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/codenameone/CodenameOne/pull/4893" rel="noopener noreferrer"&gt;PR #4893&lt;/a&gt; closes a long-standing gap reported in issue &lt;a href="https://github.com/codenameone/CodenameOne/issues/4878" rel="noopener noreferrer"&gt;#4878&lt;/a&gt;. The JDK 1.5+ overload of &lt;code&gt;String.replace&lt;/code&gt; that takes &lt;code&gt;CharSequence&lt;/code&gt; arguments (the one nearly every modern Java tutorial reaches for) was missing from the Codename One subset. So were &lt;code&gt;String.replaceAll(String, String)&lt;/code&gt; and &lt;code&gt;String.replaceFirst(String, String)&lt;/code&gt;. Because none of the three were on the bootclasspath, code that reached for them did not compile against a Codename One project at all; you had to know to fall back to the older &lt;code&gt;replace(char, char)&lt;/code&gt; overload and to roll your own regex.&lt;/p&gt;

&lt;p&gt;All three are now wired in. &lt;code&gt;String.replace(CharSequence, CharSequence)&lt;/code&gt; has a real implementation in &lt;code&gt;vm/JavaAPI&lt;/code&gt;. &lt;code&gt;replaceAll&lt;/code&gt; and &lt;code&gt;replaceFirst&lt;/code&gt; are wired through the bytecode-compliance rewriter to a new &lt;code&gt;JdkApiRewriteHelper&lt;/code&gt; pair that delegates to the existing &lt;code&gt;RE&lt;/code&gt; regex engine (the same pattern we have been using for years on &lt;code&gt;String.split&lt;/code&gt;). New compliance tests cover both rewrite rules.&lt;/p&gt;

&lt;p&gt;It is a small change in line count. In practice it is a noticeable reduction in how often "I copied a snippet from Stack Overflow and it didn't work on iOS" turns into a real bug. Three of the most-reached-for &lt;code&gt;String&lt;/code&gt; methods in modern Java are now part of the on-device API.&lt;/p&gt;

&lt;h2&gt;
  
  
  iOS push permission no longer fires at app launch
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/codenameone/CodenameOne/pull/4894" rel="noopener noreferrer"&gt;PR #4894&lt;/a&gt; fixes issue &lt;a href="https://github.com/codenameone/CodenameOne/issues/4876" rel="noopener noreferrer"&gt;#4876&lt;/a&gt;. With &lt;code&gt;ios.includePush=true&lt;/code&gt; the framework used to call &lt;code&gt;requestAuthorizationWithOptions&lt;/code&gt; from &lt;code&gt;application:didFinishLaunchingWithOptions:&lt;/code&gt;, which meant the iOS system permission dialog fired as soon as the app finished launching, before the user had seen any of your screens. There is no good way to recover from a "Don't Allow" tap at that point. The user has not experienced the app yet, does not know why notifications matter, and tapping Don't Allow is the path of least resistance. Once denied, re-prompting requires sending the user out to Settings.&lt;/p&gt;

&lt;p&gt;The fix moves the prompt to the natural points. &lt;code&gt;Push.register()&lt;/code&gt; triggers the system prompt (this code path already requested permission inside &lt;code&gt;IOSNative.m&lt;/code&gt;; we just stopped firing it ahead of time). &lt;code&gt;LocalNotification.schedule()&lt;/code&gt; also triggers it, via a new &lt;code&gt;requestAuthorizationWithOptions&lt;/code&gt; call in &lt;code&gt;sendLocalNotification&lt;/code&gt;. Same flow Android has been on for years. The practical consequence is that you can now show your own rationale screen ("we'd like to ping you when your order ships") before the system dialog fires.&lt;/p&gt;

&lt;p&gt;If you have an app that needs the legacy launch-time behaviour, a backwards-compatibility build hint restores it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight properties"&gt;&lt;code&gt;&lt;span class="py"&gt;codename1.arg.ios.notificationPermissionAtLaunch&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The default is &lt;code&gt;false&lt;/code&gt;, so existing apps that did not opt in pick up the new behaviour on next rebuild. Documented in &lt;a href="https://github.com/codenameone/CodenameOne/blob/master/docs/developer-guide/Push-Notifications.asciidoc" rel="noopener noreferrer"&gt;Push-Notifications.asciidoc&lt;/a&gt;. The cloud-side build server change shipped as &lt;a href="https://github.com/codenameone/BuildDaemon/pull/71" rel="noopener noreferrer"&gt;BuildDaemon #71&lt;/a&gt;, so local and cloud builds match.&lt;/p&gt;

&lt;p&gt;One thing to flag if you are updating an existing iOS app: if your onboarding flow was relying on the launch-time prompt happening automatically, your prompt now never fires unless &lt;code&gt;Push.register()&lt;/code&gt; or &lt;code&gt;LocalNotification.schedule()&lt;/code&gt; is invoked somewhere. That is almost certainly what you want, but check that the call lands.&lt;/p&gt;

&lt;h2&gt;
  
  
  Skin Designer FAQ follow-up
&lt;/h2&gt;

&lt;p&gt;A few questions came up on &lt;a href="https://github.com/codenameone/CodenameOne/discussions/4928" rel="noopener noreferrer"&gt;discussion #4928&lt;/a&gt; after last week's Skin Designer post, worth pulling forward here because they keep coming up in the same shape:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Skins do not affect CSS.&lt;/strong&gt; The skin is simulator scaffolding (device frame, screen rect, cutouts, safe-area insets); your &lt;code&gt;theme.css&lt;/code&gt; and your native theme are unrelated.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;For a known device, the defaults are usually right.&lt;/strong&gt; Pick the device, hit &lt;em&gt;Pick a shape&lt;/em&gt;, click &lt;em&gt;Finish&lt;/em&gt;. The customization UI is there for when our device database is incomplete (the iPhone 17e entry might say "no notch" when it actually has one, or the notch position might be off by a few pixels); when you have a physical device to measure against, that is where you refine.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Themes are leaving skins.&lt;/strong&gt; Historically the native theme was bundled inside each skin because that is what made sense at the time. Going forward the right home for themes is the framework itself, distributed via Maven, so you pick up updates automatically. The new native themes already work this way. The per-skin embedded theme stays for legacy compatibility and the Skin Designer still writes one for you, but the &lt;em&gt;Native Theme&lt;/em&gt; menu we shipped two weeks ago is the path forward.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The device database the Skin Designer reads from is open at &lt;a href="https://github.com/codenameone/CodenameOne/blob/master/scripts/skindesigner/common/src/main/resources/devices.json" rel="noopener noreferrer"&gt;&lt;code&gt;scripts/skindesigner/common/src/main/resources/devices.json&lt;/code&gt;&lt;/a&gt; if you want to file a PR with a device we are missing or a row whose details are off.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping up
&lt;/h2&gt;

&lt;p&gt;Two reminders. First, &lt;strong&gt;flip &lt;code&gt;ios.metal=true&lt;/code&gt; on your real app this week&lt;/strong&gt; if you have not. The default flip is days away and we would rather find any remaining edge case against your screens than against the install base on launch day. Second, if you have not generated a project from the &lt;a href="https://www.codenameone.com/initializr/" rel="noopener noreferrer"&gt;Initializr&lt;/a&gt; recently, do it; the Java 17 default and the &lt;code&gt;AGENTS.md&lt;/code&gt; skill are both worth seeing for yourself.&lt;/p&gt;

&lt;p&gt;A specific thank-you this week to the reporter on &lt;a href="https://github.com/codenameone/CodenameOne/issues/3302" rel="noopener noreferrer"&gt;#3302&lt;/a&gt; for sticking with the inscribed-triangle bug for as long as GL was the only target, &lt;strong&gt;Durank&lt;/strong&gt; for the iOS push permission report on &lt;a href="https://github.com/codenameone/CodenameOne/issues/4876" rel="noopener noreferrer"&gt;#4876&lt;/a&gt;, and the reporter on &lt;a href="https://github.com/codenameone/CodenameOne/issues/4878" rel="noopener noreferrer"&gt;#4878&lt;/a&gt; who flagged the missing &lt;code&gt;String.replace(CharSequence, CharSequence)&lt;/code&gt;; that one had been sitting in the gap for a long time.&lt;/p&gt;

&lt;p&gt;Issue tracker is &lt;a href="https://github.com/codenameone/CodenameOne/issues" rel="noopener noreferrer"&gt;here&lt;/a&gt;, the &lt;a href="https://www.codenameone.com/playground" rel="noopener noreferrer"&gt;Playground&lt;/a&gt; and &lt;a href="https://www.codenameone.com/initializr/" rel="noopener noreferrer"&gt;Initializr&lt;/a&gt; are the easiest places to poke at the new defaults, and the &lt;a href="https://www.codenameone.com/skindesigner/" rel="noopener noreferrer"&gt;Skin Designer&lt;/a&gt; from last week is still there if you have a device shape you need a skin for.&lt;/p&gt;

</description>
      <category>java</category>
      <category>mobile</category>
      <category>android</category>
      <category>ios</category>
    </item>
    <item>
      <title>Metal and Skins</title>
      <dc:creator>Shai Almog</dc:creator>
      <pubDate>Fri, 15 May 2026 13:34:26 +0000</pubDate>
      <link>https://dev.to/codenameone/metal-and-skins-4e00</link>
      <guid>https://dev.to/codenameone/metal-and-skins-4e00</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9bvkgonfd5n5oujabdri.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9bvkgonfd5n5oujabdri.jpg" alt="Metal and Skins" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This post has a lot to cover. Before we get to any of it I want to take on the uncomfortable subject first: quality. Two incidents from the past two weeks deserve a public explanation, one was a bug that fits into our normal iteration loop and one was a serious mistake on my part. Both deserve the kind of explanation I would want if I were on the other side of the import.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What is Codename One?&lt;/strong&gt; 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 &lt;a href="https://www.codenameone.com/" rel="noopener noreferrer"&gt;codenameone.com&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  How we think about quality
&lt;/h2&gt;

&lt;p&gt;Codename One is a small open source company. We are not a 200-engineer platform team with a dedicated SRE rotation and a separate QA org. We move fast, fast enough that we ship meaningful new code every week, and we put a lot of effort into making sure that speed does not come at the cost of breaking your apps.&lt;/p&gt;

&lt;p&gt;"A lot of effort" is doing some work in that sentence, so here is what it actually looks like:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Layer&lt;/th&gt;
&lt;th&gt;Coverage&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Unit and integration tests&lt;/td&gt;
&lt;td&gt;710 Java test files exercised on every PR.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Screenshot tests&lt;/td&gt;
&lt;td&gt;45 tests producing 190+ golden PNGs that are diffed across the iOS simulator, Android emulator, JavaSE, and headless Chrome. Both the OpenGL and Metal backends are diffed in parallel.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ParparVM bytecode-translation suite&lt;/td&gt;
&lt;td&gt;A separate, deeper test pass that exercises VM functionality (bytecode translation, garbage collector, native interop) beyond what the framework-level tests can reach.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cross-platform build matrix&lt;/td&gt;
&lt;td&gt;24 GitHub workflows build every PR against iOS, Android, JavaSE, and JavaScript.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;JDK matrix&lt;/td&gt;
&lt;td&gt;JDK 8 build, JDK 11 through 25 runtime.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;That is a meaningful amount of automated coverage and it catches a lot before code ever lands. What it does not catch is brand new behaviour, because there is nothing yet to compare a brand new feature against. The first golden of a new test is also the bug, until somebody actually runs the feature and tells us so.&lt;/p&gt;

&lt;p&gt;With that in mind, let's talk about the two specific incidents from the past two weeks.&lt;/p&gt;

&lt;h3&gt;
  
  
  Sticky headers were half baked, and that was by design
&lt;/h3&gt;

&lt;p&gt;Last week's post &lt;a href="https://www.codenameone.com/blog/liquid-glass-material-3-modern-native-themes/#sticky-headers" rel="noopener noreferrer"&gt;introduced &lt;code&gt;StickyHeaderContainer&lt;/code&gt;&lt;/a&gt; with an animated transition between section headers. Within a couple of days the issue tracker had &lt;a href="https://github.com/codenameone/CodenameOne/issues/4849" rel="noopener noreferrer"&gt;#4849&lt;/a&gt;, the &lt;code&gt;NONE&lt;/code&gt; and &lt;code&gt;FADE&lt;/code&gt; transitions were not behaving correctly and the swap had visible jitter. We turned the fix around within hours of the report.&lt;/p&gt;

&lt;p&gt;That round trip, ship, hear from a real user, fix, is the deal we make with the community. Our pixel-diff harness is excellent at catching regressions in code that already exists. It is structurally bad at catching the first version of a brand new component because there is nothing yet to compare against. We could have sat on &lt;code&gt;StickyHeaderContainer&lt;/code&gt; for another two weeks polishing it in private and we would have shipped a worse component, because we would not have had Thomas's eyes on it. Iterating in public, with a tight feedback loop, is how a team our size keeps moving.&lt;/p&gt;

&lt;h3&gt;
  
  
  The SIMD bug, which was my mistake
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/codenameone/CodenameOne/pull/4842" rel="noopener noreferrer"&gt;PR #4842&lt;/a&gt; is a different story. The SIMD code on iOS uses &lt;code&gt;alloca&lt;/code&gt; to put working buffers on the stack for speed. That is the right call for small buffers and the wrong call for large ones, past a certain size the stack request fails outright and the process crashes. The image API uses these buffers, and on large images the buffer crossed the threshold. Result: image API crash in production.&lt;/p&gt;

&lt;p&gt;This was not a new feature. It was a change to existing, mature code. We took the precautions we always take when changing code with a long history, ran the existing tests, every existing test passed, and the patch shipped. The bug got through anyway because the test coverage validated the SIMD path on small images and never on the large ones that actually triggered the failure. That hole in the tests was mine to spot, and I did not spot it.&lt;/p&gt;

&lt;p&gt;Once it was reported the fix turned around in well under 24 hours. The patched version detects the over-large case and falls back to a heap allocation. Small SIMD ops keep the fast &lt;code&gt;alloca&lt;/code&gt; path. Large ones no longer crash. New tests cover the threshold case so this specific shape of bug cannot regress.&lt;/p&gt;

&lt;p&gt;This should not have happened, but realistically it will happen again, not this exact bug, but one like it. Tests are not perfect, mine certainly are not. So the take home is the part I want to lean on:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Codename One is the first line of defense between bugs and your end users. We are not the last line.&lt;/strong&gt; Test your application before you release. If your app supports it, use a beta channel (TestFlight on iOS, Play Console internal or closed tracks on Android) so a bug like this hits &lt;em&gt;you&lt;/em&gt; before it hits the people who paid for your app. That tiny extra step is the most reliable protection your users have.&lt;/p&gt;

&lt;p&gt;We are also actively brainstorming the next generation of crash protection inside the framework. The current crash protection sits at the EDT and catches &lt;code&gt;RuntimeException&lt;/code&gt;s that user code throws. The next generation needs to extend further, into native crashes, into earlier startup, and into a more useful diagnostic payload that comes back to the developer instead of just the device log. There is no PR yet, we are still working out the shape, but it is the major framework-level investment we are making to give the community a stronger floor underneath their apps.&lt;/p&gt;

&lt;p&gt;With the quality conversation out of the way, the rest of this post is about the things that actually shipped.&lt;/p&gt;

&lt;h2&gt;
  
  
  Metal is here
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/codenameone/CodenameOne/pull/4799" rel="noopener noreferrer"&gt;PR #4799&lt;/a&gt; is the largest single change we have landed in months: a complete Metal rendering backend for iOS. It sits next to the existing OpenGL ES 2 path, behind a single build hint, with its own CI job and its own pixel-diff goldens.&lt;/p&gt;

&lt;p&gt;Metal is Apple's modern graphics API. OpenGL on iOS was deprecated by Apple back in iOS 12, it still runs today and we kept it running for years, but "deprecated" on Apple is a slow countdown that ends with the platform pulling support. Moving to Metal now is how we get ahead of that, and it brings real benefits to your apps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Better rendering performance.&lt;/strong&gt; Lower draw-call overhead, modern command-encoder batching, and pipeline state caching add up to smoother scrolling and faster transitions on the same hardware.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Less battery use.&lt;/strong&gt; Metal's reduced CPU overhead per frame means the GPU spends less time idling and the CPU spends less time bookkeeping. Long-running, graphics-heavy apps benefit the most.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Crisper text.&lt;/strong&gt; Glyphs go through a CoreText atlas, which produces noticeably sharper rendering at the same size, with proper kerning and correct handling of complex scripts.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pure-GPU gradients.&lt;/strong&gt; Linear and radial gradients render entirely on the GPU instead of round-tripping through a &lt;code&gt;CGContext&lt;/code&gt; bitmap.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Access to modern Apple graphics features.&lt;/strong&gt; New iOS rendering features (variable-rate shading, mesh shaders, ray tracing on Apple silicon) are Metal-only. Sticking with GL means watching that train leave without us.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To enable Metal in your project, set the build hint:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ios.metal=true
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Everything else stays the same. The Java surface is unchanged, your existing code keeps working.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;We plan to flip Metal to be the default within two weeks&lt;/strong&gt;, assuming no major issues surface. The &lt;code&gt;ios.metal&lt;/code&gt; hint will stay around (set it to &lt;code&gt;false&lt;/code&gt; to opt back into GL), but new projects and the build server's default behaviour will move over. If you ship an iOS app, please set the hint &lt;em&gt;now&lt;/em&gt; and put your real flows through it. We want regressions to surface against your real screens, not the day after the default changes.&lt;/p&gt;

&lt;p&gt;The most user-visible improvement from the Metal port is text. Here is the &lt;code&gt;ShowcaseTheme&lt;/code&gt; capture from the Metal screenshot suite:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc63mfdwvw9xealmsokkt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc63mfdwvw9xealmsokkt.png" alt="Metal showcase, light" width="800" height="1734"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftlw9fhtcs0hd15zk8xr6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftlw9fhtcs0hd15zk8xr6.png" alt="Metal showcase, dark" width="800" height="1734"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And the &lt;code&gt;SpanLabelTheme&lt;/code&gt; capture, which is the real test for body-copy rendering, multiple lines, variable widths, the kind of paragraphs that show up in real apps:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F63i96phw1eiw1qgsk48g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F63i96phw1eiw1qgsk48g.png" alt="Metal SpanLabel theme" width="800" height="1734"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The Metal &lt;code&gt;Dialog&lt;/code&gt; capture is also worth showing because the translucent surface composites correctly against the textured backdrop:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnuza18zrvrrfwbcelf22.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnuza18zrvrrfwbcelf22.png" alt="Metal Dialog over textured backdrop" width="800" height="1734"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The end of the skin downloader
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/codenameone/CodenameOne/pull/4758" rel="noopener noreferrer"&gt;PR #4758&lt;/a&gt; ships the Skin Designer as a JavaScript bundle, embedded into the website at &lt;a href="https://www.codenameone.com/skindesigner/" rel="noopener noreferrer"&gt;/skindesigner/&lt;/a&gt; the same way the Playground and Initializr are embedded. You can build a skin in the browser, save it, and use it in your simulator without installing anything.&lt;/p&gt;

&lt;p&gt;This is bigger than a website convenience. It is how we get out of the skin business.&lt;/p&gt;

&lt;p&gt;For the entire history of Codename One, "no skin for the iPhone 16 Pro Max" or "no skin for the iPad mini 7" has been a recurring complaint, and we have published skins as fast as we could. That model never scaled. Apple ships new device sizes faster than any of us want to maintain a parallel skin catalogue, and Android has effectively infinite device shapes. Today we are deprecating the skin downloader and moving to a generic browser-based authoring tool.&lt;/p&gt;

&lt;p&gt;To be clear about what is changing:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Existing skins are not going anywhere.&lt;/strong&gt; Every skin that ships today will continue to work, will continue to load in the simulator, and will continue to be supported. We are not removing them. If your team has a workflow built around an existing skin, that workflow keeps working.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;We will stop issuing new skins.&lt;/strong&gt; When the next iPhone or iPad ships, we will not publish an official skin for it. Anyone can build one in the new designer in minutes, and that "anyone" includes us, of course, but it also includes you.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The "no skin for X" problem is solved generically. If you are running a niche enterprise app on a less-common Android device, you no longer have to wait on us to produce a skin for it. Build it once, drop it into your team's shared assets, done.&lt;/p&gt;

&lt;h3&gt;
  
  
  How the wizard works
&lt;/h3&gt;

&lt;p&gt;The Skin Designer turns a device specification (resolution, PPI, fonts, safe-area insets, cutouts) into a &lt;code&gt;.skin&lt;/code&gt; file that the JavaSE simulator can load. It runs in your browser. There is nothing to install. The wizard is intentionally opinionated. It ships with a curated device catalog, generates the device frame procedurally, and writes a skin layout that matches the &lt;code&gt;iPhoneTheme.res&lt;/code&gt;, &lt;code&gt;iOS7Theme.res&lt;/code&gt;, and &lt;code&gt;android_holo_light.res&lt;/code&gt; themes shipped with Codename One.&lt;/p&gt;

&lt;p&gt;If you only want a skin and don't care how it is built, pick a device, accept the defaults, click &lt;em&gt;Finish&lt;/em&gt;, then &lt;em&gt;Download skin&lt;/em&gt;. The file is ready to load via &lt;em&gt;Add&lt;/em&gt; in the simulator's &lt;em&gt;Skins&lt;/em&gt; menu.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Stage 1, pick a device.&lt;/strong&gt; The first step shows a card per device from the bundled catalog. The search box filters by name (it matches both the model and the brand) and the chips below narrow by form factor: All / Phones / Tablets / Foldables. Picking a device pulls in its resolution, PPI, screen size, default safe-area insets, and the iOS or Android system font names from the catalog, then seeds a sensible starting frame: notch, island, or hole presets are applied automatically based on the device's hardware. The catalog is large, the grid is capped to the most recent matches by default, type into the search field to find older or less-common devices.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F93x60cah67xty0j927aw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F93x60cah67xty0j927aw.png" alt="Skin Designer stage 1, device picker" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Stage 2, pick a starting source.&lt;/strong&gt; There are three ways to seed the skin's body image:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;Pick a shape&lt;/em&gt; generates the device frame procedurally from a small preset library (rounded rect, notch, dynamic island, punch-hole, corner hole, classic home-button). The frame is rendered as a dark gradient with the screen rect (and any cutouts) carved into it. Best when you want a generic-looking iPhone or Android frame and don't care about exact hardware fidelity.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Upload an image&lt;/em&gt; opens an image picker. The wizard scales the image into the device's resolution, then carves the screen rect and cutouts on top. Use this when you have a marketing render of the specific device you are targeting.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Blank rectangle&lt;/em&gt; collapses the bezel and corner radius to almost nothing, drops every cutout, and turns the home indicator off. The screen fills the entire skin. Useful for desktop or web simulators where the device frame would just be visual noise.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fid99a104njb1nsmu2jfk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fid99a104njb1nsmu2jfk.png" alt="Skin Designer stage 2, source picker" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Stage 3, the editor.&lt;/strong&gt; The editor is split into two panes: a live preview on the left that paints the device frame, screen tint, cutouts, and home indicator, and a sidebar on the right with three tabs.&lt;/p&gt;

&lt;p&gt;The &lt;em&gt;Shape&lt;/em&gt; tab shows a preset grid (Rounded rect, Notch, Dynamic Island, Punch-hole, Corner hole, Classic home) and dimension fields for corner radius, bezel thickness, and a toggle for the bottom home indicator. iPhones from X onward and most modern Androids should leave the indicator on, classic devices with a hardware home button should turn it off.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnz4ozo3bqbtv8h98e29e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnz4ozo3bqbtv8h98e29e.png" alt="Skin Designer stage 3, Shape tab" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The &lt;em&gt;Cutouts&lt;/em&gt; tab lists every cutout currently on the skin. Tap a row to expand its width, height, and offset fields. The three add buttons at the bottom seed a sensible default of each type. &lt;em&gt;Notch&lt;/em&gt; (180 x 30 viewbox px) is a physical hardware cutout drawn in the device frame above the screen rect, mirroring iPhone X / 11 / 12 / 13 hardware. &lt;em&gt;Island&lt;/em&gt; (120 x 35) is a Dynamic Island, software-reserved space rendered as an opaque pill inside the screen rect, floating on top of the iOS status bar. &lt;em&gt;Hole&lt;/em&gt; (28 x 28) is an Android punch-hole camera, rendered like the island. When the wizard generates the &lt;code&gt;.skin&lt;/code&gt;, it automatically extends &lt;code&gt;safePortraitTop&lt;/code&gt; to cover any in-screen cutouts so app content lands below the floating shape.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9u2206c03eehtz7ghteo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9u2206c03eehtz7ghteo.png" alt="Skin Designer stage 3, Cutouts tab" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The &lt;em&gt;Info&lt;/em&gt; tab is mostly read-only and shows what is about to be written into &lt;code&gt;skin.properties&lt;/code&gt;: name, width, height, PPI, pixels-per-millimeter, and the user-editable safe-area insets. The wizard intentionally does &lt;em&gt;not&lt;/em&gt; write &lt;code&gt;smallFontSize&lt;/code&gt;, &lt;code&gt;mediumFontSize&lt;/code&gt;, or &lt;code&gt;largeFontSize&lt;/code&gt;, when those are absent the simulator auto-derives them from &lt;code&gt;pixelMilliRatio&lt;/code&gt;, which is what you want on high-PPI screens.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5h7ie4be2sxemw7qkwqk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5h7ie4be2sxemw7qkwqk.png" alt="Skin Designer stage 3, Info tab" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Stage 4, finish and download.&lt;/strong&gt; Clicking &lt;em&gt;Finish&lt;/em&gt; renders the portrait skin image at the device's actual resolution with rounded corners, transparent screen, opaque cutouts, and a home indicator if enabled. It synthesises the landscape skin by 90-degree rotation, writes the &lt;code&gt;skin_map.png&lt;/code&gt; overlays that mark the screen rectangle for the simulator's screen-position detection, bundles the appropriate native theme inside the skin zip, and writes &lt;code&gt;skin.properties&lt;/code&gt; with the platform metadata, safe-area, PPI, and display rect. Clicking &lt;em&gt;Download skin&lt;/em&gt; hands the file to the browser's download dialog. After the file is on disk, drop it into your simulator's skins folder (or use the &lt;em&gt;Add&lt;/em&gt; command in the simulator's &lt;em&gt;Skins&lt;/em&gt; menu) and your new device should appear in the picker.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvxyw9bqdcuogvhr6m930.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvxyw9bqdcuogvhr6m930.png" alt="Skin Designer stage 4, finish and download" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A generated &lt;code&gt;.skin&lt;/code&gt; is just a renamed zip:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Apple-iPhone-16-Pro.skin/
  skin.png            # portrait body (device frame + transparent screen + cutouts)
  skin_l.png          # 90-degree rotated portrait
  skin_map.png        # black rect = screen, white = frame, used for hit-testing
  skin_map_l.png      # rotated map
  iOS7Theme.res       # bundled native theme (or android_holo_light.res / winTheme.res)
  skin.properties     # platform metadata, safe-area, PPI, display rect
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The full developer-guide chapter at &lt;a href="https://github.com/codenameone/CodenameOne/blob/master/docs/developer-guide/Skin-Designer.asciidoc" rel="noopener noreferrer"&gt;Skin-Designer.asciidoc&lt;/a&gt; walks through every stage with annotated screenshots and documents the &lt;code&gt;skin.properties&lt;/code&gt; keys the wizard writes (&lt;code&gt;roundScreen&lt;/code&gt;, &lt;code&gt;displayX/Y/Width/Height&lt;/code&gt;, &lt;code&gt;safePortrait*&lt;/code&gt;, &lt;code&gt;safeLandscape*&lt;/code&gt;, &lt;code&gt;overrideNames&lt;/code&gt;, system font families, PPI, and pixel ratio).&lt;/p&gt;

&lt;h3&gt;
  
  
  Eating our own dog food
&lt;/h3&gt;

&lt;p&gt;While we're talking about the Skin Designer, this is the right moment to point out something I think is genuinely worth highlighting. The &lt;a href="https://www.codenameone.com/initializr/" rel="noopener noreferrer"&gt;Initializr&lt;/a&gt;, the &lt;a href="https://www.codenameone.com/playground/" rel="noopener noreferrer"&gt;Playground&lt;/a&gt;, and the &lt;a href="https://www.codenameone.com/skindesigner/" rel="noopener noreferrer"&gt;Skin Designer&lt;/a&gt; are all open source Codename One apps. They are written in Java using the same Codename One UI framework you use to build your iOS and Android apps, and they are deployed to the browser through our JavaScript port.&lt;/p&gt;

&lt;p&gt;Every interaction you have with these tools, the device picker grid, the live preview rendering the device frame and cutouts, the form-driven editor with its tabbed sidebar, the file generation that bundles a &lt;code&gt;.skin&lt;/code&gt; zip in your browser tab, is the same Codename One code that ships in your apps. The &lt;code&gt;Container&lt;/code&gt;, &lt;code&gt;Form&lt;/code&gt;, &lt;code&gt;BoxLayout&lt;/code&gt;, theming, and event-handling code is identical to what you would write for a phone build. The JavaScript port translates it into something a browser can run.&lt;/p&gt;

&lt;p&gt;These three tools are the most direct demonstration we can give of what Codename One is capable of: real, non-trivial UIs, with state, file I/O, image generation, and complex layouts, running smoothly inside a browser tab. If you have ever wondered whether the JavaScript port is production-grade enough for a real application, the Initializr, Playground, and Skin Designer are your answer. They are also the answer to "can Codename One build apps that go beyond mobile". Same codebase, deployed to a fourth target, with no rewrite.&lt;/p&gt;

&lt;p&gt;The source for all three lives in the same &lt;a href="https://github.com/codenameone/CodenameOne" rel="noopener noreferrer"&gt;CodenameOne&lt;/a&gt; repository the framework itself does. If you want to see how a non-trivial Codename One app is structured, those are three good places to start reading.&lt;/p&gt;

&lt;h2&gt;
  
  
  iOS multi-line TextArea: Return as Done
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/codenameone/CodenameOne/pull/4859" rel="noopener noreferrer"&gt;PR #4859&lt;/a&gt;, driven by issue &lt;a href="https://github.com/codenameone/CodenameOne/issues/4854" rel="noopener noreferrer"&gt;#4854&lt;/a&gt;, gives multi-line &lt;code&gt;TextArea&lt;/code&gt; an opt-in flag that makes the iOS keyboard's Return key act as Done. It closes the editor and fires the Done listener instead of inserting a newline. This is the iOS Reminders-app behaviour: a growing, multi-line task-title field where Return finishes the entry.&lt;/p&gt;

&lt;p&gt;The reason it has to be a flag is that real iOS does not expose this as a built-in primitive. Reminders implements it on a &lt;code&gt;UITextView&lt;/code&gt; whose delegate intercepts &lt;code&gt;\n&lt;/code&gt; in &lt;code&gt;shouldChangeTextInRange:&lt;/code&gt;. We replicate that exactly, gated behind a client property so existing layouts are untouched:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;TextArea&lt;/span&gt; &lt;span class="n"&gt;ta&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;TextArea&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;ta&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;putClientProperty&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"iosReturnExitsEditing"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Boolean&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;TRUE&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;ta&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setDoneListener&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="cm"&gt;/* Return / Done was tapped */&lt;/span&gt; &lt;span class="o"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;While the flag is set, the keyboard's Return key is relabelled to &lt;strong&gt;Done&lt;/strong&gt; (&lt;code&gt;UIReturnKeyDone&lt;/code&gt;). Default behaviour is unchanged: the flag defaults to off, only takes effect on multi-line &lt;code&gt;TextArea&lt;/code&gt;s, and only intercepts an exact &lt;code&gt;"\n"&lt;/code&gt; replacement so pasted multi-line text is unaffected.&lt;/p&gt;

&lt;h2&gt;
  
  
  Diagnostics for status-bar tap scroll-to-top
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/codenameone/CodenameOne/pull/4868" rel="noopener noreferrer"&gt;PR #4868&lt;/a&gt;, driven by issue &lt;a href="https://github.com/codenameone/CodenameOne/issues/3589" rel="noopener noreferrer"&gt;#3589&lt;/a&gt;, adds three complementary diagnostics for the iOS status-bar tap path. We shipped a fix earlier (&lt;a href="https://github.com/codenameone/CodenameOne/pull/4857" rel="noopener noreferrer"&gt;#4857&lt;/a&gt;) and the reporter still saw no scroll on device. Rather than another sweep in the dark, we built tools to make the path observable.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Simulator menu, &lt;code&gt;Simulate &amp;gt; iOS Status Bar Tap&lt;/code&gt;.&lt;/strong&gt; Synthesises the same &lt;code&gt;(displayWidth/2, 0)&lt;/code&gt; tap that &lt;code&gt;scrollViewShouldScrollToTop:&lt;/code&gt; dispatches, pops a dialog reporting the responder UIID, the build-hint state, and an OK / PROBLEM verdict, then actually fires &lt;code&gt;pointerPressed&lt;/code&gt; and &lt;code&gt;pointerReleased&lt;/code&gt; so any wired-up scroll-to-top is observable.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Device-side properties.&lt;/strong&gt; &lt;code&gt;Display.getProperty("cn1.iosStatusBarTap.count")&lt;/code&gt;, &lt;code&gt;cn1.iosStatusBarTap.lastEpochMillis&lt;/code&gt;, &lt;code&gt;cn1.iosStatusBarTap.lastX/Y&lt;/code&gt;, and &lt;code&gt;cn1.iosStatusBarTap.proxyInstalled&lt;/code&gt; let you inspect the path on a real iPhone. Run your app on the device, tap the status bar, and read the property. That distinguishes "iOS never delivered the message" from "iOS delivered it but a CodenameOne component intercepted the tap".&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Regression coverage.&lt;/strong&gt; &lt;code&gt;StatusBarTapDiagnosticScreenshotTest&lt;/code&gt; exercises the exact same code path through a 2x3 frame grid, with the visible counter rising and the scroll position alternating, so future regressions surface in CI.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Simulator: Dark / Light mode toggle
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/codenameone/CodenameOne/pull/4871" rel="noopener noreferrer"&gt;PR #4871&lt;/a&gt; adds a &lt;strong&gt;Dark / Light Mode&lt;/strong&gt; submenu under the simulator's &lt;strong&gt;Simulate&lt;/strong&gt; menu with three options: Dark Mode, Light Mode, and Unsupported (the default).&lt;/p&gt;

&lt;p&gt;Selecting an option flips &lt;code&gt;Display.isDarkMode()&lt;/code&gt; (&lt;code&gt;Boolean.TRUE&lt;/code&gt; / &lt;code&gt;Boolean.FALSE&lt;/code&gt; / &lt;code&gt;null&lt;/code&gt;) and calls &lt;code&gt;refreshSkin(...)&lt;/code&gt; so themes that branch on &lt;code&gt;@darkModeBool&lt;/code&gt; re-render immediately. The choice is persisted under the &lt;code&gt;cn1.simulator.darkMode&lt;/code&gt; Preference so the simulator restarts in the mode you left it.&lt;/p&gt;

&lt;p&gt;Combined with the &lt;strong&gt;Native Theme&lt;/strong&gt; menu we shipped two weeks ago, you can now sit on a single skin and flip between iOS Modern, Material 3, iOS 7, and Holo Light, in light, dark, and unsupported, in seconds. The everyday win is being able to verify your own theme looks right in dark mode without restarting the simulator.&lt;/p&gt;

&lt;h2&gt;
  
  
  Heads-up: weekend backend maintenance
&lt;/h2&gt;

&lt;p&gt;This weekend we will be doing some maintenance on our build backend servers. The work is mostly invisible from the outside but it touches enough of the infrastructure that you might see intermittent build issues during the window: slower-than-usual builds, the occasional retry, possibly a short period where new builds are queued.&lt;/p&gt;

&lt;p&gt;We are doing it because the underlying backend needs to move forward, and the cost of putting that work off keeps compounding. We will keep the disruption as short as we can. If you have a hard release deadline that lands this weekend, please plan around it. Otherwise the impact should be small and you can build through it normally.&lt;/p&gt;

&lt;h2&gt;
  
  
  Warning: Android 16 will effectively disallow locking orientation
&lt;/h2&gt;

&lt;p&gt;Thanks to &lt;strong&gt;Durank&lt;/strong&gt; for flagging &lt;a href="https://github.com/codenameone/CodenameOne/issues/4879" rel="noopener noreferrer"&gt;#4879&lt;/a&gt;. The &lt;a href="https://developer.android.com/about/versions/16/behavior-changes-16" rel="noopener noreferrer"&gt;Android 16 behavior changes&lt;/a&gt; include a meaningful change to how Android handles orientation, in short, on large-screen devices the platform will ignore an app's request to lock orientation. If your app calls &lt;code&gt;Display.lockOrientation(...)&lt;/code&gt; or sets a fixed orientation in the Android manifest, that lock will be honoured on phones but effectively ignored on tablets and foldables once the device targets Android 16.&lt;/p&gt;

&lt;p&gt;There is not much we can do about this on the framework side. It is a platform-level decision and there is no public opt-out for general apps. The realistic path forward is to design layouts that work in both orientations, and to test your app against both portrait and landscape on a tablet before Android 16 reaches your users. We will keep watching for any opt-in path Google publishes, but for the moment please plan accordingly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why the version jumped to 7.0.242
&lt;/h2&gt;

&lt;p&gt;A small note on versioning: the current release is &lt;strong&gt;7.0.242&lt;/strong&gt;, not 7.0.238 as you might expect from the cadence. The gap is real and worth explaining. We made a fix to the Maven archetype that brings over the features we added in the Codename One Initializr to projects created from the command line. The change itself is straightforward, but it interacted badly with our release build automation and we had to delete several releases along the way to get the pipeline back on its feet. The version numbers we burned in the process are the visible scar. The bright side is that command-line &lt;code&gt;mvn archetype:generate&lt;/code&gt; now produces projects that line up with what the Initializr generates, which is what we wanted all along.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping up
&lt;/h2&gt;

&lt;p&gt;We closed &lt;strong&gt;24 issues&lt;/strong&gt; in the past week, a meaningful share of them direct beneficiaries of the Metal port. Old GL-only rasterisation diffs, font sizing on retina, polygon drawing artefacts, perspective transform issues, things that the Metal pipeline simply renders correctly out of the box. Migrating the rendering layer turned out to be the cleanest way to retire a long tail of small bugs at once. With the new Skin Designer landing in the same week, two long-running structural problems went from "we should fix this someday" to "this is fixed and shipping".&lt;/p&gt;

&lt;p&gt;If you ship an iOS app, please flip &lt;code&gt;ios.metal=true&lt;/code&gt; this week and run your real app through it. We want to find any remaining issues now, not the day we flip the default. Issue tracker is &lt;a href="https://github.com/codenameone/CodenameOne/issues" rel="noopener noreferrer"&gt;here&lt;/a&gt;, the &lt;a href="https://www.codenameone.com/playground" rel="noopener noreferrer"&gt;Playground&lt;/a&gt; is the easiest place to poke at the new themes, the &lt;a href="https://www.codenameone.com/skindesigner/" rel="noopener noreferrer"&gt;Skin Designer&lt;/a&gt; is live on the site.&lt;/p&gt;

&lt;p&gt;A specific thank-you this week to &lt;strong&gt;Thomas (@ThomasH99)&lt;/strong&gt; for the sticky-header transition report and the Picker centring follow-up, &lt;strong&gt;Francesco Galgani (@jsfan3)&lt;/strong&gt; for the iOS Reminders-style Return RFE, and the reporter on &lt;a href="https://github.com/codenameone/CodenameOne/issues/3589" rel="noopener noreferrer"&gt;#3589&lt;/a&gt; for sticking with us through a multi-PR diagnosis on the status-bar tap. The "tests cannot catch everything" section above is also a "and that is why we need you" section. It works because you keep filing.&lt;/p&gt;

</description>
      <category>java</category>
      <category>mobile</category>
      <category>android</category>
      <category>ios</category>
    </item>
    <item>
      <title>Liquid Glass, Material 3, And A Lot Of Plumbing</title>
      <dc:creator>Shai Almog</dc:creator>
      <pubDate>Wed, 06 May 2026 13:08:18 +0000</pubDate>
      <link>https://dev.to/codenameone/liquid-glass-material-3-and-a-lot-of-plumbing-2jkk</link>
      <guid>https://dev.to/codenameone/liquid-glass-material-3-and-a-lot-of-plumbing-2jkk</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F10fvsqx7t0j76921s1vn.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F10fvsqx7t0j76921s1vn.jpg" alt="Header Image" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It has been one of those weeks where the diff is bigger than the headline. The headline is short — Codename One now ships modern native themes: an iOS "liquid glass" look and an Android Material 3 look, bundled into the iOS and Android ports, on by default in the Playground, and selectable from a brand new menu in the simulator. The diff behind that headline is several thousand lines across the platform ports, the simulator, the GUI plumbing, and a small army of screenshot tests.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What is Codename One?&lt;/strong&gt; 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 &lt;a href="https://www.codenameone.com/" rel="noopener noreferrer"&gt;codenameone.com&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The theme behind the work is simple: Codename One should look modern out of the box on every platform we ship to, and it should feel fast. Almost everything in the past week of commits is in service of one of those two goals.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it right now in the Playground
&lt;/h2&gt;

&lt;p&gt;The easiest way to see any of this is the &lt;a href="https://www.codenameone.com/playground" rel="noopener noreferrer"&gt;Playground&lt;/a&gt;. The Playground now defaults to iOS Modern when the device toggle is set to iPhone and Android Material 3 when it is set to Android, in both light and dark mode. No setup, no &lt;code&gt;pom.xml&lt;/code&gt;, no build hints — just open the page, drop in any of the standard components, and the modern look is what you get. If the past releases of Codename One looked dated to you, the Playground is where to start.&lt;/p&gt;

&lt;p&gt;The simulator is the second-easiest place. We will get to that.&lt;/p&gt;

&lt;h2&gt;
  
  
  The new native themes
&lt;/h2&gt;

&lt;p&gt;For most of Codename One's life the iOS native theme has been the venerable iOS 7 flat theme, and the Android native theme has been Holo Light. Both still ship — backwards compatibility has always been one of our most important goals — but they are no longer where we want a brand new app to start. We spent the bulk of this week building two new themes that target current platform aesthetics:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;iOS Modern&lt;/strong&gt; — Apple system colors (accent &lt;code&gt;#007aff&lt;/code&gt; light / &lt;code&gt;#0a84ff&lt;/code&gt; dark, grouped-form surfaces, the system separator palette), pill borders for tabs, an iOS-Settings-style &lt;code&gt;MultiButton&lt;/code&gt;, &lt;code&gt;CHECK_CIRCLE&lt;/code&gt;-style checkbox glyphs, and translucent surfaces for &lt;code&gt;Dialog&lt;/code&gt; and &lt;code&gt;TabsContainer&lt;/code&gt; so they read as glass-frosted on top of whatever is behind them. It is not a real &lt;code&gt;UIVisualEffectView&lt;/code&gt; backdrop — that is a port-side primitive we have not built yet — but the look is much closer to the iOS 26 vibe than anything we have shipped before.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Android Material 3&lt;/strong&gt; — the Material 3 baseline tonal palette (primary &lt;code&gt;#6750a4&lt;/code&gt; light / &lt;code&gt;#d0bcff&lt;/code&gt; dark, surface-container tiers, elevated containers approximated tonally because real elevation drop-shadows are still on the to-do list), plus all the Material density and padding choices — Roboto-ish proportions, a top-tab bar with the underline-by-color treatment, the standard square checkbox glyph.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each theme covers the usual ~25 UIIDs: base (&lt;code&gt;Component&lt;/code&gt;, &lt;code&gt;Form&lt;/code&gt;, &lt;code&gt;ContentPane&lt;/code&gt;, &lt;code&gt;Container&lt;/code&gt;), typography (&lt;code&gt;Label&lt;/code&gt;, &lt;code&gt;SecondaryLabel&lt;/code&gt;, &lt;code&gt;TertiaryLabel&lt;/code&gt;, &lt;code&gt;SpanLabel*&lt;/code&gt;), buttons (&lt;code&gt;Button&lt;/code&gt;, &lt;code&gt;RaisedButton&lt;/code&gt;, &lt;code&gt;FlatButton&lt;/code&gt; with &lt;code&gt;.pressed&lt;/code&gt; and &lt;code&gt;.disabled&lt;/code&gt;), text input, selection controls, toolbar, tabs, side menu, list, &lt;code&gt;MultiButton&lt;/code&gt;, dialog/sheet, FAB, and all the supporting separator and popup pieces. Both themes have full light and dark coverage.&lt;/p&gt;

&lt;p&gt;The shipping CSS sources sit in the repo at &lt;a href="https://github.com/codenameone/CodenameOne/blob/master/native-themes/ios-modern/theme.css" rel="noopener noreferrer"&gt;native-themes/ios-modern/theme.css&lt;/a&gt; and &lt;a href="https://github.com/codenameone/CodenameOne/blob/master/native-themes/android-material/theme.css" rel="noopener noreferrer"&gt;native-themes/android-material/theme.css&lt;/a&gt; for anyone who wants to read what each UIID is doing.&lt;/p&gt;

&lt;h3&gt;
  
  
  iOS Modern
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjatopnsv3zpr6plxkdbm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjatopnsv3zpr6plxkdbm.png" alt="iOS Modern theme — light and dark" width="800" height="364"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is the &lt;code&gt;ShowcaseTheme&lt;/code&gt; capture from the new screenshot suite, run on iOS in light and dark. Same Form, same components, swap &lt;code&gt;Display.setDarkMode(...)&lt;/code&gt; and re-resolve. The form is built like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;Container&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Container&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;BoxLayout&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;x&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Button&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Default"&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
&lt;span class="nc"&gt;Button&lt;/span&gt; &lt;span class="n"&gt;raised&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Button&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Raised"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;raised&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setUIID&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"RaisedButton"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;raised&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;form&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

&lt;span class="nc"&gt;TextField&lt;/span&gt; &lt;span class="n"&gt;tf&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;TextField&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"hello@example.com"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;form&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tf&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

&lt;span class="nc"&gt;Container&lt;/span&gt; &lt;span class="n"&gt;toggles&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Container&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;BoxLayout&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;x&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
&lt;span class="nc"&gt;CheckBox&lt;/span&gt; &lt;span class="n"&gt;cb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;CheckBox&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Remember me"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;cb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setSelected&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;toggles&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cb&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="nc"&gt;RadioButton&lt;/span&gt; &lt;span class="n"&gt;rb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;RadioButton&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Agree"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;rb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setSelected&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;toggles&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rb&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;form&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;toggles&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

&lt;span class="nc"&gt;SpanLabel&lt;/span&gt; &lt;span class="n"&gt;body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;SpanLabel&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Body copy …"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;form&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That gives you the full picture in one screen:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;Default&lt;/code&gt; button uses the stock &lt;code&gt;Button&lt;/code&gt; UIID. The &lt;code&gt;Raised&lt;/code&gt; button uses &lt;code&gt;RaisedButton&lt;/code&gt;, which &lt;code&gt;cn1-derive&lt;/code&gt;s from &lt;code&gt;Button&lt;/code&gt; and adds a tinted pill on top of the iOS system blue — that is the iOS Modern accent in both modes.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;TextField&lt;/code&gt; is a single rounded-rect surface with the iOS system gray fill, the same shape Apple uses in Settings.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;CheckBox&lt;/code&gt; and &lt;code&gt;RadioButton&lt;/code&gt; use the new optional &lt;code&gt;@checkBoxCheckedIconInt&lt;/code&gt; / &lt;code&gt;@radioCheckedIconInt&lt;/code&gt; theme constants to swap to &lt;code&gt;CHECK_CIRCLE&lt;/code&gt; / &lt;code&gt;CHECK_CIRCLE_OUTLINE&lt;/code&gt; glyphs — Reminders-app aesthetic on iOS while Android keeps the standard square check.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;SpanLabel&lt;/code&gt; body uses the theme's base font and inherits transparent backgrounds so it never paints over a translucent parent.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The full screen source is &lt;a href="https://github.com/codenameone/CodenameOne/blob/master/scripts/hellocodenameone/common/src/main/java/com/codenameone/examples/hellocodenameone/tests/DarkLightShowcaseThemeScreenshotTest.java" rel="noopener noreferrer"&gt;DarkLightShowcaseThemeScreenshotTest.java&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Android Material 3
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8qdktf6n4wjdns2egchd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8qdktf6n4wjdns2egchd.png" alt="Android Material 3 theme — light and dark" width="800" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Same &lt;code&gt;ShowcaseTheme&lt;/code&gt; source on Android. The Material 3 baseline palette gives &lt;code&gt;Default&lt;/code&gt; the primary container color and &lt;code&gt;Raised&lt;/code&gt; the elevated-surface tone, with the dark variant flipping the relationship correctly via the dark color-role mapping. Padding and font sizing follow Material density, which you can see in how compact the same Form lays out compared to iOS.&lt;/p&gt;

&lt;h3&gt;
  
  
  Translucent surfaces
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F18pf508bhtz72x9kjg3y.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F18pf508bhtz72x9kjg3y.png" alt="Dialog over a textured backdrop — light and dark" width="800" height="509"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is the &lt;code&gt;DialogTheme&lt;/code&gt; capture against the screenshot suite's textured diagonal-stripe backdrop. The backdrop is intentional — it lets reviewers see whether anything that is &lt;em&gt;supposed&lt;/em&gt; to be translucent actually is. The iOS Modern &lt;code&gt;Dialog&lt;/code&gt; uses an &lt;code&gt;rgba&lt;/code&gt; surface fill (0.78 alpha in light, 0.95 in dark — dark needs more opacity because bright stripes bleed through) and its &lt;code&gt;DialogBody&lt;/code&gt;, &lt;code&gt;DialogTitle&lt;/code&gt;, &lt;code&gt;ContentPane&lt;/code&gt;, &lt;code&gt;CommandArea&lt;/code&gt; sub-UIIDs are transparent so the rounded corners read cleanly. The same trick is applied to &lt;code&gt;TabsContainer&lt;/code&gt; and the iOS &lt;code&gt;MultiButton&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Runtime palette overrides
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxr95hztht0wvsur3wgx5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxr95hztht0wvsur3wgx5.png" alt="Magenta palette layered over iOS Modern — light and dark" width="800" height="373"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The native theme is meant to be a starting point — you can layer your own palette on top without forking the theme. Above is the &lt;code&gt;PaletteOverrideTheme&lt;/code&gt; capture: the base is iOS Modern, but the test layers a magenta palette on top at runtime via &lt;code&gt;UIManager.addThemeProps(...)&lt;/code&gt;. &lt;code&gt;RaisedButton&lt;/code&gt;, &lt;code&gt;FlatButton&lt;/code&gt;, the disabled tone, and the body-copy span all pick up the override in both light and dark — the override seam works at the resource-bundle layer, exactly the same mechanism a user theme uses to override the native theme on a real app.&lt;/p&gt;

&lt;h2&gt;
  
  
  In the simulator
&lt;/h2&gt;

&lt;p&gt;Three pieces, all live:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Themes are bundled.&lt;/strong&gt; The simulator jar-with-dependencies includes both modern themes alongside the four legacy themes (&lt;code&gt;iPhoneTheme&lt;/code&gt;, &lt;code&gt;iOS7Theme&lt;/code&gt;, &lt;code&gt;androidTheme&lt;/code&gt;, &lt;code&gt;android_holo_light&lt;/code&gt;) at the root of the jar. The simulator can pick any one of them at runtime without touching the skin repo.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A new "Native Theme" menu.&lt;/strong&gt; Right next to the Skins menu there is now a Native Theme menu with a radio group for the six themes plus "Auto" and "Use skin's embedded theme". Selecting one writes the &lt;code&gt;simulatorNativeTheme&lt;/code&gt; Preference, flips the simulator-reload flag, and disposes the current window so the skin reloader kicks in with the new theme. You can sit on a single skin and flip through every native theme in seconds.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Build hints know about it.&lt;/strong&gt; The new &lt;code&gt;nativeTheme&lt;/code&gt;, &lt;code&gt;ios.themeMode&lt;/code&gt;, and &lt;code&gt;and.themeMode&lt;/code&gt; build hints are registered with the simulator's Build Hints UI on launch — labels, types, value lists, descriptions, the lot. (The legacy keys &lt;code&gt;cn1.nativeTheme&lt;/code&gt; and &lt;code&gt;cn1.androidTheme&lt;/code&gt; are still honored for back-compat.) Set them in the Build Hints dialog, in &lt;code&gt;codenameone_settings.properties&lt;/code&gt;, or via &lt;code&gt;-D&lt;/code&gt; system properties; they flow through to the device build and the simulator both.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The "Auto" choice in the Native Theme menu defers to those build hints — set &lt;code&gt;ios.themeMode=modern&lt;/code&gt; in your project's settings and "Auto" previews iOS Modern; flip the same project to &lt;code&gt;ios.themeMode=ios7&lt;/code&gt; and "Auto" previews iOS 7. The explicit menu entries (iOS Modern, iOS 7, etc.) override the hints regardless. &lt;code&gt;-Dcn1.forceSimulatorTheme&lt;/code&gt; is still honored as the highest-priority override; pick "Use skin's embedded theme" to bypass the framework theme entirely and get whatever the skin shipped with.&lt;/p&gt;

&lt;h2&gt;
  
  
  On devices
&lt;/h2&gt;

&lt;p&gt;The opt-in is the same on iOS and Android. The platform knobs follow a single naming pattern — &lt;code&gt;ios.themeMode&lt;/code&gt; and &lt;code&gt;and.themeMode&lt;/code&gt; — and accept &lt;code&gt;modern&lt;/code&gt; / &lt;code&gt;liquid&lt;/code&gt; / &lt;code&gt;auto&lt;/code&gt; / &lt;code&gt;ios7&lt;/code&gt; / &lt;code&gt;flat&lt;/code&gt; on iOS, &lt;code&gt;modern&lt;/code&gt; / &lt;code&gt;material&lt;/code&gt; / &lt;code&gt;auto&lt;/code&gt; / &lt;code&gt;hololight&lt;/code&gt; / &lt;code&gt;legacy&lt;/code&gt; on Android. There is a single cross-platform shortcut, &lt;code&gt;nativeTheme=modern&lt;/code&gt;, which the iOS builder consults when &lt;code&gt;ios.themeMode&lt;/code&gt; is unset and which the Android port reads at runtime as a default for &lt;code&gt;and.themeMode&lt;/code&gt;. The legacy aliases &lt;code&gt;cn1.androidTheme&lt;/code&gt; and &lt;code&gt;cn1.nativeTheme&lt;/code&gt; are still honored for back-compat, as is &lt;code&gt;and.hololight=true&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The default for an existing app stays on legacy on every platform. We do not flip a 15-year-old app's look without an opt-in. New apps generated from the initializr ship with &lt;code&gt;nativeTheme=modern&lt;/code&gt;, &lt;code&gt;ios.themeMode=modern&lt;/code&gt;, and &lt;code&gt;and.themeMode=modern&lt;/code&gt; already set in &lt;code&gt;codenameone_settings.properties&lt;/code&gt;, so a brand new project starts with the modern themes preselected. The Playground does the same, and Playground project downloads carry the same defaults into the generated &lt;code&gt;codenameone_settings.properties&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The HTML5 port has the runtime support for the modern themes but does not bundle them with user apps yet — that is one of the loose ends we want to close in the next round.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sticky headers
&lt;/h2&gt;

&lt;p&gt;The other piece of look-and-feel that we want to highlight is &lt;code&gt;StickyHeaderContainer&lt;/code&gt;, which finally has a proper home in the framework. It is the iOS-contacts-list / sectioned-material-list component: scroll past a section boundary and the previous header is replaced by the next one. New this week, the swap is animated. A directional slide moves the outgoing header up on a forward scroll and down on a reverse scroll, or you can pick a cross-fade.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmfa44e6l9hg1iazmvvyr.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmfa44e6l9hg1iazmvvyr.gif" alt="Sticky header sectioned scroll" width="300" height="367"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Above is a six-frame sweep from the screenshot test — the user scrolls through sections A, B, C, D, E and the pinned header recolors to whichever section is currently active at the top of the viewport.&lt;/p&gt;

&lt;p&gt;The API is small. Build the container, register sections with &lt;code&gt;addSection(header, content)&lt;/code&gt;, configure the transition style and duration, and add it to a Form:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;StickyHeaderContainer&lt;/span&gt; &lt;span class="n"&gt;sticky&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;StickyHeaderContainer&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;sticky&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setTransitionStyle&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;StickyHeaderContainer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;TRANSITION_SLIDE&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;sticky&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setTransitionDurationMillis&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;250&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sc"&gt;'A'&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="sc"&gt;'Z'&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;++)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;Label&lt;/span&gt; &lt;span class="n"&gt;header&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Label&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;""&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"StickyHeader"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="nc"&gt;Container&lt;/span&gt; &lt;span class="n"&gt;items&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Container&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;BoxLayout&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;y&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Label&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;" entry "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;sticky&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;addSection&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;header&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;form&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;BorderLayout&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;CENTER&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sticky&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;TRANSITION_SLIDE&lt;/code&gt; is the default. &lt;code&gt;TRANSITION_FADE&lt;/code&gt; cross-fades the outgoing header on top of the incoming one. &lt;code&gt;TRANSITION_NONE&lt;/code&gt; keeps the prior instantaneous swap if you want it. Issue &lt;a href="https://github.com/codenameone/CodenameOne/issues/4807" rel="noopener noreferrer"&gt;#4807&lt;/a&gt; for the original request.&lt;/p&gt;

&lt;h2&gt;
  
  
  How we test this
&lt;/h2&gt;

&lt;p&gt;Every screenshot in this post is captured by a test that runs the app on a real iOS device, an Android emulator, and headless Chrome, then diffs each capture against a stored golden image. The diff &lt;em&gt;is&lt;/em&gt; the test — if the rendered pixels drift, the run fails.&lt;/p&gt;

&lt;p&gt;For animations the test grabs a series of frames over a fixed-duration transition, then composites them into a single index image. That is how the dual-appearance shots end up as one side-by-side picture per test:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F18pf508bhtz72x9kjg3y.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F18pf508bhtz72x9kjg3y.png" alt="Dialog over a textured backdrop — light and dark" width="800" height="509"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;…and how the sticky-header animation ends up as a six-frame strip stitched into a GIF:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmfa44e6l9hg1iazmvvyr.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmfa44e6l9hg1iazmvvyr.gif" alt="Sticky header sectioned scroll" width="300" height="367"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you want to read the source, the suite lives at &lt;a href="https://github.com/codenameone/CodenameOne/tree/master/scripts/hellocodenameone/common/src/main/java/com/codenameone/examples/hellocodenameone/tests" rel="noopener noreferrer"&gt;scripts/hellocodenameone/common/src/main/java/com/codenameone/examples/hellocodenameone/tests/&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bugs and misc features from this week
&lt;/h2&gt;

&lt;p&gt;The theme work was the loudest thing this week, but plenty of other commits landed alongside it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;SIMD large-allocation fallback.&lt;/strong&gt; The SIMD path on iOS allocates its working buffers on the stack via &lt;code&gt;alloca&lt;/code&gt; for speed. Past a certain buffer size the stack allocation simply fails — there is not enough stack to give, and the request crashes the process. The fix detects that case and falls back to a regular heap allocation when the request is too large to live on the stack. Small SIMD ops keep the fast &lt;code&gt;alloca&lt;/code&gt; path; large ones no longer crash.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pluggable AnimationTime clock.&lt;/strong&gt; &lt;code&gt;Motion&lt;/code&gt;, &lt;code&gt;Timeline&lt;/code&gt;, &lt;code&gt;MorphAnimation&lt;/code&gt;, &lt;code&gt;Image.animate&lt;/code&gt;, and &lt;code&gt;Label&lt;/code&gt; tickers now all route through a new &lt;code&gt;AnimationTime&lt;/code&gt; class that defaults to &lt;code&gt;System.currentTimeMillis()&lt;/code&gt; but can be overridden. Tests can drive animations deterministically frame by frame; demos can run in slow motion or fast forward; &lt;code&gt;Motion.slowMotion&lt;/code&gt; is no longer the only lever.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;POSIX character classes for non-ASCII letters.&lt;/strong&gt; &lt;code&gt;[[:alpha:]]&lt;/code&gt;, &lt;code&gt;[[:alnum:]]&lt;/code&gt;, &lt;code&gt;[[:lower:]]&lt;/code&gt;, and &lt;code&gt;[[:upper:]]&lt;/code&gt; silently failed to match anything outside the basic ASCII range — Greek, Cyrillic, CJK ideographs, accented letters, vulgar fractions, currency symbols. They now match the way you would expect, with five regression tests covering the failing cases from the issue.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fail-fast on JDK &amp;lt; 11.&lt;/strong&gt; The simulator and "Run as desktop app" goals fork the JVM with &lt;code&gt;--add-exports=java.desktop/com.apple.eawt=ALL-UNNAMED&lt;/code&gt;, which JDK 8 rejects with the unhelpful "Could not create the Java Virtual Machine". Now the Maven plugin checks the runtime JDK version on entry to &lt;code&gt;cn1:run&lt;/code&gt; and &lt;code&gt;cn1:debug&lt;/code&gt; and aborts with a friendly message naming the detected version, &lt;code&gt;JAVA_HOME&lt;/code&gt;, and a pointer to Adoptium. JDK 11 through 25 is the supported runtime range for the simulator, JDK 8 stays the build-time requirement for the core framework, and JDK 8 is still fully supported at runtime for shipped desktop apps — only the simulator / "Run as desktop app" Maven goals require JDK 11+.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sheet scrolling swipe and animation.&lt;/strong&gt; &lt;code&gt;Sheet&lt;/code&gt; finally drags from the bottom with a real animation instead of snapping in. Issue &lt;a href="https://github.com/codenameone/CodenameOne/issues/4825" rel="noopener noreferrer"&gt;#4825&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Picker positioning.&lt;/strong&gt; &lt;code&gt;Picker&lt;/code&gt; got additional button-positioning options and a small batch of coverage tests.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Playground polish.&lt;/strong&gt; The Playground moved every &lt;code&gt;Dialog.show(...)&lt;/code&gt; to &lt;code&gt;InteractionDialog&lt;/code&gt; mode so user code calling &lt;code&gt;Dialog.show&lt;/code&gt; does not blow away the editor chrome — it renders into the layered pane instead. Error messages got a substantial overhaul. The preview-resolution syntax expanded so the Playground can pick previews from a much wider set of expressions, with a new harness keeping it honest in CI.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deeper &lt;code&gt;refreshTheme()&lt;/code&gt;.&lt;/strong&gt; &lt;code&gt;Form.refreshTheme()&lt;/code&gt; has been around forever — it re-resolves the styles on a single Form. The new thing this week is &lt;code&gt;UIManager.getInstance().refreshTheme()&lt;/code&gt;, which snapshots the current theme props &lt;em&gt;and&lt;/em&gt; theme constants, clears the resolved-style caches, and re-applies the lot. This is what lets the screenshot suite flip dark mode mid-suite and see fresh styles, and what lets a runtime palette override take effect immediately. Most apps will never need to call it directly — palettes typically don't change at runtime, and a &lt;code&gt;Display.setDarkMode(...)&lt;/code&gt; call already triggers the right invalidation. It is there if you do change the palette and want the change to stick on the next paint without reloading the theme from disk.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Where this is going — and a thank-you
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.codenameone.com/blog/ios-density-scroll-and-accessibility/" rel="noopener noreferrer"&gt;Last week's post&lt;/a&gt; was about Codename One &lt;em&gt;feeling&lt;/em&gt; faster: corrected pixel densities, principled scroll physics, SIMD on iOS, accessibility text scaling. This week is the symbiotic other half — Codename One &lt;em&gt;looking&lt;/em&gt; like it belongs on a 2026 phone. Both halves are the same project. There is not much point in shipping a SIMD-accelerated &lt;code&gt;Base64&lt;/code&gt; if the surrounding UI looks like a 2014 app, and there is not much point in shipping a glass-frosted &lt;code&gt;Dialog&lt;/code&gt; if the scroll underneath it judders.&lt;/p&gt;

&lt;p&gt;Neither half is finished. They are both ongoing, and they both depend on community help — bug reports, RFEs, the patient back-and-forth on issue threads where somebody describes a layout problem on an iPhone you do not own. A specific thank you to the people who drove the issues that turned into this week's commits: &lt;strong&gt;Thomas (@ThomasH99)&lt;/strong&gt; filed &lt;a href="https://github.com/codenameone/CodenameOne/issues/4781" rel="noopener noreferrer"&gt;#4781&lt;/a&gt; (the original "build a liquid glass example" RFE that started this whole effort), &lt;a href="https://github.com/codenameone/CodenameOne/issues/4807" rel="noopener noreferrer"&gt;#4807&lt;/a&gt; (sticky headers), &lt;a href="https://github.com/codenameone/CodenameOne/issues/4838" rel="noopener noreferrer"&gt;#4838&lt;/a&gt; (sideways tab swipe), &lt;a href="https://github.com/codenameone/CodenameOne/issues/4841" rel="noopener noreferrer"&gt;#4841&lt;/a&gt; (the POSIX regex fix), &lt;a href="https://github.com/codenameone/CodenameOne/issues/4819" rel="noopener noreferrer"&gt;#4819&lt;/a&gt; (picker buttons), and several others; &lt;strong&gt;Francesco Galgani (@jsfan3)&lt;/strong&gt; filed &lt;a href="https://github.com/codenameone/CodenameOne/issues/4825" rel="noopener noreferrer"&gt;#4825&lt;/a&gt; (sheet swipe animation) and &lt;a href="https://github.com/codenameone/CodenameOne/issues/4824" rel="noopener noreferrer"&gt;#4824&lt;/a&gt; (light + dark theme by default in initializr); &lt;strong&gt;&lt;a class="mentioned-user" href="https://dev.to/ddyer0"&gt;@ddyer0&lt;/a&gt;&lt;/strong&gt; caught &lt;a href="https://github.com/codenameone/CodenameOne/issues/4811" rel="noopener noreferrer"&gt;#4811&lt;/a&gt; (the EDT stack overflow) and &lt;a href="https://github.com/codenameone/CodenameOne/issues/4767" rel="noopener noreferrer"&gt;#4767&lt;/a&gt; (iPad restart Form size); &lt;strong&gt;Lucca Biagi (@LuccaPrado)&lt;/strong&gt; filed &lt;a href="https://github.com/codenameone/CodenameOne/issues/4817" rel="noopener noreferrer"&gt;#4817&lt;/a&gt; (form creation in IntelliJ). Several of those are RFEs you would not file unless you actually use the framework day-to-day, and that is the kind of feedback that turns into shippable work.&lt;/p&gt;

&lt;p&gt;We are sitting at &lt;strong&gt;496 open issues&lt;/strong&gt; as of this post. That is slow but steady progress — the number is moving in the right direction week over week, and the issues that close tend to ship as features or fixes you can see, not as silent triage. If you have a problem, &lt;a href="https://github.com/codenameone/CodenameOne/issues" rel="noopener noreferrer"&gt;file it&lt;/a&gt;. If you have an RFE, file that too. The themes you saw above started as an RFE.&lt;/p&gt;

&lt;p&gt;You can try the new themes today by opening the &lt;a href="https://www.codenameone.com/playground" rel="noopener noreferrer"&gt;Playground&lt;/a&gt;, by setting &lt;code&gt;nativeTheme=modern&lt;/code&gt; (or &lt;code&gt;ios.themeMode=modern&lt;/code&gt; / &lt;code&gt;and.themeMode=modern&lt;/code&gt; for finer control) in your project's &lt;code&gt;codenameone_settings.properties&lt;/code&gt;, or by picking them from the simulator's new Native Theme menu. New projects from the initializr already have them on. The shipping resources are bundled in the iOS and Android ports as of this week.&lt;/p&gt;

</description>
      <category>java</category>
      <category>mobile</category>
      <category>android</category>
      <category>ios</category>
    </item>
    <item>
      <title>Front End Debugging Part 3: Networking</title>
      <dc:creator>Shai Almog</dc:creator>
      <pubDate>Tue, 28 Jan 2025 16:46:20 +0000</pubDate>
      <link>https://dev.to/codenameone/front-end-debugging-part-3-networking-4bii</link>
      <guid>https://dev.to/codenameone/front-end-debugging-part-3-networking-4bii</guid>
      <description>&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Network Debugging Powerhouse&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Re-Issuing and Modifying Requests&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;cURL and Postman&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Throttling and Debugging Race Conditions&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Why Throttling Matters:&lt;/li&gt;
&lt;li&gt;How to Use&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Managing State with Storage Tools&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Challenges of State Management&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;&lt;strong&gt;Analyzing Request and Response Headers&lt;/strong&gt;&lt;/li&gt;

&lt;li&gt;&lt;strong&gt;Debugging in Incognito Mode: Limitations and Best Practices&lt;/strong&gt;&lt;/li&gt;

&lt;li&gt;&lt;strong&gt;Connecting the Front-End to the Database&lt;/strong&gt;&lt;/li&gt;

&lt;li&gt;Final Word&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;Debugging network communication issues is a critical skill for any front-end developer. While tools like &lt;a href="https://debugagent.com/wireshark-tcpdump-a-debugging-power-couple" rel="noopener noreferrer"&gt;Wireshark&lt;/a&gt; provide low-level insight into network traffic, modern browsers like Chrome and Firefox offer developer tools with powerful features tailored for web development. In this post we will discuss using browser-based tools to debug network communication issues effectively. This is a far better approach than using Wireshark for the vast majority of simple cases.&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/_DfNti1q6ec"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;As a side note, if you like the content of this and the other posts in this series check out my &lt;a href="https://www.amazon.com/dp/1484290410/" rel="noopener noreferrer"&gt;Debugging book&lt;/a&gt; that covers &lt;strong&gt;t&lt;/strong&gt;his subject. If you have friends that are learning to code I'd appreciate a reference to my &lt;a href="https://www.amazon.com/Java-Basics-Practical-Introduction-Full-Stack-ebook/dp/B0CCPGZ8W1/" rel="noopener noreferrer"&gt;Java Basics book.&lt;/a&gt; If you want to get back to Java after a while check out my &lt;a href="https://www.amazon.com/Java-21-Explore-cutting-edge-features/dp/9355513925/" rel="noopener noreferrer"&gt;Java 8 to 21 book&lt;/a&gt;&lt;strong&gt;.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Network Debugging Powerhouse&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Modern browsers come equipped with developer tools that rival standalone IDE debuggers in capability and convenience. Both Chrome and Firefox have robust network monitoring features that allow developers to observe/analyze requests and responses without leaving the browser.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp40dfcxozhplcdxevfm3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp40dfcxozhplcdxevfm3.png" alt="Figure 1" width="800" height="491"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;On the basic level, which you’re probably familiar with, these tools include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Network monitors:&lt;/strong&gt; View all HTTP and HTTPS requests, including their headers, payloads, and responses.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Throttling controls:&lt;/strong&gt; Simulate slower connections to test performance and debug race conditions.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Request replay functionality:&lt;/strong&gt; Modify and resend requests directly from the browser.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;While this post focuses on debugging techniques, it's worth noting that these tools are invaluable for performance optimization as well, though that topic warrants its own discussion.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffj2ly7oa8nz1ly5fc3jd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffj2ly7oa8nz1ly5fc3jd.png" alt="Figure 2" width="800" height="664"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Re-Issuing and Modifying Requests&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;One of the most powerful debugging features is the ability to re-issue requests. Instead of switching to external tools like cURL or Postman, browsers allow us to modify and resend requests directly.&lt;/p&gt;

&lt;p&gt;This lets us quickly test variations of a failing API call to pinpoint issues without leaving the debugging environment. It’s especially useful when we have hard to reproduce issues or deep UI hierarchies.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;In Firefox we can&lt;/strong&gt; right-click any network entry in the Firefox Developer Tools and select "Resend." This opens an editable window where we can change request parameters, such as headers, payloads, or query strings, and resend the request.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F15er44m35zukxdxdvfe7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F15er44m35zukxdxdvfe7.png" alt="Figure 3" width="800" height="511"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Chrome provides similar functionality, though its interface for modifying and resending requests is slightly less direct than Firefox's.&lt;/p&gt;

&lt;h3&gt;
  
  
  cURL and Postman
&lt;/h3&gt;

&lt;p&gt;Both browsers let you copy a request as a cURL command via the context menu. This is useful for reproducing issues in the terminal or sharing with back-end developers. I use this frequently as part of creating a reproducible issue.&lt;/p&gt;

&lt;p&gt;If you prefer Postman, you can copy request headers and payloads from the browser and paste them into Postman to replicate requests.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Throttling and Debugging Race Conditions&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Network throttling is a highly underrated feature that can be a game-changer for debugging specific classes of bugs. Both Chrome and Firefox allow developers to simulate various network speeds, from 2G connections to fast 4G.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwgipd5uu6mtqj5zutjj7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwgipd5uu6mtqj5zutjj7.png" alt="Figure 4" width="800" height="470"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Why Throttling Matters:
&lt;/h3&gt;

&lt;p&gt;Some bugs only surface when requests arrive out of their expected order. Slowing down the network can help replicate and analyze these situations. Typical examples would be race conditions and related issues.&lt;/p&gt;

&lt;p&gt;This is also very useful for simulating real-world conditions. Many users may not have fast or reliable internet connections. Throttling helps you understand how your application behaves in these scenarios.&lt;/p&gt;

&lt;p&gt;I use this frequently when testing loading indicators which disappear too quickly when running locally. Instead of adding sleep code into the JavaScript or server code I can simulate slow-loading assets to verify that loading spinners or placeholders appear correctly.&lt;/p&gt;

&lt;h3&gt;
  
  
  How to Use
&lt;/h3&gt;

&lt;p&gt;In Chrome we Open Developer Tools → Network tab.&lt;/p&gt;

&lt;p&gt;We then use the "No throttling" dropdown to select pre-configured speeds or create a custom profile.&lt;/p&gt;

&lt;p&gt;In Firefox we have similar functionality is available under the Network Monitor.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Managing State with Storage Tools&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Local storage, session storage, and indexedDB often hold data critical to reproducing bugs, especially those tied to specific user states or devices.&lt;/p&gt;

&lt;h3&gt;
  
  
  Challenges of State Management
&lt;/h3&gt;

&lt;p&gt;Even in incognito mode, state can persist if multiple private windows are open simultaneously. Persistence across sessions is a big challenge in these situations.&lt;/p&gt;

&lt;p&gt;Understanding the exact state of a user's local storage can provide insight into seemingly random bugs. Debugging user-specific issues is problematic without control over storage.&lt;/p&gt;

&lt;p&gt;In Firefox the dedicated &lt;strong&gt;Storage&lt;/strong&gt; tab in Developer Tools makes it easy to inspect, edit, and delete data from local storage, session storage, cookies, and indexedDB.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F93gcpg2x73ijrbkapoy7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F93gcpg2x73ijrbkapoy7.png" alt="Figure 5" width="800" height="371"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In Chrome the &lt;strong&gt;Application&lt;/strong&gt; tab consolidates all storage options, including the ability to clear specific caches or edit entries manually.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb363c16wt9o4s3k2dd55.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb363c16wt9o4s3k2dd55.png" alt="Figure 6" width="800" height="523"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This functionality has many powerful uses for debugging:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Inject Debug Information:&lt;/strong&gt; Tools like these let us manually add or modify storage data to simulate edge cases or specific user conditions.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Share Local State:&lt;/strong&gt; Users can export their local storage, cookies, or indexedDB entries, allowing developers to reproduce issues locally.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Clear Cache Strategically:&lt;/strong&gt; Clear only the relevant entries instead of a blanket cache clear, preserving useful state for debugging.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Analyzing Request and Response Headers&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Request and response headers often hold the key to understanding network issues. We can use the network monitor to inspect:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Authorization headers:&lt;/strong&gt; Check for missing or malformed tokens.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;CORS headers:&lt;/strong&gt; Verify that the server allows requests from your domain. These are some of the most painful type of http bugs. Reviewing these headers can be a lifesaver. If requests fail with CORS errors, inspect the &lt;code&gt;Access-Control-Allow-Origin&lt;/code&gt; header in the response.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Cache-Control headers:&lt;/strong&gt; Ensure proper caching behavior for your resources.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These tools are especially useful when debugging missing headers: Look for required headers like &lt;code&gt;Content-Type&lt;/code&gt; or &lt;code&gt;Authorization&lt;/code&gt;. Debugging Authentication: Use the "Copy as cURL" feature to test API calls with modified headers directly in the terminal.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Debugging in Incognito Mode: Limitations and Best Practices&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Incognito mode can help isolate issues by providing a clean slate, however it has some limitations. Multiple incognito windows share the same state, which can lead to unintentional persistence of local data.&lt;/p&gt;

&lt;p&gt;I suggest using &lt;strong&gt;storage management tools&lt;/strong&gt; to manually clear or modify local data instead of relying solely on incognito mode. Keep only one incognito window open during testing to avoid unintended state sharing.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Connecting the Front-End to the Database&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;The front-end is often a transition point between user interaction and back-end data processing. While this post focuses on debugging the network layer, it's important to remember that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Network issues often manifest due to back-end problems (e.g., a database error resulting in a 500 Internal Server Error).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Front-end developers should collaborate closely with back-end engineers to trace issues across the stack.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We can use &lt;strong&gt;custom response headers&lt;/strong&gt; to include diagnostic information from the back end, such as query execution time or error codes. We can leverage &lt;strong&gt;server logs&lt;/strong&gt; in conjunction with front-end debugging to get a complete picture of the issue.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Word
&lt;/h2&gt;

&lt;p&gt;Browser developer tools are indispensable for debugging network communication issues, offering features like request replay, throttling, and storage management that simplify the debugging process. By mastering these tools, front-end developers can efficiently identify and resolve issues, ensuring a smoother user experience.&lt;/p&gt;

&lt;p&gt;With the techniques and tips outlined in this post, you'll be better equipped to tackle network debugging challenges head-on. As you grow more familiar with these tools, you'll find them invaluable not only for debugging but also for improving your development workflow.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>frontend</category>
      <category>java</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Front End Debugging Part 2: Console.log() to the Max</title>
      <dc:creator>Shai Almog</dc:creator>
      <pubDate>Tue, 26 Nov 2024 17:53:11 +0000</pubDate>
      <link>https://dev.to/codenameone/front-end-debugging-part-2-consolelog-to-the-max-5704</link>
      <guid>https://dev.to/codenameone/front-end-debugging-part-2-consolelog-to-the-max-5704</guid>
      <description>&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Understanding Front-End Logging vs. Back-End Logging&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Leveraging Console Log Levels&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Customizing Console Output with CSS&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Stack Tracing with console.trace()&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Assertions for Design-by-Contract&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Printing Tables for Clearer Data Visualization&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Copying Objects to the Clipboard&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Inspecting with console.dir() and dirxml()&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Counting Function Calls&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Organizing Logs with Groups&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Chrome-Specific Debugging Features&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Final Word&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In my previous post I talked about why &lt;code&gt;Console.log()&lt;/code&gt; isn’t the most effective debugging tool. In this installment, we will do a bit of an about-face and discuss the ways in which &lt;code&gt;Console.log()&lt;/code&gt; is fantastic. Let’s break down some essential concepts and practices that can make your debugging life much easier and more productive.&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/Qi7S98HNhYY"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;As a side note, if you like the content of this and the other posts in this series check out my &lt;a href="https://www.amazon.com/dp/1484290410/" rel="noopener noreferrer"&gt;Debugging book&lt;/a&gt; that covers this subject. If you have friends that are learning to code I'd appreciate a reference to my &lt;a href="https://www.amazon.com/Java-Basics-Practical-Introduction-Full-Stack-ebook/dp/B0CCPGZ8W1/" rel="noopener noreferrer"&gt;Java Basics book.&lt;/a&gt; If you want to get back to Java after a while check out my &lt;a href="https://www.amazon.com/Java-21-Explore-cutting-edge-features/dp/9355513925/" rel="noopener noreferrer"&gt;Java 8 to 21 book&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Understanding Front-End Logging vs. Back-End Logging&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Front-end logging differs significantly from back-end logging, and understanding this distinction is crucial. Unlike back-end systems, where persistent logs are vital for monitoring and debugging, the fluid nature of front-end development introduces different challenges. When debugging backends I’d often go for tracepoints which are far superior in that setting. However the front-end with its constant need to refresh, reload, contexts switch etc. is a very different beast. In the front-end relying heavily on elaborate logging mechanisms can become cumbersome.&lt;/p&gt;

&lt;p&gt;While tracepoints remain superior to basic print statements, the continuous testing and browser reloading in front-end workflows lessen their advantage. Moreover, features like logging to a file or structured ingestion are rarely useful in the browser, diminishing the need for a comprehensive logging framework. However, using a logger is still considered best practice over the typical &lt;code&gt;Console.log&lt;/code&gt; for long term logging… For short term logging &lt;code&gt;Console.log&lt;/code&gt; has some tricks up its sleeve.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Leveraging Console Log Levels&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;One of the hidden gems of the browser console is its support for log levels, which is a significant step up from rudimentary print statements. The console provides five levels:&lt;/p&gt;

&lt;p&gt;• &lt;strong&gt;log&lt;/strong&gt;: Standard logging&lt;/p&gt;

&lt;p&gt;• &lt;strong&gt;debug&lt;/strong&gt;: Same as log but used for debugging purposes&lt;/p&gt;

&lt;p&gt;• &lt;strong&gt;info&lt;/strong&gt;: Informative messages, often rendered like log/debug&lt;/p&gt;

&lt;p&gt;• &lt;strong&gt;warn&lt;/strong&gt;: Warnings that might need attention&lt;/p&gt;

&lt;p&gt;• &lt;strong&gt;error&lt;/strong&gt;: Errors that have occurred&lt;/p&gt;

&lt;p&gt;While log and debug can be indistinguishable, these levels allow for a more organized and filtered debugging experience. Browsers enable filtering the output based on these levels, mirroring the capabilities of server-side logging systems and allowing you to focus on relevant messages.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjma0r3v5y0pfqbiipmdd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjma0r3v5y0pfqbiipmdd.png" alt="Log Levels" width="474" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Customizing Console Output with CSS&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Front-end development allows for creative solutions, and logging is no exception. Using CSS styles in the console can make logs more visually distinct. By utilizing &lt;code&gt;%c&lt;/code&gt; in a console message, you can apply custom CSS:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;customLog&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;%c&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;color:black;background:pink;font-family:system-ui;font-size:4rem;-webkit-text-stroke: 1px black;font-weight:bold&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;customLog&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Dazzle&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This approach is helpful when you need to make specific logs stand out or organize output visually. You can use multiple &lt;code&gt;%c&lt;/code&gt; substitutions to apply various styles to different parts of a log message.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh2lr6p4dj2t67lyqt37y.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh2lr6p4dj2t67lyqt37y.png" alt="CSS Styling" width="800" height="165"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Stack Tracing with console.trace()&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;console.trace()&lt;/code&gt; method can print a stack trace at a particular location, which can sometimes be helpful for understanding the flow of your code. However, due to JavaScript’s asynchronous behavior, stack traces aren’t always as straightforward as in back-end debugging. Still, in specific scenarios, such as synchronous code segments or event handling, it can be quite valuable.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Assertions for Design-by-Contract&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Assertions in front-end code allow developers to enforce expectations and promote a “fail-fast” mentality. Using &lt;code&gt;Console.assert()&lt;/code&gt;, you can test conditions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;assert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;x must be greater than zero&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the browser, a failed assertion appears as an error, similar to console.error. An added benefit is that assertions can be stripped from production builds, removing any performance impact. This makes assertions a great tool for enforcing design contracts during development without compromising production efficiency.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpy7ikkhsp14yr95g3ptp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpy7ikkhsp14yr95g3ptp.png" alt=" " width="800" height="61"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Printing Tables for Clearer Data Visualization&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;When working with arrays or objects, displaying data as tables can significantly enhance readability. The console.table() method allows you to output structured data easily:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;table&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Simple Array&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;With a few elements&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;in line&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This method is especially handy when debugging arrays of objects, presenting a clear, tabular view of the data and making complex data structures much easier to understand.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn5ki2d0rsggehjtq2ans.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn5ki2d0rsggehjtq2ans.png" alt="Tables" width="800" height="640"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Copying Objects to the Clipboard&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Debugging often involves inspecting objects, and the &lt;code&gt;copy(object)&lt;/code&gt; method allows you to copy an object’s content to the clipboard for external use. This feature is useful when you need to transfer data or analyze it outside the browser.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Inspecting with console.dir() and dirxml()&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;console.dir()&lt;/code&gt; method provides a more detailed view of objects, showing their properties as you’d see in a debugger. This is particularly helpful for inspecting DOM elements or exploring API responses. Meanwhile, &lt;code&gt;console.dirxml()&lt;/code&gt; allows you to view objects as XML, which can be useful when debugging HTML structures.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpkdbguve69cnlocorjqm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpkdbguve69cnlocorjqm.png" alt="Console Dir" width="800" height="552"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Counting Function Calls&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Keeping track of how often a function is called or a code block is executed can be crucial. The &lt;code&gt;console.count()&lt;/code&gt; method tracks the number of times it’s invoked, helping you verify that functions are called as expected:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;myFunction&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;count&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;myFunction called&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can reset the counter using &lt;code&gt;console.countReset()&lt;/code&gt;. This simple tool can help you catch performance issues or confirm the correct execution flow.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjehd0jyc638vmmw8e6sn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjehd0jyc638vmmw8e6sn.png" alt="Count Function Calls" width="442" height="640"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Organizing Logs with Groups&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;To prevent log clutter, use console groups to organize related messages. &lt;code&gt;console.group()&lt;/code&gt; starts a collapsible log section, and &lt;code&gt;console.groupEnd()&lt;/code&gt; closes it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;group&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;My Group&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Message 1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Message 2&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;groupEnd&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Grouping makes it easier to navigate complex logs and keeps your console clean.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1466uy16dzgwwxoahnna.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1466uy16dzgwwxoahnna.png" alt="Grouping" width="634" height="464"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Chrome-Specific Debugging Features&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Monitoring Functions&lt;/strong&gt;: Chrome’s &lt;code&gt;monitor()&lt;/code&gt; method logs every call to a function, showing the arguments and enabling a method-tracing experience.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F28jrdvvty36tn97l0r6q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F28jrdvvty36tn97l0r6q.png" alt="Monitoring" width="800" height="646"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Monitoring Events&lt;/strong&gt;: Using &lt;code&gt;monitorEvents()&lt;/code&gt;, you can log events on an element. This is useful for debugging UI interactions. For example, &lt;code&gt;monitorEvents(window, 'mouseout')&lt;/code&gt; logs only &lt;code&gt;mouseout&lt;/code&gt; events.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu6neqp6pwwrfntkb2o3q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu6neqp6pwwrfntkb2o3q.png" alt="Monitoring Events" width="800" height="513"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Querying Object Instances&lt;/strong&gt;: &lt;code&gt;queryObjects(Constructor)&lt;/code&gt; lists all objects created with a specific constructor, giving you insights into memory usage and object instantiation.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Falfl1l1zy3zxzs8pfjih.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Falfl1l1zy3zxzs8pfjih.png" alt="Query Object Instance" width="538" height="608"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Final Word&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Front-end debugging tools have come a long way. These tools provide a rich set of features that go far beyond simple &lt;code&gt;console.log()&lt;/code&gt; statements. From log levels and CSS styling to assertions and event monitoring, mastering these techniques can transform your debugging workflow.&lt;/p&gt;

&lt;p&gt;If you read this post as part of my series you will notice a big change in my attitude toward debugging when we reached the front-end. Front-end debugging is very different when compared to backend debugging. When debugging the backend I’m vehemently against code changes for debugging (e.g. println debugging), but on the front-end this can be a reasonable hack. The change in environment justifies it. The short lifecycle, the single user use case and the risk is smaller.&lt;/p&gt;

&lt;p&gt;While there are many transferrable skills we pick up while debugging, it’s important to remain flexible in our attitude. Next time we will discuss networking and storage debugging on the front-end.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>tutorial</category>
      <category>java</category>
    </item>
    <item>
      <title>Front End Debugging Part 1: Not just Console Log</title>
      <dc:creator>Shai Almog</dc:creator>
      <pubDate>Tue, 29 Oct 2024 17:38:36 +0000</pubDate>
      <link>https://dev.to/codenameone/front-end-debugging-part-1-not-just-console-log-14f0</link>
      <guid>https://dev.to/codenameone/front-end-debugging-part-1-not-just-console-log-14f0</guid>
      <description>&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Instant Debugging with the&lt;/strong&gt; &lt;code&gt;debugger&lt;/code&gt; Keyword&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Triggering Debugging from the Console&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;DOM Breakpoints: Monitoring DOM Changes&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;XHR Breakpoints: Uncovering Hidden Network Calls&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Simulating Environments for Debugging&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Debugging Layout and Style Issues&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Final Word&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;As a Java developer most of my focus is on the backend side of debugging. Front-end debugging poses different challenges and has sophisticated tools of its own. Unfortunately, print based debugging has become the norm in front-end. To be fair, it makes more sense there as the cycles are different and the problem is always a single user problem. But even if you choose to use &lt;code&gt;Console.log&lt;/code&gt;, there’s a lot of nuance to pick up there.&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/1KFlbecOmc0"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;As a side note, if you like the content of this and the other posts in this series check out my &lt;a href="https://www.amazon.com/dp/1484290410/" rel="noopener noreferrer"&gt;Debugging book&lt;/a&gt; that covers this subject. If you have friends that are learning to code I'd appreciate a reference to my &lt;a href="https://www.amazon.com/Java-Basics-Practical-Introduction-Full-Stack-ebook/dp/B0CCPGZ8W1/" rel="noopener noreferrer"&gt;Java Basics book.&lt;/a&gt; If you want to get back to Java after a while check out my &lt;a href="https://www.amazon.com/Java-21-Explore-cutting-edge-features/dp/9355513925/" rel="noopener noreferrer"&gt;Java 8 to 21 book&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Instant Debugging with the&lt;/strong&gt; &lt;code&gt;debugger&lt;/code&gt; Keyword
&lt;/h2&gt;

&lt;p&gt;A cool yet powerful tool in JavaScript is the &lt;code&gt;debugger&lt;/code&gt; keyword. Instead of simply printing a stack trace, we can use this keyword to launch the debugger directly at the line of interest. That is a fantastic tool that instantly brings your attention to a bug, I often use it in my debug builds of the front-end instead of just printing an error log.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How to Use It:&lt;/strong&gt; Place the &lt;code&gt;debugger&lt;/code&gt; keyword within your code, particularly within error-handling methods. When the code execution hits this line, it automatically pauses, allowing you to inspect the current state, step through code, and understand what's going wrong.&lt;/p&gt;

&lt;p&gt;Notice that while this is incredibly useful during development, we must remember to remove or conditionally exclude &lt;code&gt;debugger&lt;/code&gt; statements in production environments. A release build should not include these calls in a production site live environment.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Triggering Debugging from the Console&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Modern browsers allow you to invoke debugging directly from the console, adding an additional layer of flexibility to your debugging process.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example:&lt;/strong&gt; By using the &lt;code&gt;debug(functionName)&lt;/code&gt; command in the console, you can set a breakpoint at the start of the specified function. When this function is subsequently invoked, the execution halts, sending you directly into the debugger.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;hello&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Hello &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nf"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;hello&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;hello&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Shai&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is particularly useful when you want to start debugging without modifying the source code, or when you need to inspect a function that’s only defined in the global scope.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;DOM Breakpoints: Monitoring DOM Changes&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;DOM breakpoints are an advanced feature in Chrome and Firebug (Firefox plugin) that allow you to pause execution when a specific part of the DOM is altered.&lt;/p&gt;

&lt;p&gt;To use it we can right-click on the desired DOM element, select “Break On,” and choose the specific mutation type you are interested in (e.g., subtree modifications, attribute changes, etc.).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftnhcf65djlyctm44fjxr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftnhcf65djlyctm44fjxr.png" alt="Subtree modification" width="800" height="610"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;DOM breakpoints are extremely powerful for tracking down issues where DOM manipulation causes unexpected results, such as dynamic content loading or changes in the user interface that disrupt the intended layout or functionality. Think of them like field breakpoints we discussed in the past.&lt;/p&gt;

&lt;p&gt;These breakpoints complement traditional line and conditional breakpoints, providing a more granular approach to debugging complex front-end issues. This is a great tool to use when the DOM is manipulated by an external dependency.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;XHR Breakpoints: Uncovering Hidden Network Calls&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Understanding who initiates specific network requests can be challenging, especially in large applications with multiple sources contributing to a request. XHR (&lt;code&gt;XMLHttpRequest&lt;/code&gt;) breakpoints provide a solution to this problem.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg7ojrpu5d225e69qoc46.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg7ojrpu5d225e69qoc46.png" alt="XHR Breakpoint" width="512" height="210"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In Chrome or Firebug, set an XHR breakpoint by specifying a substring of the URI you wish to monitor. When a request matching this pattern is made, the execution stops, allowing you to investigate the source of the request.&lt;/p&gt;

&lt;p&gt;This tool is invaluable when dealing with dynamically generated URIs or complex flows where tracking the origin of a request is not straightforward.&lt;/p&gt;

&lt;p&gt;Notice that you should be selective with the filters you set; leaving the filter blank will cause the breakpoint to trigger on all XHR requests, which can become overwhelming.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Simulating Environments for Debugging&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Sometimes, the issues you need to debug are specific to certain environments, such as mobile devices or different geographical locations. Chrome and Firefox offer several simulation tools to help you replicate these conditions on your desktop.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Simulating User Agents:&lt;/strong&gt; Change the browser’s user agent to mimic different devices or operating systems. This can help you identify platform-specific issues or debug server-side content delivery that varies by user agent.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Geolocation Spoofing:&lt;/strong&gt; Modify the browser’s reported location to test locale-specific features or issues. This is particularly useful for applications that deliver region-specific content or services.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Touch and Device Orientation Emulation:&lt;/strong&gt; Simulate touch events or change the device orientation to see how your application responds to mobile-specific interactions. This is crucial for ensuring a seamless user experience across all devices.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These are things that are normally very difficult to reproduce. E.g. touch related issues are often challenging to debug on the device. By simulating them on the desktop browser we can shorten the debug cycle and use the tooling available on the desktop.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Debugging Layout and Style Issues&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;CSS and HTML bugs can be particularly tricky, often requiring a detailed examination of how elements are rendered and styled.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn1u9cdoost95glyce2it.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn1u9cdoost95glyce2it.png" alt="Inspect element" width="800" height="463"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Inspect Element:&lt;/strong&gt; The "inspect element" tool is the cornerstone of front-end debugging, allowing you to view and manipulate the DOM and CSS in real-time. As you make changes, the page updates instantly, providing immediate feedback on your tweaks.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Addressing Specificity Issues:&lt;/strong&gt; One common problem is CSS specificity, where a more specific selector overrides the styles you intend to apply. The inspect element view highlights overridden styles, helping you identify and resolve conflicts.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Firefox vs. Chrome:&lt;/strong&gt; While both browsers offer robust tools, they have different approaches to organizing these features. Firefox’s interface may seem more straightforward, with fewer tabs, while Chrome organizes similar tools under various tabs, which can either streamline your workflow or add complexity, depending on your preference.&lt;/p&gt;

&lt;h3&gt;
  
  
  Final Word
&lt;/h3&gt;

&lt;p&gt;There are many front-end tools that I want to discuss in the coming posts. I hope you picked up a couple of new debugging tricks in this first part.&lt;/p&gt;

&lt;p&gt;Front-end debugging requires deep understanding of browser tools and JavaScript capabilities. By mastering the techniques outlined in this post—instant debugging with the &lt;code&gt;debugger&lt;/code&gt; keyword, DOM and XHR breakpoints, environment simulation, and layout inspection—you can significantly enhance your debugging efficiency and deliver more robust, error-free web applications.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>java</category>
      <category>tutorial</category>
      <category>frontend</category>
    </item>
    <item>
      <title>The Art of Full Stack Debugging</title>
      <dc:creator>Shai Almog</dc:creator>
      <pubDate>Tue, 08 Oct 2024 18:39:51 +0000</pubDate>
      <link>https://dev.to/codenameone/the-art-of-full-stack-debugging-3oba</link>
      <guid>https://dev.to/codenameone/the-art-of-full-stack-debugging-3oba</guid>
      <description>&lt;ul&gt;
&lt;li&gt;
Full Stack Development, A Shifting Definition

&lt;ul&gt;
&lt;li&gt;The Full Stack Debugging Approach&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

Frontend Debugging: Tools and Techniques

&lt;ul&gt;
&lt;li&gt;It isn't "Just Console.log"&lt;/li&gt;
&lt;li&gt;The Power of Developer Tools&lt;/li&gt;
&lt;li&gt;Tackling Code Obfuscation&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

Debugging Across Layers

&lt;ul&gt;
&lt;li&gt;Isolating Issues Across the Stack&lt;/li&gt;
&lt;li&gt;The Importance of System-Level Debugging&lt;/li&gt;
&lt;li&gt;Embracing Complexity&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Conclusion&lt;/li&gt;

&lt;/ul&gt;



&lt;p&gt;Full stack development is often likened to an intricate balancing act, where developers are expected to juggle multiple responsibilities across the frontend, backend, database, and beyond. As the definition of full stack development continues to evolve, so too does the approach to debugging. Full stack debugging is an essential skill for developers, as it involves tracking issues through multiple layers of an application, often navigating domains where one’s knowledge may only be cursory. In this blog post I aim to explore the nuances of full stack debugging, offering practical tips and insights for developers navigating the complex web of modern software development.&lt;/p&gt;

&lt;p&gt;Notice that this is an introductory post focusing mostly on the front end debugging aspects, in the following posts I will dig deeper into the less familiar capabilities in front end debugging.&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/mM8p2VrrEaE"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;As a side note, if you like the content of this and the other posts in this series check out my &lt;a href="https://www.amazon.com/dp/1484290410/" rel="noopener noreferrer"&gt;Debugging book&lt;/a&gt; that covers &lt;strong&gt;t&lt;/strong&gt;his subject. If you have friends that are learning to code I'd appreciate a reference to my &lt;a href="https://www.amazon.com/Java-Basics-Practical-Introduction-Full-Stack-ebook/dp/B0CCPGZ8W1/" rel="noopener noreferrer"&gt;Java Basics book.&lt;/a&gt; If you want to get back to Java after a while check out my &lt;a href="https://www.amazon.com/Java-21-Explore-cutting-edge-features/dp/9355513925/" rel="noopener noreferrer"&gt;Java 8 to 21 book&lt;/a&gt;&lt;strong&gt;.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Full Stack Development, A Shifting Definition
&lt;/h2&gt;

&lt;p&gt;The definition of full stack development is as fluid as the technology stacks themselves. Traditionally, full stack developers were defined as those who could work on both the frontend and backend of an application. However, as the industry evolves, this definition has expanded to include aspects of operations (OPS) and configuration. The modern full stack developer is expected to submit pull requests that cover all parts required to implement a feature—backend, database, frontend, and configuration. While this does not make them an expert in all these areas, it does require them to navigate across domains, often relying on domain experts for guidance.&lt;/p&gt;

&lt;p&gt;I've heard it said that full stack developers are:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Jack of all trades, master of none.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;However, the full quote probably better represents the reality:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Jack of all trades, master of none, &lt;strong&gt;but better than a master of one&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  The Full Stack Debugging Approach
&lt;/h3&gt;

&lt;p&gt;Just as full stack development involves working across various domains, full stack debugging requires a similar approach. A symptom of a bug may manifest in the frontend, but its root cause could lie deep within the backend or database layers. Full stack debugging is about tracing these issues through the layers and isolating them as quickly as possible. This is no easy task, especially when dealing with complex systems where multiple layers interact in unexpected ways. The key to successful full stack debugging lies in understanding how to track an issue through each layer of the stack and identifying common pitfalls that developers may encounter.&lt;/p&gt;

&lt;h2&gt;
  
  
  Frontend Debugging: Tools and Techniques
&lt;/h2&gt;

&lt;h3&gt;
  
  
  It isn't "Just Console.log"
&lt;/h3&gt;

&lt;p&gt;Frontend developers are often stereotyped as relying solely on &lt;code&gt;Console.log&lt;/code&gt; for debugging. While this method is simple and effective for basic debugging tasks, it falls short when dealing with the complex challenges of modern web development. The complexity of frontend code has increased significantly, making advanced debugging tools not just useful, but necessary. Yet, despite the availability of powerful debugging tools, many developers continue to shy away from them, clinging to old habits.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Power of Developer Tools
&lt;/h3&gt;

&lt;p&gt;Modern web browsers come equipped with robust developer tools that offer a wide range of capabilities for debugging frontend issues. These tools, available in browsers like Chrome and Firefox, allow developers to inspect elements, view and edit HTML and CSS, monitor network activity, and much more. One of the most powerful, yet underutilized, features of these tools is the JavaScript debugger.&lt;/p&gt;

&lt;p&gt;The debugger allows developers to set breakpoints, step through code, and inspect the state of variables at different points in the execution. However, the complexity of frontend code, particularly when it has been obfuscated for performance reasons, can make debugging a challenging task.&lt;/p&gt;

&lt;p&gt;We can launch the browser tools on Firefox using this menu:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fegm0deq97u05j8tr1ikj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fegm0deq97u05j8tr1ikj.png" alt=" " width="800" height="299"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;On Chrome we can use this option:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flsi1y1om76prwf8gdob4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flsi1y1om76prwf8gdob4.png" alt=" " width="800" height="555"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I prefer working with Firefox, I find their developer tools more convenient but both browsers have similar capabilities. Both have fantastic debuggers (as you can see with the Firefox debugger below), unfortunately many developers limit themselves to console printing instead of exploring this powerful tool.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0elcqadckt63igxjlzso.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0elcqadckt63igxjlzso.png" alt=" " width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Tackling Code Obfuscation
&lt;/h3&gt;

&lt;p&gt;Code obfuscation is a common practice in frontend development, employed to protect proprietary code and reduce file sizes for better performance. However, obfuscation also makes the code difficult to read and debug. Fortunately, both Chrome and Firefox developer tools provide a feature to de-obfuscate code, making it more readable and easier to debug. By clicking the curly brackets button in the toolbar, developers can transform a single line of obfuscated code into a well-formed, debuggable file.&lt;/p&gt;

&lt;p&gt;Another important tool in the fight against obfuscation is the source map. Source maps are files that map obfuscated code back to its original source code, including comments. When generated and properly configured, source maps allow developers to debug the original code instead of the obfuscated version. In Chrome, this feature can be enabled by ensuring that "Enable JavaScript source maps" is checked in the developer tools settings.&lt;/p&gt;

&lt;p&gt;You can use code like this in the JavaScript file to point at the sourcemap file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;//@sourceMappingURL=myfile.js.map&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For this to work in Chrome we need to ensure that "Enable JavaScript source maps" is checked in the settings. Last I checked it was on by default but it doesn't hurt to verify:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3l1ixd5iuyunrvh9ru15.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3l1ixd5iuyunrvh9ru15.png" alt=" " width="800" height="1023"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Debugging Across Layers
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Isolating Issues Across the Stack
&lt;/h3&gt;

&lt;p&gt;In full stack development, issues often manifest in one layer but originate in another. For example, a frontend error might be caused by a misconfigured backend service or a database query that returns unexpected results. Isolating the root cause of these issues requires a methodical approach, starting from the symptom and working backward through the layers.&lt;/p&gt;

&lt;p&gt;A common strategy is to reproduce the issue in a controlled environment, such as a local development setup, where each layer of the stack can be tested individually. This helps to narrow down the potential sources of the problem. Once the issue has been isolated to a specific layer, developers can use the appropriate tools and techniques to diagnose and resolve it.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Importance of System-Level Debugging
&lt;/h3&gt;

&lt;p&gt;Full stack debugging is not limited to the application code. Often, issues arise from the surrounding environment, such as network configurations, third-party services, or hardware limitations. A classic example of this that we ran into a couple of years ago was a production problem where a WebSocket connection would frequently disconnect. After extensive debugging, &lt;a href="https://github.com/shannah/" rel="noopener noreferrer"&gt;Steve&lt;/a&gt; discovered that the issue was caused by the CDN provider (CloudFlare) timing out the WebSocket after two minutes—something that could only be identified by debugging the entire system, not just the application code.&lt;/p&gt;

&lt;p&gt;System-level debugging requires a broad understanding of how different components of the infrastructure interact with each other. It also involves using tools that can monitor and analyze the behavior of the system as a whole, such as network analyzers, logging frameworks, and performance monitoring tools.&lt;/p&gt;

&lt;h3&gt;
  
  
  Embracing Complexity
&lt;/h3&gt;

&lt;p&gt;Full stack debugging is inherently complex, as it requires developers to navigate multiple layers of an application, often dealing with unfamiliar technologies and tools. However, this complexity also presents an opportunity for growth. By embracing the challenges of full stack debugging, developers can expand their knowledge and become more versatile in their roles.&lt;/p&gt;

&lt;p&gt;One of the key strengths of full stack development is the ability to collaborate with domain experts. When debugging an issue that spans multiple layers, it is important to leverage the expertise of colleagues who specialize in specific areas. This collaborative approach not only helps to resolve issues more efficiently but also fosters a culture of knowledge sharing and continuous learning within the team.&lt;/p&gt;

&lt;p&gt;As tools continue to evolve, so too do the tools and techniques available for debugging. Developers should strive to stay up-to-date with the latest advancements in debugging tools and best practices. Whether it’s learning to use new features in browser developer tools or mastering system-level debugging techniques, continuous learning is essential for success in full stack development.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Full stack debugging is a critical skill for modern developers, we mistakenly think it requires deep understanding of both the application and its surrounding environment. I disagree... By mastering the tools and techniques discussed in this post/upcoming posts, developers can more effectively diagnose and resolve issues that span multiple layers of the stack. Whether you’re dealing with obfuscated frontend code, misconfigured backend services, or system-level issues, the key to successful debugging lies in a methodical, collaborative approach.&lt;/p&gt;

&lt;p&gt;You don't need to understand every part of the system, just the ability to eliminate the impossible.&lt;/p&gt;

</description>
      <category>java</category>
      <category>javascript</category>
      <category>tutorial</category>
      <category>frontend</category>
    </item>
    <item>
      <title>Mastering Serverless Debugging</title>
      <dc:creator>Shai Almog</dc:creator>
      <pubDate>Tue, 02 Jul 2024 16:26:02 +0000</pubDate>
      <link>https://dev.to/codenameone/mastering-serverless-debugging-211p</link>
      <guid>https://dev.to/codenameone/mastering-serverless-debugging-211p</guid>
      <description>&lt;ul&gt;
&lt;li&gt;Introduction to Serverless Computing&lt;/li&gt;
&lt;li&gt;
Challenges of Serverless Debugging

&lt;ul&gt;
&lt;li&gt;Disconnected Environments&lt;/li&gt;
&lt;li&gt;Lack of Standardization&lt;/li&gt;
&lt;li&gt;Limited Debugging Tools&lt;/li&gt;
&lt;li&gt;Concurrency and Scale&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

Effective Strategies for Serverless Debugging

&lt;ul&gt;
&lt;li&gt;Local Debugging with IDE Remote Capabilities&lt;/li&gt;
&lt;li&gt;Using Feature Flags for Debugging&lt;/li&gt;
&lt;li&gt;Staged Rollouts and Canary Deployments&lt;/li&gt;
&lt;li&gt;Comprehensive Logging&lt;/li&gt;
&lt;li&gt;Embracing Idempotency&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

Debugging a Lambda Application Locally with AWS SAM

&lt;ul&gt;
&lt;li&gt;Setting Up the Local Environment&lt;/li&gt;
&lt;li&gt;Running the Hello World Application Locally&lt;/li&gt;
&lt;li&gt;Configuring Remote Debugging&lt;/li&gt;
&lt;li&gt;Handling Debugger Timeouts&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Final Word&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;Serverless computing has emerged as a transformative approach to deploying and managing applications. The theory is that by abstracting away the underlying infrastructure, developers can focus solely on writing code. While the benefits are clear—scalability, cost efficiency, and performance—debugging serverless applications presents unique challenges. This post explores effective strategies for debugging serverless applications, particularly focusing on AWS Lambda.&lt;/p&gt;

&lt;p&gt;Before I proceed I think it's important to disclose a bias: I am personally not a huge fan of Serverless or PaaS after &lt;a href="https://dev.to/codenameone/production-horrors-handling-disasters-public-debrief-1kf6"&gt;I was burned badly by PaaS in the past&lt;/a&gt;. However, &lt;a href="https://www.adam-bien.com/" rel="noopener noreferrer"&gt;some smart people like Adam swear by it&lt;/a&gt; so I should keep an open mind.&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/B6uyutAbEDw"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;As a side note, if you like the content of this and the other posts in this series check out my &lt;a href="https://www.amazon.com/dp/1484290410/" rel="noopener noreferrer"&gt;Debugging book&lt;/a&gt; that covers &lt;strong&gt;t&lt;/strong&gt;his subject. If you have friends that are learning to code I'd appreciate a reference to my &lt;a href="https://www.amazon.com/Java-Basics-Practical-Introduction-Full-Stack-ebook/dp/B0CCPGZ8W1/" rel="noopener noreferrer"&gt;Java Basics book.&lt;/a&gt; If you want to get back to Java after a while check out my &lt;a href="https://www.amazon.com/Java-21-Explore-cutting-edge-features/dp/9355513925/" rel="noopener noreferrer"&gt;Java 8 to 21 book&lt;/a&gt;&lt;strong&gt;.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction to Serverless Computing
&lt;/h2&gt;

&lt;p&gt;Serverless computing, often referred to as Function as a Service (FaaS), allows developers to build and run applications without managing servers. In this model, cloud providers automatically handle the infrastructure, scaling, and management tasks, enabling developers to focus purely on writing and deploying code. Popular serverless platforms include AWS Lambda, Azure Functions, and Google Cloud Functions.&lt;/p&gt;

&lt;p&gt;In contrast, Platform as a Service (PaaS) offers a more managed environment where developers can deploy applications but still need to configure and manage some aspects of the infrastructure. PaaS solutions, such as Heroku and Google App Engine, provide a higher level of abstraction than Infrastructure as a Service (IaaS) but still require some server management.&lt;/p&gt;

&lt;p&gt;Kubernetes, &lt;a href="https://debugagent.com/why-is-kubernetes-debugging-so-problematic?source=more_series_bottom_blogs" rel="noopener noreferrer"&gt;which we recently discussed&lt;/a&gt;, is an open-source container orchestration platform that automates the deployment, scaling, and management of containerized applications. While Kubernetes offers powerful capabilities for managing complex, multi-container applications, it requires significant expertise to set up and maintain. Serverless computing simplifies this by removing the need for container orchestration and management altogether.&lt;/p&gt;

&lt;p&gt;The "catch" is two fold:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Serverless programming removes the need to understand the servers but also removes the ability to rely on them resulting in more complex architectures.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Pricing starts off cheap. Practically free. It can quickly escalate especially in case of an attack or misconfiguration.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Challenges of Serverless Debugging
&lt;/h2&gt;

&lt;p&gt;While serverless architectures offer some benefits, they also introduce unique debugging challenges. The primary issues stem from the inherent complexity and distributed nature of serverless environments. Here are some of the most pressing challenges.&lt;/p&gt;

&lt;h3&gt;
  
  
  Disconnected Environments
&lt;/h3&gt;

&lt;p&gt;One of the major hurdles in serverless debugging is the lack of consistency between development, staging, and production environments. While traditional development practices rely on these separate environments to test and validate code changes, serverless architectures often complicate this process. The differences in configuration and scale between these environments can lead to bugs that only appear in production, making them difficult to reproduce and fix.&lt;/p&gt;

&lt;h3&gt;
  
  
  Lack of Standardization
&lt;/h3&gt;

&lt;p&gt;The serverless ecosystem is highly fragmented, with various vendors offering different tools and frameworks. This lack of standardization can make it challenging to adopt a unified debugging approach. Each platform has its own set of practices and tools, requiring developers to learn and adapt to multiple environments.&lt;/p&gt;

&lt;p&gt;This is slowly evolving with some platforms gaining traction, but since this is a vendor driven industry there are many edge cases.&lt;/p&gt;

&lt;h3&gt;
  
  
  Limited Debugging Tools
&lt;/h3&gt;

&lt;p&gt;Traditional debugging tools, such as step-through debugging and breakpoints, are often unavailable in serverless environments. The managed and controlled nature of serverless functions restricts access to these tools, forcing developers to rely on alternative methods, such as logging and remote debugging.&lt;/p&gt;

&lt;h3&gt;
  
  
  Concurrency and Scale
&lt;/h3&gt;

&lt;p&gt;Serverless functions are designed to handle high concurrency and scale seamlessly. However, this can introduce issues that are hard to reproduce in a local development environment. Bugs that manifest only under specific concurrency conditions or high load are particularly challenging to debug.&lt;/p&gt;

&lt;p&gt;Notice that when I discuss concurrency here I'm often referring to race conditions between separate services.&lt;/p&gt;

&lt;h2&gt;
  
  
  Effective Strategies for Serverless Debugging
&lt;/h2&gt;

&lt;p&gt;Despite these challenges, several strategies can help make serverless debugging more manageable. By leveraging a combination of local debugging, feature flags, staged rollouts, logging, idempotency, and Infrastructure as Code (IaC), developers can effectively diagnose and fix issues in serverless applications.&lt;/p&gt;

&lt;h3&gt;
  
  
  Local Debugging with IDE Remote Capabilities
&lt;/h3&gt;

&lt;p&gt;While serverless functions run in the cloud, you can simulate their execution locally using tools like AWS SAM (Serverless Application Model). This involves setting up a local server that mimics the cloud environment, allowing you to run tests and perform basic trial-and-error debugging.&lt;/p&gt;

&lt;p&gt;To get started, you need to install Docker or Docker Desktop, create an AWS account, and set up the AWS SAM CLI. Deploy your serverless application locally using the SAM CLI, which enables you to run the application and simulate Lambda functions on your local machine. Configure your IDE for remote debugging, launching the application in debug mode, and connecting your debugger to the local host. Set breakpoints to step through the code and identify issues.&lt;/p&gt;

&lt;h3&gt;
  
  
  Using Feature Flags for Debugging
&lt;/h3&gt;

&lt;p&gt;Feature flags allow you to enable or disable parts of your application without deploying new code. This can be invaluable for isolating issues in a live environment. By toggling specific features on or off, you can narrow down the problematic areas and observe the application’s behavior under different configurations.&lt;/p&gt;

&lt;p&gt;Implementing feature flags involves adding conditional checks in your code that control the execution of specific features based on the flag’s status. Monitoring the application with different flag settings helps identify the source of bugs and allows you to test fixes without affecting the entire user base.&lt;/p&gt;

&lt;p&gt;This is essentially "debugging in production". Working on a new feature?&lt;/p&gt;

&lt;p&gt;Wrap it in a feature flag which is effectively akin to wrapping the entire feature (client and server) in if statements. You can then enable it conditionally globally or on a per user basis. This means you can test the feature, enable or disable it based on configuration without redeploying the application.&lt;/p&gt;

&lt;h3&gt;
  
  
  Staged Rollouts and Canary Deployments
&lt;/h3&gt;

&lt;p&gt;Deploying changes incrementally can help catch bugs before they affect all users. Staged rollouts involve gradually rolling out updates to a small percentage of users before a full deployment. This allows you to monitor the performance and error logs of the new version in a controlled manner, catching issues early.&lt;/p&gt;

&lt;p&gt;Canary deployments take this a step further by deploying new changes to a small subset of instances (canaries) while the rest of the system runs the stable version. If issues are detected in the canaries, you can roll back the changes without impacting the majority of users. This method limits the impact of potential bugs and provides a safer way to introduce updates. This isn't great as in some cases some demographics might be more reluctant to report errors. However, for server side issues this might make sense as you can see the impact based on server logs and metrics.&lt;/p&gt;

&lt;h3&gt;
  
  
  Comprehensive Logging
&lt;/h3&gt;

&lt;p&gt;Logging is one of the most common and essential tools for debugging serverless applications. I wrote and &lt;a href="https://www.youtube.com/watch?v=53qCLRFcBSs" rel="noopener noreferrer"&gt;spoke a lot about logging in the past&lt;/a&gt;. By logging all relevant data points, including inputs and outputs of your functions, you can trace the flow of execution and identify where things go wrong.&lt;/p&gt;

&lt;p&gt;However, excessive logging can increase costs, as serverless billing is often based on execution time and resources used. It’s important to strike a balance between sufficient logging and cost efficiency. Implementing log levels and selectively enabling detailed logs only when necessary can help manage costs while providing the information needed for debugging.&lt;/p&gt;

&lt;p&gt;I talk about striking the delicate balance between debuggable code, performance and cost with logs in the following video. Notice that this is a general best practice and not specific to serverless.&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/53qCLRFcBSs"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;h3&gt;
  
  
  Embracing Idempotency
&lt;/h3&gt;

&lt;p&gt;Idempotency, a key concept from functional programming, ensures that functions produce the same result given the same inputs, regardless of the number of times they are executed. This simplifies debugging and testing by ensuring consistent and predictable behavior.&lt;/p&gt;

&lt;p&gt;Designing your serverless functions to be idempotent involves ensuring that they do not have side effects that could alter the outcome when executed multiple times. For example, including timestamps or unique identifiers in your requests can help maintain consistency. Regularly testing your functions to verify idempotency can make it easier to pinpoint discrepancies and debug issues.&lt;/p&gt;

&lt;p&gt;Testing is always important but in serverless and complex deployments it becomes critical. Awareness and embrace of idempotency allows for more testable code and easier to reproduce bugs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Debugging a Lambda Application Locally with AWS SAM
&lt;/h2&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/SlFA-JlTYGM"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Debugging serverless applications, particularly AWS Lambda functions, can be challenging due to their distributed nature and the limitations of traditional debugging tools. However, AWS SAM (Serverless Application Model) provides a way to simulate Lambda functions locally, enabling developers to test and debug their applications more effectively. I will use it as a sample to explore the process of setting up a local debugging environment, running a sample application, and configuring remote debugging.&lt;/p&gt;

&lt;h3&gt;
  
  
  Setting Up the Local Environment
&lt;/h3&gt;

&lt;p&gt;Before diving into the debugging process, it's crucial to set up a local environment that can simulate the AWS Lambda environment. This involves a few key steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Install Docker&lt;/strong&gt;: Docker is required to run the local simulation of the Lambda environment. You can download Docker or Docker Desktop from the official &lt;a href="https://docs.docker.com/get-docker/" rel="noopener noreferrer"&gt;Docker website&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Create an AWS Account&lt;/strong&gt;: If you don't already have an AWS account, you need to create one. Follow the instructions on the &lt;a href="https://aws.amazon.com/premiumsupport/knowledge-center/create-and-activate-aws-account/" rel="noopener noreferrer"&gt;AWS account creation page&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Set Up AWS SAM CLI&lt;/strong&gt;: The AWS SAM CLI is essential for building and running serverless applications locally. You can install it by following the &lt;a href="https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-install.html" rel="noopener noreferrer"&gt;AWS SAM installation guide&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Running the Hello World Application Locally
&lt;/h3&gt;

&lt;p&gt;To illustrate the debugging process, let's use a simple "Hello World" application. The code for this application can be found in the &lt;a href="https://github.com/shai-almog/HelloLambda" rel="noopener noreferrer"&gt;AWS Hello World tutorial&lt;/a&gt;.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Deploy Locally&lt;/strong&gt;: Use the SAM CLI to deploy the Hello World application locally. This can be done with the following command:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;sam &lt;span class="nb"&gt;local &lt;/span&gt;start-api
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;This command starts a local server that simulates the AWS Lambda cloud environment.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Trigger the Endpoint&lt;/strong&gt;: Once the local server is running, you can trigger the endpoint using a &lt;code&gt;curl&lt;/code&gt; command:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl http://localhost:3000/hello
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;This command sends a request to the local server, allowing you to test the function's response.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Configuring Remote Debugging
&lt;/h3&gt;

&lt;p&gt;While running tests locally is a valuable step, it doesn't provide full debugging capabilities. To debug the application, you need to configure remote debugging. This involves several steps.&lt;/p&gt;

&lt;p&gt;First we need to start the application in debug mode using the following SAM command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;sam &lt;span class="nb"&gt;local &lt;/span&gt;invoke &lt;span class="nt"&gt;-d&lt;/span&gt; 5858
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command pauses the application and waits for a debugger to connect.&lt;/p&gt;

&lt;p&gt;Next we need to configure the IDE for remote debugging. We start by setting up the IDE to connect to the local host for remote debugging. This typically involves creating a new run configuration that matches the remote debugging settings.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0mlv7ij1mypsmg0rzlsk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0mlv7ij1mypsmg0rzlsk.png" alt=" " width="800" height="498"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We can now set breakpoints in the code where we want the execution to pause. This allows us to step through the code and inspect variables and application state just like in any other local application.&lt;/p&gt;

&lt;p&gt;We can test this by invoking the endpoint e.g. using curl. With the debugger connected we would stop on the breakpoint like any other tool:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl http://localhost:3000/hello
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The application will pause at the breakpoints you set, allowing you to step through the code.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyzpgf6da5rpw332ednvm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyzpgf6da5rpw332ednvm.png" alt=" " width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Handling Debugger Timeouts
&lt;/h3&gt;

&lt;p&gt;One significant challenge when debugging Lambda functions is the quick timeout setting. Lambda functions are designed to execute quickly, and if they take too long, the costs can become prohibitive. By default, the timeout is set to a short duration, but you can configure this in the &lt;code&gt;template.yaml&lt;/code&gt; file e.g.:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;Resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;HelloWorldFunction&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AWS::Serverless::Function&lt;/span&gt;
    &lt;span class="na"&gt;Properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;Handler&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;app.lambdaHandler&lt;/span&gt;
      &lt;span class="na"&gt;Timeout&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;60&lt;/span&gt;  &lt;span class="c1"&gt;# timeout in seconds&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After updating the timeout value, re-issue the &lt;code&gt;sam build&lt;/code&gt; command to apply the changes.&lt;/p&gt;

&lt;p&gt;In some cases, running the application locally might not be enough. You may need to simulate running on the actual AWS stack to get more accurate debugging information. Solutions like SST (Serverless Stack) or MerLoc can help achieve this, though they are specific to AWS and relatively niche.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Word
&lt;/h2&gt;

&lt;p&gt;Serverless debugging requires a combination of strategies to effectively identify and resolve issues. While traditional debugging methods may not always apply, leveraging local debugging, feature flags, staged rollouts, comprehensive logging, idempotency, and IaC can significantly improve your ability to debug serverless applications. As the serverless ecosystem continues to evolve, staying adaptable and continuously updating your debugging techniques will be key to success.&lt;/p&gt;

&lt;p&gt;Debugging serverless applications, particularly AWS Lambda functions, can be complex due to their distributed nature and the constraints of traditional debugging tools. However, by leveraging tools like AWS SAM, you can simulate the Lambda environment locally and use remote debugging to step through your code. Adjusting timeout settings and considering advanced simulation tools can further enhance your debugging capabilities.&lt;/p&gt;

</description>
      <category>lambda</category>
      <category>tutorial</category>
      <category>serverless</category>
      <category>developers</category>
    </item>
    <item>
      <title>Debugging Kubernetes - Troubleshooting Guide</title>
      <dc:creator>Shai Almog</dc:creator>
      <pubDate>Tue, 18 Jun 2024 14:26:44 +0000</pubDate>
      <link>https://dev.to/codenameone/debugging-kubernetes-troubleshooting-guide-5gfh</link>
      <guid>https://dev.to/codenameone/debugging-kubernetes-troubleshooting-guide-5gfh</guid>
      <description>&lt;ul&gt;
&lt;li&gt;
Identifying Configuration Issues

&lt;ul&gt;
&lt;li&gt;Common Causes and Solutions&lt;/li&gt;
&lt;li&gt;Detailed Investigation Steps&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

Dealing with Image Pull Errors

&lt;ul&gt;
&lt;li&gt;Troubleshooting Steps&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

Handling Node Issues

&lt;ul&gt;
&lt;li&gt;Preventive Measures&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Managing Missing Configuration Keys or Secrets&lt;/li&gt;

&lt;li&gt;Utilizing Buildg for Interactive Debugging&lt;/li&gt;

&lt;li&gt;Conclusion&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;As Kubernetes continues to revolutionize the way we manage and deploy applications, understanding its intricacies becomes essential for developers and operations teams alike. If you don't have a dedicated DevOps team you probably shouldn't be working with Kubernetes. Despite that, in some cases a DevOps engineer might not be available while we're debugging an issue. For these situations and for general familiarity we should still familiarize ourselves with common Kubernetes issues to bridge the gap between development and operations. I think this also provides an important skill that helps us understand the work of DevOps better, with that understanding we can improve as a cohesive team. This guide explores prevalent Kubernetes errors and provides troubleshooting tips to help developers navigate the complex landscape of container orchestration.&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/Q3cy8i4tsyQ"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;As a side note, if you like the content of this and the other posts in this series check out my &lt;a href="https://www.amazon.com/dp/1484290410/" rel="noopener noreferrer"&gt;Debugging book&lt;/a&gt; that covers &lt;strong&gt;t&lt;/strong&gt;his subject. If you have friends that are learning to code I'd appreciate a reference to my &lt;a href="https://www.amazon.com/Java-Basics-Practical-Introduction-Full-Stack-ebook/dp/B0CCPGZ8W1/" rel="noopener noreferrer"&gt;Java Basics book.&lt;/a&gt; If you want to get back to Java after a while check out my &lt;a href="https://www.amazon.com/Java-21-Explore-cutting-edge-features/dp/9355513925/" rel="noopener noreferrer"&gt;Java 8 to 21 book&lt;/a&gt;&lt;strong&gt;.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Identifying Configuration Issues
&lt;/h2&gt;

&lt;p&gt;When you encounter configuration issues in Kubernetes, the first place to check is the status column using the &lt;code&gt;kubectl get pods&lt;/code&gt; command. Common errors manifest here, requiring further inspection with &lt;code&gt;kubectl describe pod&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;kubectl get pods
NAME                     READY    STATUS     RESTARTS   AGE 
my-first-pod-id-xxxx      1/1     Running    0          13s
my-second-pod-id-xxxx     1/1     Running    0          13s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Common Causes and Solutions
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Insufficient Resources&lt;/strong&gt;: Notice that this means resources for the POD itself and not resources within the container. It means the hardware or surrounding VM is hitting a limit.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Symptom&lt;/strong&gt;: Pods fail to schedule due to resource constraints.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution&lt;/strong&gt;: Scale up the cluster by adding more nodes to accommodate the resource requirements.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Volume Mounting Failures&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Symptom&lt;/strong&gt;: Pods cannot mount volumes correctly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution&lt;/strong&gt;: Ensure storage is defined accurately in the pod specification and check the storage class and Persistent Volume (PV) configurations.&lt;/p&gt;

&lt;h3&gt;
  
  
  Detailed Investigation Steps
&lt;/h3&gt;

&lt;p&gt;We can use &lt;code&gt;kubectl describe pod&lt;/code&gt;: This command provides a detailed description of the pod, including events that have occurred. By examining these events, we can pinpoint the exact cause of the issue.&lt;/p&gt;

&lt;p&gt;Another important step is resource quota analysis. Sometimes, resource constraints are due to namespace-level resource quotas. Use &lt;code&gt;kubectl get resourcequotas&lt;/code&gt; to check if quotas are limiting pod creation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Dealing with Image Pull Errors
&lt;/h2&gt;

&lt;p&gt;Errors like &lt;code&gt;ErrImagePull&lt;/code&gt; or &lt;code&gt;ImagePullBackOff&lt;/code&gt; indicate issues with fetching container images. These errors are typically related to image availability or access permissions.&lt;/p&gt;

&lt;h3&gt;
  
  
  Troubleshooting Steps
&lt;/h3&gt;

&lt;p&gt;The first step is checking the image name which we can do with the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker pull &amp;lt;image-name&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We then need to verify the image name for typos or invalid characters. I pipe the command through grep to verify the name is 100% identical, some typos are just notoriously hard to spot.&lt;/p&gt;

&lt;p&gt;Credentials can also be a major pitfall. E.g. an authorization failure when pulling images from private repositories.&lt;/p&gt;

&lt;p&gt;We must ensure that Docker registry credentials are correctly configured in Kubernetes secrets.&lt;/p&gt;

&lt;p&gt;Network configuration should also be reviewed. Ensure that the Kubernetes nodes have network access to the Docker registry. Network policies or firewall rules might block access.&lt;/p&gt;

&lt;p&gt;There are quite a few additional pitfalls such as problems with image tags. Ensure you are using the correct image tags. Latest tags might not always point to the expected image version.&lt;/p&gt;

&lt;p&gt;If you're using a private registry you might be experiencing access issues. Make sure your credentials are up-to-date and the registry is accessible from all nodes in all regions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Handling Node Issues
&lt;/h2&gt;

&lt;p&gt;Node-related errors often point to physical or virtual machine issues. These issues can disrupt the normal operation of the Kubernetes cluster and need prompt attention.&lt;/p&gt;

&lt;p&gt;To check node status use the command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get nodes
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can then identify problematic nodes in the resulting output.&lt;/p&gt;

&lt;p&gt;It's a cliché but sometimes rebooting nodes is the best solution to some problems. We can reboot the affected machine or VM. Kubernetes should attempt to "self-heal" and recover within a few minutes.&lt;/p&gt;

&lt;p&gt;To investigate node conditions we can use the command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl describe node &amp;lt;node-name&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We should look for conditions such as &lt;code&gt;MemoryPressure&lt;/code&gt;, &lt;code&gt;DiskPressure&lt;/code&gt;, or &lt;code&gt;NetworkUnavailable&lt;/code&gt;. These conditions provide clues about the underlying issue we should address in the node.&lt;/p&gt;

&lt;h3&gt;
  
  
  Preventive Measures
&lt;/h3&gt;

&lt;p&gt;Node monitoring should be used to with tools such as Prometheus, Grafana to keep an eye on node health and performance. These work great for the low level Kubernetes related issues, we can also use them for high level application issues.&lt;/p&gt;

&lt;p&gt;There are some automated healing tools such as the Kubernetes Cluster Autoscaler that we can leverage to automatically manage the number of nodes in your cluster based on workload demands. Personally, I'm not a huge fan as I'm afraid of a cascading failure that would trigger additional resource consumption.&lt;/p&gt;

&lt;h2&gt;
  
  
  Managing Missing Configuration Keys or Secrets
&lt;/h2&gt;

&lt;p&gt;Missing configuration keys or secrets are common issues that disrupt Kubernetes deployments. Proper management of these elements is crucial for smooth operation.&lt;/p&gt;

&lt;p&gt;We need to use ConfigMaps and secrets. These let us store configuration values and sensitive information securely. To avoid that we need to ensure that ConfigMaps and Secrets are correctly referenced in your pod specifications.&lt;/p&gt;

&lt;p&gt;Inspect pod descriptions using the command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl describe pod &amp;lt;pod-name&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Review the output and look for missing configuration details. Rectify any misconfigurations.&lt;/p&gt;

&lt;p&gt;ConfigMap and secret creation can be verified using the command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get configmaps
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get secrets
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ensure that the required ConfigMaps and Secrets exist in the namespace and contain the expected data.&lt;/p&gt;

&lt;p&gt;It's best to keep non-sensitive parts of ConfigMaps in version control while excluding Secrets for security. Furthermore, you should use different ConfigMaps and Secrets for different environments (development, staging, production) to avoid configuration leaks.&lt;/p&gt;

&lt;h2&gt;
  
  
  Utilizing Buildg for Interactive Debugging
&lt;/h2&gt;

&lt;p&gt;Buildg is a relatively new tool that enhances the debugging process for Docker configurations by allowing interactive debugging.&lt;/p&gt;

&lt;p&gt;It provides Interactive Debugging for configuration issues in a way that's similar to a standard debugging. It lets us step through the &lt;code&gt;Dockerfile&lt;/code&gt; stages and set breakpoints. Buildg is compatible with VSCode and other IDEs via the Debug Adapter Protocol (DAP).&lt;/p&gt;

&lt;p&gt;Buildg lets us inspect container state at each stage of the build process to identify issues early.&lt;/p&gt;

&lt;p&gt;To install buildg follow the instructions on the &lt;a href="https://github.com/ktock/buildg" rel="noopener noreferrer"&gt;Buildg GitHub page&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9vdkbc50gxi643htwb0j.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9vdkbc50gxi643htwb0j.png" width="800" height="513"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Debugging Kubernetes can be challenging, but with the right knowledge and tools, developers can effectively identify and resolve common issues. By understanding configuration problems, image pull errors, node issues, and the importance of ConfigMaps and Secrets, developers can contribute to more robust and reliable Kubernetes deployments. Tools like Buildg offer promising advancements in interactive debugging, further bridging the gap between development and operations.&lt;/p&gt;

&lt;p&gt;As Kubernetes continues to evolve, staying informed about new tools and best practices will be essential for successful application management and deployment. By proactively addressing these common issues, developers can ensure smoother, more efficient Kubernetes operations, ultimately leading to more resilient and scalable applications.&lt;/p&gt;

</description>
      <category>kubernetes</category>
      <category>devops</category>
      <category>development</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Why is Kubernetes Debugging so Problematic?</title>
      <dc:creator>Shai Almog</dc:creator>
      <pubDate>Tue, 04 Jun 2024 15:15:04 +0000</pubDate>
      <link>https://dev.to/codenameone/why-is-kubernetes-debugging-so-problematic-4feo</link>
      <guid>https://dev.to/codenameone/why-is-kubernetes-debugging-so-problematic-4feo</guid>
      <description>&lt;ul&gt;
&lt;li&gt;The Immutable Nature of Containers&lt;/li&gt;
&lt;li&gt;The Limitations of &lt;code&gt;kubectl exec&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Avoiding Direct Modifications&lt;/li&gt;
&lt;li&gt;
Enter Ephemeral Containers

&lt;ul&gt;
&lt;li&gt;Using &lt;code&gt;kubectl debug&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Practical Application of Ephemeral Containers&lt;/li&gt;

&lt;li&gt;Security Considerations&lt;/li&gt;

&lt;li&gt;Interlude: The Role of Observability&lt;/li&gt;

&lt;li&gt;Command Line Debugging&lt;/li&gt;

&lt;li&gt;Connecting a Standard IDE for Remote Debugging&lt;/li&gt;

&lt;li&gt;Conclusion&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;Debugging application issues in a Kubernetes cluster can often feel like navigating a labyrinth. Containers are ephemeral by design, intended to be immutable once deployed. This presents a unique challenge when something goes wrong and we need to dig into the issue. Before diving into the debugging tools and techniques, it's essential to grasp the core problem: why modifying container instances directly is a bad idea. This blog post will walk you through the intricacies of Kubernetes debugging, offering insights and practical tips to effectively troubleshoot your Kubernetes environment.&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/xkOekt02mNY"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;As a side note, if you like the content of this and the other posts in this series check out my &lt;a href="https://www.amazon.com/dp/1484290410/" rel="noopener noreferrer"&gt;Debugging book&lt;/a&gt; that covers &lt;strong&gt;t&lt;/strong&gt;his subject. If you have friends that are learning to code I'd appreciate a reference to my &lt;a href="https://www.amazon.com/Java-Basics-Practical-Introduction-Full-Stack-ebook/dp/B0CCPGZ8W1/" rel="noopener noreferrer"&gt;Java Basics book.&lt;/a&gt; If you want to get back to Java after a while check out my &lt;a href="https://www.amazon.com/Java-21-Explore-cutting-edge-features/dp/9355513925/" rel="noopener noreferrer"&gt;Java 8 to 21 book&lt;/a&gt;&lt;strong&gt;.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  The Immutable Nature of Containers
&lt;/h3&gt;

&lt;p&gt;One of the fundamental principles of Kubernetes is the immutability of container instances. This means that once a container is running, it shouldn't be altered. Modifying containers on the fly can lead to inconsistencies and unpredictable behavior, especially as Kubernetes orchestrates the lifecycle of these containers, replacing them as needed. Imagine trying to diagnose an issue only to realize that the container you’re investigating has been modified, making it difficult to reproduce the problem consistently.&lt;/p&gt;

&lt;p&gt;The idea behind this immutability is to ensure that every instance of a container is identical to any other instance. This consistency is crucial for achieving reliable, scalable applications. If you start modifying containers, you undermine this consistency, leading to a situation where one container behaves differently from another, even though they are supposed to be identical.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Limitations of &lt;code&gt;kubectl exec&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;We often start our journey in Kubernetes with commands such as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;kubectl &lt;span class="nt"&gt;--&lt;/span&gt; &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-ti&lt;/span&gt; &amp;lt;pod-name&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This logs into a container and feels like accessing a traditional server with SSH. However, this approach has significant limitations. Containers often lack basic diagnostic tools—no &lt;code&gt;vim&lt;/code&gt;, no &lt;code&gt;traceroute&lt;/code&gt;, sometimes not even a shell. This can be a rude awakening for those accustomed to a full-featured Linux environment. Additionally, if a container crashes, &lt;code&gt;kubectl exec&lt;/code&gt; becomes useless as there's no running instance to connect to. This tool is insufficient for thorough debugging, especially in production environments.&lt;/p&gt;

&lt;p&gt;Consider the frustration of logging into a container only to find out that you can't even open a simple text editor to check configuration files. This lack of basic tools means that you are often left with very few options for diagnosing problems. Moreover, the minimalistic nature of many container images, designed to reduce their attack surface and footprint, exacerbates this issue.&lt;/p&gt;

&lt;h3&gt;
  
  
  Avoiding Direct Modifications
&lt;/h3&gt;

&lt;p&gt;While it might be tempting to install missing tools on-the-fly using commands like &lt;code&gt;apt-get install vim&lt;/code&gt;, this practice violates the principle of container immutability. In production, installing packages dynamically can introduce new dependencies, potentially causing application failures. The risks are high, and it's crucial to maintain the integrity of your deployment manifests, ensuring that all configurations are predefined and reproducible.&lt;/p&gt;

&lt;p&gt;Imagine a scenario where a quick fix in production involves installing a missing package. This might solve the immediate problem but could lead to unforeseen consequences. Dependencies introduced by the new package might conflict with existing ones, leading to application instability. Moreover, this approach makes it challenging to reproduce the exact environment, which is vital for debugging and scaling your application.&lt;/p&gt;

&lt;h3&gt;
  
  
  Enter Ephemeral Containers
&lt;/h3&gt;

&lt;p&gt;The solution to the aforementioned problems lies in ephemeral containers. Kubernetes allows the creation of these temporary containers within the same pod as the application container you need to debug. These ephemeral containers are isolated from the main application, ensuring that any modifications or tools installed do not impact the running application.&lt;/p&gt;

&lt;p&gt;Ephemeral containers provide a way to bypass the limitations of &lt;code&gt;kubectl exec&lt;/code&gt; without violating the principles of immutability and consistency. By launching a separate container within the same pod, you can inspect and diagnose the application container without altering its state. This approach preserves the integrity of the production environment while giving you the tools you need to debug effectively.&lt;/p&gt;

&lt;h4&gt;
  
  
  Using &lt;code&gt;kubectl debug&lt;/code&gt;
&lt;/h4&gt;

&lt;p&gt;The &lt;code&gt;kubectl debug&lt;/code&gt; command is a powerful tool that simplifies the creation of ephemeral containers. Unlike &lt;code&gt;kubectl exec&lt;/code&gt;, which logs into the existing container, &lt;code&gt;kubectl debug&lt;/code&gt; creates a new container within the same namespace. This container can run a different OS, mount the application container’s filesystem, and provide all necessary debugging tools without altering the application’s state. This method ensures you can inspect and diagnose issues even if the original container is not operational.&lt;/p&gt;

&lt;p&gt;For example, let’s consider a scenario where we’re debugging a container using an ephemeral Ubuntu container:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl debug &amp;lt;myapp&amp;gt; &lt;span class="nt"&gt;-it&lt;/span&gt; &amp;lt;pod-name&amp;gt; &lt;span class="nt"&gt;--image&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;ubuntu &lt;span class="nt"&gt;--share-process&lt;/span&gt; &lt;span class="nt"&gt;--copy-to&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;lt;myapp-debug&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command launches a new Ubuntu-based container within the same pod, providing a full-fledged environment to diagnose the application container. Even if the original container lacks a shell or crashes, the ephemeral container remains operational, allowing you to perform necessary checks and install tools as needed. It relies on the fact that we can have multiple containers in the same pod, that way we can inspect the filesystem of the debugged container without physically entering that container.&lt;/p&gt;

&lt;h3&gt;
  
  
  Practical Application of Ephemeral Containers
&lt;/h3&gt;

&lt;p&gt;To illustrate, let’s delve deeper into how ephemeral containers can be used in real-world scenarios. Suppose you have a container that consistently crashes due to a mysterious issue. By deploying an ephemeral container with a comprehensive set of debugging tools, you can monitor the logs, inspect the filesystem, and trace processes without worrying about the constraints of the original container environment.&lt;/p&gt;

&lt;p&gt;For instance, you might encounter a situation where an application container crashes due to an unhandled exception. By using &lt;code&gt;kubectl debug&lt;/code&gt;, you can create an ephemeral container that shares the same network namespace as the original container. This allows you to capture network traffic and analyze it to understand if there are any issues related to connectivity or data corruption.&lt;/p&gt;

&lt;h3&gt;
  
  
  Security Considerations
&lt;/h3&gt;

&lt;p&gt;While ephemeral containers reduce the risk of impacting the production environment, they still pose security risks. It’s critical to restrict access to debugging tools and ensure that only authorized personnel can deploy ephemeral containers. Treat access to these systems with the same caution as handing over the keys to your infrastructure.&lt;/p&gt;

&lt;p&gt;Ephemeral containers, by their nature, can access sensitive information within the pod. Therefore, it is essential to enforce strict access controls and audit logs to track who is deploying these containers and what actions are being taken. This ensures that the debugging process does not introduce new vulnerabilities or expose sensitive data.&lt;/p&gt;

&lt;h3&gt;
  
  
  Interlude: The Role of Observability
&lt;/h3&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/bRnOGb7rUV4"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;While tools like &lt;code&gt;kubectl exec&lt;/code&gt; and &lt;code&gt;kubectl debug&lt;/code&gt; are invaluable for troubleshooting, they are not replacements for comprehensive observability solutions. Observability allows you to monitor, trace, and log the behavior of your applications in real-time, providing deeper insights into issues without the need for intrusive debugging sessions.&lt;/p&gt;

&lt;p&gt;These tools aren't meant for everyday debugging, that role should be occupied by various observability tools. I will discuss observability in more detail in an upcoming post.&lt;/p&gt;

&lt;h3&gt;
  
  
  Command Line Debugging
&lt;/h3&gt;

&lt;p&gt;While tools like &lt;code&gt;kubectl exec&lt;/code&gt; and &lt;code&gt;kubectl debug&lt;/code&gt; are invaluable, there are times when you need to dive deep into the application code itself. This is where we can use command line debuggers. Command line debuggers allow you to inspect the state of your application at a very granular level, stepping through code, setting breakpoints, and examining variable states. Personally, I don't use them much&lt;/p&gt;

&lt;p&gt;For instance, Java developers can use &lt;code&gt;jdb&lt;/code&gt;, the Java Debugger, which is analogous to &lt;code&gt;gdb&lt;/code&gt; for C/C++ programs. Here’s a basic rundown of how you might use &lt;code&gt;jdb&lt;/code&gt; in a Kubernetes environment:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Set Up Debugging&lt;/strong&gt;: First, you need to start your Java application with debugging enabled. This typically involves adding a debug flag to your Java command. However, as discussed in &lt;a href="https://debugagent.com/mastering-jhsdb-the-hidden-gem-for-debugging-jvm-issues" rel="noopener noreferrer"&gt;my post here&lt;/a&gt;, there's an even more powerful way that doesn't require a restart:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;java &lt;span class="nt"&gt;-agentlib&lt;/span&gt;:jdwp&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;transport&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;dt_socket,server&lt;span class="o"&gt;=&lt;/span&gt;y,suspend&lt;span class="o"&gt;=&lt;/span&gt;n,address&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;*&lt;/span&gt;:5005 &lt;span class="nt"&gt;-jar&lt;/span&gt; myapp.jar
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Port Forwarding&lt;/strong&gt;: Since the debugger needs to connect to the application, you’ll set up port forwarding to expose the debug port of your pod to your local machine. This is important as &lt;a href="https://debugagent.com/remote-debugging-dangers-and-pitfalls" rel="noopener noreferrer"&gt;JDWP is dangerous&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl port-forward &amp;lt;pod-name&amp;gt; 5005:5005
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Connecting the Debugger&lt;/strong&gt;: With port forwarding in place, you can now connect &lt;code&gt;jdb&lt;/code&gt; to the remote application:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;jdb &lt;span class="nt"&gt;-attach&lt;/span&gt; localhost:5005
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;From here, you can use &lt;code&gt;jdb&lt;/code&gt; commands to set breakpoints, step through code, and inspect variables. This process allows you to debug issues within the code itself, which can be invaluable for diagnosing complex problems that aren’t immediately apparent through logs or superficial inspection.&lt;/p&gt;

&lt;h3&gt;
  
  
  Connecting a Standard IDE for Remote Debugging
&lt;/h3&gt;

&lt;p&gt;I prefer IDE debugging by far. I never used JDB for anything other than a demo. Modern IDEs support remote debugging, and by leveraging Kubernetes port forwarding, you can connect your IDE directly to a running application inside a pod.&lt;/p&gt;

&lt;p&gt;To set up remote debugging we start with the same steps as the command line debugging. Configuring the application and setting up the port forwarding.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Configure the IDE&lt;/strong&gt;: In your IDE (e.g., IntelliJ IDEA, Eclipse), set up a remote debugging configuration. Specify the host as &lt;a href="http://localhost" rel="noopener noreferrer"&gt;&lt;code&gt;localhost&lt;/code&gt;&lt;/a&gt; and the port as &lt;code&gt;5005&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Start Debugging&lt;/strong&gt;: Launch the remote debugging session in your IDE. You can now set breakpoints, step through code, and inspect variables directly within the IDE, just as if you were debugging a local application.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I show how to do it in IntelliJ/IDEA &lt;a href="https://debugagent.com/remote-debugging-dangers-and-pitfalls" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;Debugging Kubernetes environments requires a blend of traditional techniques and modern tools designed for container orchestration. Understanding the limitations of &lt;code&gt;kubectl exec&lt;/code&gt; and the benefits of ephemeral containers can significantly enhance your troubleshooting process. However, the ultimate goal should be to build robust observability into your applications, reducing the need for ad-hoc debugging and enabling proactive issue detection and resolution.&lt;/p&gt;

&lt;p&gt;By following these guidelines and leveraging the right tools, you can navigate the complexities of Kubernetes debugging with confidence and precision. In the next installment of this series, we’ll delve into common configuration issues in Kubernetes and how to address them effectively.&lt;/p&gt;

</description>
      <category>kubernetes</category>
      <category>devops</category>
      <category>tutorial</category>
      <category>java</category>
    </item>
  </channel>
</rss>
