<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="4.4.1">Jekyll</generator><link href="https://masilotti.com/feed.xml" rel="self" type="application/atom+xml" /><link href="https://masilotti.com/" rel="alternate" type="text/html" /><updated>2026-07-13T10:10:30+00:00</updated><id>https://masilotti.com/feed.xml</id><title type="html">Masilotti.com</title><author><name>Joe Masilotti</name><email>joe@masilotti.com</email></author><entry><title type="html">I’ve spent 10+ years helping Rails devs reach the App Store. Today, someone shipped without me.</title><link href="https://masilotti.com/shipped-without-me/" rel="alternate" type="text/html" title="I’ve spent 10+ years helping Rails devs reach the App Store. Today, someone shipped without me." /><published>2026-05-05T00:00:00+00:00</published><updated>2026-05-05T00:00:00+00:00</updated><id>https://masilotti.com/shipped-without-me</id><content type="html" xml:base="https://masilotti.com/shipped-without-me/"><![CDATA[<p>The first time I helped a Rails team get an iOS app into TestFlight, I was sure the hard part would be the code. The team had a polished Rails app, a real product, and paying customers. We just needed to put it in front of people on their phones. How hard could the wrapper be?</p>

<p>Hard enough that I built a career around it.</p>

<p>That was almost ten years ago. Since then I’ve shipped more than 25 mobile apps for Rails businesses, <a href="https://pragprog.com/titles/jmnative/hotwire-native-for-rails-developers/">written a book on it</a>, and trained hundreds of developers in workshops, livestreams, and office hours. The teams keep changing. But the wall doesn’t.</p>

<p>And the wall isn’t Rails!</p>

<p>Rails developers are usually delighted by how much of their existing app works inside a Hotwire Native shell. Their forms, their auth, their navigation, their styling: most of it just runs. The wall is everything that happens once the web app is humming and somebody asks the question that always comes next.</p>

<p>“How do we get this into the app stores?”</p>

<p>Then the <em>real</em> pain starts. Apple Developer Program enrollment, provisioning profiles, signing certificates, app identifiers, capabilities, push notification keys, a privacy manifest, a build number that has to be bumped <em>just so</em>. An archive in Xcode that fails the first three times for reasons that will not be Googleable. A TestFlight upload that disappears and comes back with a single-line rejection.</p>

<p>For someone who lives in Rails, that gauntlet is alien. It’s not that any one step is impossible. It’s that every step is its own small adventure, and the adventures compound. By the time you’re staring at App Store Connect trying to figure out which of nine tabs the rejection came from, you’ve forgotten you were supposed to be shipping a feature.</p>

<p>I’ve walked teams through this so many times that I started keeping notes on the order I do it in. The notes turned into a book chapter, the chapter turned into a workshop, the workshop turned into a paid newsletter. Underneath all of it was the same uncomfortable observation. I was getting good at a thing that, ideally, nobody should have to be good at.</p>

<p>So I started building <a href="https://rubynative.com">Ruby Native</a>.</p>

<p>The pitch is simple, even if the work was not. You should be able to write Ruby, run a command, and end up with a real iOS app on a real device, without ever opening Xcode. Not “without writing Swift,” which Hotwire Native already gave us. <strong>Without Xcode at all.</strong> There are no project files to manage, no signing dialogs to fight, and no manual archive step. The infrastructure Apple insists on is still there, of course. It just isn’t yours to operate.</p>

<p>I posted a teaser on Substack on February 11, the kind of post that promises something is coming and then quietly hopes anyone cares. Somebody named Ender left a two-word comment.</p>

<blockquote>
  <p>Wow. Looking forward.</p>
</blockquote>

<p>Ender Ahmet Yurt is a Rails developer in Turkey. We had never spoken. I had no way of knowing whether “looking forward” meant he’d open the next email or whether his comment would scroll off into the void with everybody else’s. I replied and went to sleep.</p>

<p>Yesterday I officially launched Ruby Native.</p>

<p>Today, Ender shipped <a href="https://apps.apple.com/tr/app/foxance/id6763144327">Foxance</a> to the App Store.</p>

<figure class="not-prose w-full md:max-w-lg rounded-2xl bg-gray-50 p-6 leading-6 flex flex-col justify-between my-8 mx-auto">
  <blockquote class="text-gray-900">
    <p>“I started with Hotwire Native, then tried plain Swift. Both took too long. Ruby Native got me from zero to TestFlight <strong>in a day</strong>.”</p>
  </blockquote>
  <figcaption class="mt-4 flex items-center text-sm gap-x-4">
    
      <img class="h-10 w-10 rounded-full bg-gray-50" src="/assets/images/testimonials/ender-ahmet-yurt.jpg" alt="Ender Ahmet Yurt" />
    
    <div>
      <div class="font-semibold text-gray-900">Ender Ahmet Yurt</div>
      <div class="text-gray-600">Software Engineer</div>
    </div>
  </figcaption>
</figure>

<p>He never opened Xcode. He’s never met me. He lives on a different continent, in a different time zone, and he turned a Rails app into a real app on real iPhones in less time than it usually takes me to debug a missing entitlement. <strong>Foxance is the first customer app shipped on top of Ruby Native.</strong> I had nothing to do with the app itself. I only built the path.</p>

<h2 id="what-this-actually-changes">What this actually changes</h2>

<p>For most of the last decade, the way a Rails business closed the gap between the web app and the App Store was to hire someone like me, or to spend several months becoming someone like me. There was no shortage of talented Rails developers who wanted to ship to the App Store. <strong>There was a shortage of patience for the path that got them there.</strong></p>

<p>That gate sets a price, a timeline, and a <em>confidence</em> floor that keeps a lot of perfectly good Rails businesses out of the stores entirely. “Should we have a mobile app?” turns into “do we have the budget and runway to learn a whole second discipline?” and the question quietly answers itself.</p>

<p>If a Rails developer in Turkey can take an app from working-on-the-web to live-on-the-store in the days after a launch announcement, the gate is lower than it used to be. Not gone. The App Store still has rules and review and rejections, and there will always be room for people who have been through that grinder before. But the part that was about Xcode is, finally, somebody else’s problem.</p>

<p>I’ll keep helping Rails teams ship mobile apps. <a href="https://masilotti.com/services/">That’s still what I do.</a> But for the first time the question I get to ask isn’t “are you ready to commit to the ramp?” It’s “do you want your app in the store next month <em>or next week</em>?”</p>

<p>Ten years of closing this gap, and the headline I get to write today is the one I never could before.</p>

<p>Somebody shipped without me.</p>]]></content><author><name>Joe Masilotti</name><email>joe@masilotti.com</email></author><summary type="html"><![CDATA[Yesterday Ruby Native launched. Today the first customer app went live. And the developer never opened Xcode.]]></summary></entry><entry><title type="html">The Rails developers’ guide to mobile app frameworks</title><link href="https://masilotti.com/rails-developers-guide-to-mobile-app-frameworks/" rel="alternate" type="text/html" title="The Rails developers’ guide to mobile app frameworks" /><published>2026-02-12T00:00:00+00:00</published><updated>2026-02-12T00:00:00+00:00</updated><id>https://masilotti.com/rails-developers-guide-to-mobile-app-frameworks</id><content type="html" xml:base="https://masilotti.com/rails-developers-guide-to-mobile-app-frameworks/"><![CDATA[<p>You have a Rails app. Your users want a mobile app. And now you’re staring down a handful of options, each with different tradeoffs.</p>

<p>This isn’t a “just make it responsive” situation. You want an actual app in the App Store and Google Play (or at least you’re considering it). So, which framework do you pick?</p>

<p>I’ve helped dozens of teams make this exact decision and <a href="/services/">shipped 25+ mobile apps backed by Rails</a>. Here’s how I walk through the decision for each of my clients.</p>

<h2 id="the-four-real-options">The four real options</h2>

<p>There are four paths worth seriously considering for a Rails team. Each one trades off development speed, native feel, and long-term maintenance differently.</p>

<h3 id="native-swift-and-kotlin">Native (Swift and Kotlin)</h3>

<p>Building fully native apps means writing separate <a href="https://developer.apple.com/ios/">iOS</a> and <a href="https://developer.android.com">Android</a> codebases in Swift and Kotlin, on top of your existing Rails app. You get full control over every pixel and every interaction. <strong>Fully native Swift and Kotlin apps feel <em>incredible</em>.</strong></p>

<p>But you’re building everything <em>three times</em>. Every screen, every flow, and every feature needs an iOS version, an Android version, and the web version you already have. And if your Rails frontend is HTML-based (e.g. ERB, Hotwire, Turbo), you’ll also need to build a JSON API to power those native screens. That means new features can require work in <em>four</em> places: the data model, the API, the iOS UI, and the Android UI.</p>

<p>You will most likely need dedicated mobile developers (or need to become one) and you’re maintaining three codebases indefinitely. For most Rails teams, this is the most expensive option by a wide margin.</p>

<h3 id="react-native">React Native</h3>

<p><a href="https://reactnative.dev">React Native</a> lets you write one JavaScript codebase that runs on both iOS and Android. It’s backed by Meta, has a massive ecosystem, and produces apps that feel close to native.</p>

<p><strong>You never have to open Xcode or Android Studio with React Native.</strong> You write code in your editor of choice, run a command, and see the result in a device simulator. The developer ergonomics are quite good once you’re up and running. Though getting to that point can be its own adventure. Setting up React Native projects is notoriously finicky, not unlike the React ecosystem on the web.</p>

<p>React Native also has a large plugin ecosystem for adding native features like cameras, maps, and biometrics. But if you need something custom that doesn’t have a plugin, you’re writing native modules in Swift or Kotlin anyway. And now you’re fighting against the abstraction layer rather than working with the platform directly. It can end up being more work than just building the feature natively.</p>

<p>Here’s the catch for Rails teams: it’s still a completely separate codebase. You’re building a new frontend in React, creating an API layer to talk to your Rails backend, and duplicating logic. And despite the name, React web and React Native are different enough that you can’t share frontend code between them. You’re pretty much building the frontend twice.</p>

<h3 id="pwa-progressive-web-app">PWA (Progressive Web App)</h3>

<p>A <a href="https://developer.mozilla.org/en-US/docs/Web/Progressive_web_apps">Progressive Web App</a> skips the app stores entirely. Your Rails app runs in the browser, and users can “install” it to their home screen. <strong>It has zero native toolchain overhead and the lowest development cost.</strong></p>

<p>The tradeoffs are real, though. No in-app purchases, limited push notification support on iOS, and no presence in the app stores. You lose discoverability and the legitimacy that comes with being downloadable. And honestly, it’s quite rare for anyone to actually click “Add to Home Screen.” Or even know where to find it.</p>

<p>That said, if you don’t need the app stores, a PWA lets you move fast with the fewest constraints.</p>

<h3 id="hotwire-native">Hotwire Native</h3>

<p><a href="https://native.hotwired.dev">Hotwire Native</a> wraps your existing Rails app in a native shell. Your HTML from the server gets rendered inside native navigation, so your Rails views <em>are</em> the mobile app. All of the business logic stays in one place: your Rails server. <strong>When you deploy a new feature or fix a bug, you change your Rails code and the apps update in real time.</strong> No app store review required.</p>

<p>When you need native features like push notifications, camera access, or biometrics, you add them with <a href="/bridge-components/">bridge components</a> that connect your HTML to native code. And you can always “drop down to native” for fully custom screens when the situation calls for it.</p>

<p>I wrote an entire <a href="https://pragprog.com/titles/jmnative/hotwire-native-for-rails-developers/">book on this approach</a>. <strong>It’s also how 37signals builds Basecamp, HEY Email, and HEY Calendar, serving millions of paying customers across iOS and Android.</strong> These aren’t toy apps. They’re revenue-generating products built and maintained by a small team, because Hotwire Native lets them keep most of the work on the server.</p>

<p>The big tradeoff: you’re managing Xcode and Android Studio projects directly, and you’ll need to write a bit of Swift and Kotlin. But the amount of native code stays small because most of the work, and the core logic, stays on the server.</p>

<p>One thing to be aware of is that Hotwire Native doesn’t currently have offline support. Your app needs a network connection to load screens. This may be <a href="https://newsletter.masilotti.com/p/offline-mode-for-hotwire-native-apps">changing soon</a>, but for now, if your users need to work without connectivity, this is a real limitation.</p>

<p>If this sounds like your situation, my <a href="/hotwire-native/">complete guide to Hotwire Native</a> covers what it is, how it works, and how to ship your first app.</p>

<h2 id="how-they-compare">How they compare</h2>

<p>Here’s a side-by-side to make the tradeoffs concrete:</p>

<table>
  <thead>
    <tr>
      <th> </th>
      <th>Native</th>
      <th>React Native</th>
      <th>PWA</th>
      <th>Hotwire Native</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Timeline</td>
      <td>6-12+ months</td>
      <td>4-8 months</td>
      <td>1 week</td>
      <td>1-2 months</td>
    </tr>
    <tr>
      <td>Codebases</td>
      <td>3</td>
      <td>2</td>
      <td>1</td>
      <td>1 + 2 small<sup><a href="#footnote-1">1</a></sup></td>
    </tr>
    <tr>
      <td>Teams needed</td>
      <td>iOS, Android, and Rails</td>
      <td>React Native and Rails</td>
      <td>Rails</td>
      <td>Rails</td>
    </tr>
    <tr>
      <td>Learning curve</td>
      <td>Steep</td>
      <td>Moderate</td>
      <td>None</td>
      <td>Low</td>
    </tr>
    <tr>
      <td>Offline support</td>
      <td>Full</td>
      <td>Full</td>
      <td>Partial</td>
      <td>None</td>
    </tr>
    <tr>
      <td>Native feel</td>
      <td>Full</td>
      <td>Full</td>
      <td>Minimal</td>
      <td>Mostly</td>
    </tr>
    <tr>
      <td>App Store presence</td>
      <td>Yes</td>
      <td>Yes</td>
      <td>No</td>
      <td>Yes</td>
    </tr>
    <tr>
      <td>Native API access</td>
      <td>Full</td>
      <td>Full</td>
      <td>Limited</td>
      <td>Full</td>
    </tr>
  </tbody>
</table>

<p><sup id="footnote-1">1</sup>Hotwire Native technically has three codebases, but the iOS and Android projects are thin wrappers. Most of your development time stays in Rails.</p>

<p>The “teams needed” row is the biggest differentiator for most businesses: Hotwire Native and PWAs are the only options where your existing Rails developers can do the work.</p>

<h2 id="when-to-pick-each">When to pick each</h2>

<h3 id="pick-fully-native-if">Pick fully native if…</h3>

<p>The mobile app <em>is</em> your product, not a companion to a web app. You need heavy offline support, you have or can hire dedicated iOS and Android developers, and budget and timeline aren’t major constraints. If all four of those are true, native will give you the best possible experience.</p>

<h3 id="pick-react-native-if">Pick React Native if…</h3>

<p>Your team is already using React on the web and you have an API layer built. The JavaScript knowledge transfers and you’re not starting from scratch. But if your frontend is server-rendered Rails (e.g. ERB, Hotwire, Turbo), adopting React Native means building an entirely new frontend skill set on top of the framework itself.</p>

<h3 id="pick-a-pwa-if">Pick a PWA if…</h3>

<p>You don’t need the app stores. Your app is primarily content or information display, push notifications on iOS aren’t important, and budget is tight. A PWA is the fastest path to “mobile app” when the stores aren’t a requirement.</p>

<h3 id="pick-hotwire-native-if">Pick Hotwire Native if…</h3>

<p>You have a working Rails app with real users and you want to get into the app stores in weeks, not months. You don’t have mobile developers and don’t want to hire them. You want one codebase powering the majority of web, iOS, and Android. If that sounds like your situation, <a href="https://pragprog.com/titles/jmnative/hotwire-native-for-rails-developers/">my book</a> will walk you through building it yourself, or I can <a href="/services/mobile-playbook/">help you plan the right approach</a>.</p>

<h2 id="what-about-flutter-and-capacitor">What about Flutter and Capacitor?</h2>

<p>Two other frameworks come up in these conversations. Here’s the short version.</p>

<p><strong>Flutter</strong> is Google’s cross-platform framework using Dart. It has a custom rendering engine and produces pixel-perfect apps across platforms. But it requires learning a new language, building a completely separate codebase, and creating new APIs. There’s minimal code reuse with your Rails app. If your app is mobile-first and Rails is just the API, Flutter is worth considering. But for a Rails business <em>adding</em> mobile? It’s overkill.</p>

<p><strong>Capacitor</strong> wraps a web app in a native shell with a plugin bridge for native APIs. It’s designed for JavaScript SPAs (React, Vue, Angular) bundled into the native binary and has good offline support since assets ship locally. But if you’re using server-rendered Rails, Capacitor creates a mismatch. You’d either build a redundant JS frontend or use their officially unsupported server mode. It’s a good tool for JavaScript teams, not a natural fit for Rails developers.</p>

<h2 id="still-not-sure-which-framework-to-choose">Still not sure which framework to choose?</h2>

<p>The right answer depends on your team, your timeline, and what your users actually need. There’s no universal “best framework,” just the one that fits your situation.</p>

<p>If you’d rather have someone help you figure out the right approach before writing any code, take a look at the <a href="/services/mobile-playbook/">Mobile Playbook</a>. In two weeks you’ll have a framework recommendation, architecture diagram, risk register, and a phased build plan.</p>

<p>And if you just want to follow along as I share what I’m learning, <a href="https://newsletter.masilotti.com">my weekly newsletter</a> covers building mobile apps for Rails businesses.</p>]]></content><author><name>Joe Masilotti</name><email>joe@masilotti.com</email></author><summary type="html"><![CDATA[Understand the benefits and tradeoffs of native, React Native, PWAs, and Hotwire Native.]]></summary></entry><entry><title type="html">Hotwire Native at Rails World</title><link href="https://masilotti.com/hotwire-native-at-rails-world/" rel="alternate" type="text/html" title="Hotwire Native at Rails World" /><published>2025-08-21T00:00:00+00:00</published><updated>2025-08-21T00:00:00+00:00</updated><id>https://masilotti.com/hotwire-native-at-rails-world</id><content type="html" xml:base="https://masilotti.com/hotwire-native-at-rails-world/"><![CDATA[<p>Hey everyone,</p>

<p>Can you believe Rails World is so soon? Exactly two weeks from today I’ll be on stage delivering my talk on Hotwire Native.</p>

<p>But the most exciting part? <strong>My talk was upgraded to a keynote!</strong></p>

<p><img src="/assets/images/newsletter/rails-world-keynote-announcement.jpeg" alt="Rails World keynote announcement" /></p>

<p>I’m excited and grateful to The Rails Foundation for giving me this opportunity. But I’d be lying if I said I wasn’t nervous. 🙈</p>

<p>As a tiny sneak peek, here’s one of my favorite slides from my deck so far. Just look at all of these apps built with Hotwire Native! They are all in the App Store and/or Google Play.</p>

<p><img src="/assets/images/newsletter/app-icons.png" alt="Hotwire Native app icons" /></p>

<p>If you’re attending Rails World then come say hi - I’d love to meet in person.</p>

<hr />

<h2 id="from-masilotticom">From Masilotti.com</h2>

<p>Since the last newsletter, I’ve been busy with two projects I’m excited to share.</p>

<h3 id="ruby-friends-android-app">🤖 <a href="https://play.google.com/store/apps/details?id=com.masilotti.rubyfriends&amp;hl=en_US">Ruby Friends Android app</a></h3>

<p><a href="https://rubyfriends.app">Ruby Friends</a> is now on Android! The app makes it easy to connect at conferences without the awkward “what’s your Twitter?” moment. Just set up a profile, scan someone’s code, and you’ll have a real connection to revisit later - long after the hallway track ends.</p>

<h3 id="hotwire-native-modals">🎥 <a href="https://youtu.be/Sy1WYXlvDJ4">Hotwire Native Modals</a></h3>

<p>Want your Hotwire Native apps to feel smoother? I published a 5 minute video showing how to make web-based modals behave like real native screens on iOS and android. No clunky overlays or awkward transitions - just fast, polished interactions that blend right in with the rest of your app.</p>

<hr />

<h2 id="hotwire-native-around-the-web">Hotwire Native around the web</h2>

<p>Here’s a few articles and announcements about Hotwire Native that caught my eye.</p>

<h3 id="action-native-push">📲 <a href="https://dev.37signals.com/introducing-action-native-push/">Action Native Push</a></h3>

<p>37signals released a new gem for sending iOS and Android push notifications. It connects directly to APNS and FCM, and takes care of retries, rate limiting, and cleaning up inactive devices automatically. If your app only needs to send push notifications, this looks like a compact, focused dependency. For broader notification management, check out <a href="https://github.com/excid3/noticed">Noticed</a>.</p>

<h3 id="turbo-adapter-hotwire-natives-backdoor-entrance">🚪 <a href="https://radanskoric.com/articles/turbo-adapter-hotwire-native-backdoor-entrance">Turbo adapter: Hotwire Native’s backdoor entrance</a></h3>

<blockquote>
  <p>TL;DR: Hotwire Native injects a piece of JavaScript that integrates with the Turbo already present on the web and makes it talk to native mobile code.</p>
</blockquote>

<p>This deep dive explains the magic behind how Hotwire Native bridges the web and native worlds. Essential reading for anyone looking to understand the underlying architecture.</p>

<h3 id="the-rails-world-2025-app-is-back-now-native--built-by-the-community">👩‍💻 <a href="https://www.teloslabs.co/post/the-rails-world-2025-app-is-back">The Rails World 2025 App is Back: Now Native &amp; Built by the Community</a></h3>

<p>Rails World 2025’s official app is back and better than ever. The open source <a href="https://github.com/TelosLabs/conference-ios-app">iOS</a> and <a href="https://github.com/TelosLabs/conference-android-app">Android</a> conference app has been upgraded to Rails 8 and powered by Hotwire Native, delivering native experiences while still running as a progressive web app on desktop and mobile.</p>

<h3 id="️a-bridge-component-in-action">🖨️ <a href="https://x.com/RobStortelder/status/1955648412520509819">A bridge component in action</a></h3>

<p>Rob Stortelder shared a demo triggering an Epson printer to spit out a receipt. Since most browsers prohibit requests to a local network, bridge components were the key to making it work seamlessly.</p>

<hr />

<p>There’s so much exciting work happening in the Hotwire Native world right now, from new gems to open source apps to creative bridge components!</p>

<p>Again, if you’re heading to Rails World this year, I’d love to connect in person. If you see me around, don’t hesitate to come say hi.</p>]]></content><author><name>Joe Masilotti</name><email>joe@masilotti.com</email></author><summary type="html"><![CDATA[Hotwire Native takes the Rails World 2025 keynote stage, plus updates on Ruby Friends for Android, native-feeling modals, and community projects.]]></summary></entry><entry><title type="html">RailsConf workshop recording and Ruby Friends v1.2</title><link href="https://masilotti.com/railsconf-workshop-recording/" rel="alternate" type="text/html" title="RailsConf workshop recording and Ruby Friends v1.2" /><published>2025-07-31T00:00:00+00:00</published><updated>2025-07-31T00:00:00+00:00</updated><id>https://masilotti.com/railsconf-workshop-recording</id><content type="html" xml:base="https://masilotti.com/railsconf-workshop-recording/"><![CDATA[<p>Hey everyone, how’s your week going?</p>

<p>Last night we took the boys to dinner at a local family-friendly brewery. And it was <em>glorious</em>.</p>

<p>Why don’t more places like this exist?! Crayons, french fries, a play area, beer… it’s a busy parent’s dream!</p>

<figure>
  <img src="/assets/images/newsletter/joe-with-kids-at-brewery.jpeg" alt="Joe with his boys at a family-friendly brewery" />
  <figcaption>Joe with his boys at a family-friendly brewery</figcaption>
</figure>

<h2 id="railsconf-workshop-recording">RailsConf workshop recording</h2>

<p>If you missed my Hotwire Native workshop at RailsConf then don’t fret, the <a href="https://youtu.be/gIOkC44_dA8">recording is now on YouTube</a>. When you finish working through it then hit reply and show me what you built!</p>

<iframe class="w-full aspect-video" src="https://www.youtube-nocookie.com/embed/gIOkC44_dA8" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen=""></iframe>

<p>Ruby Central also uploaded recordings of the rest of the <a href="https://www.youtube.com/playlist?list=PLbHJudTY1K0fOQPBF0uTwFIGuMVEKnV1p">talks and workshops</a>. I’m excited to catch up on these talks that I missed while in Philadelphia:</p>

<ul>
  <li><a href="https://youtu.be/4JiNCgPn5HY">Validating non-model classes with…ActiveModel? by Andy Andrea</a></li>
  <li><a href="https://youtu.be/MVHfdblm7uU">Cache = Cash! 2.0 by Stefan Wintermeyer</a></li>
  <li><a href="https://youtu.be/HMqbBno22_s">An ActiveRecord Rewrite: the Story Behind the Attributes API by Tess Griffin</a></li>
</ul>

<p>When I got back from the conference, I finally recorded a Hotwire Native video I’d been excited to make for a while.</p>

<h2 id="add-a-native-button-to-your-hotwire-native-app">Add a native button to your Hotwire Native app</h2>

<p>This 5 minute tutorial walks you through how to copy and paste a ready-made bridge component from my open-source library. No Swift or Kotlin required!</p>

<iframe class="w-full aspect-video" src="https://www.youtube-nocookie.com/embed/HMMkYi2_ZNk" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen=""></iframe>

<p>I’m thinking about doing a short video like this for each component. Would that be helpful?</p>

<p>Speaking of bridge components, I used the <a href="https://github.com/joemasilotti/bridge-components/tree/main/components/barcode-scanner">Barcode Scanner</a> and <a href="https://github.com/joemasilotti/bridge-components/tree/main/components/notification-token">Notification Token</a> components for the latest iOS release of Ruby Friends!</p>

<h2 id="ruby-friends-v12">Ruby Friends v1.2</h2>

<p><a href="https://rubyfriends.app">Ruby Friends</a>, a fun little app to help you keep in touch with folks you meet at conferences, just hit v1.2 on iOS.</p>

<p>This release includes a <em>ton</em> of new native features:</p>

<ul>
  <li><strong>QR code scanning</strong> with a native bridge component</li>
  <li><strong>Push notifications</strong> when someone adds you as a friend</li>
  <li><strong>Universal Links</strong> to jump into the app from emails and messages</li>
  <li><strong>Apple Wallet support</strong> with <em>Add to Wallet</em> integration</li>
  <li><strong>Mastodon</strong> profile links</li>
</ul>

<p>I’m also working on an NFC integration. This would enable tapping a NFC tag and deep linking right to a profile… even if the app isn’t running! I have a proof-of-concept working and just need to iron out some bugs.</p>

<figure class="unstyled">
  <img src="/assets/images/newsletter/ruby-friends-nfc-scan.png" alt="The Ruby Friends iOS app reading an NFC tag" />
  <figcaption>The Ruby Friends iOS app reading an NFC tag</figcaption>
</figure>

<p>There’s probably a generic component that I can extract from this and add to my <a href="https://bridgecomponents.dev">bridge component library</a>, too.</p>

<p>Want to give it a try? Hit reply and I’ll add you to the TestFlight group.</p>

<p>Until next time, folks!</p>]]></content><author><name>Joe Masilotti</name><email>joe@masilotti.com</email></author><summary type="html"><![CDATA[Hotwire Native workshop recording, new bridge component tutorial, and Ruby Friends v1.2 with QR scanning, Universal Links, push, and Wallet integration.]]></summary></entry><entry><title type="html">Ruby Friends is in the App Store!</title><link href="https://masilotti.com/ruby-friends-in-the-app-store/" rel="alternate" type="text/html" title="Ruby Friends is in the App Store!" /><published>2025-07-23T00:00:00+00:00</published><updated>2025-07-23T00:00:00+00:00</updated><id>https://masilotti.com/ruby-friends-in-the-app-store</id><content type="html" xml:base="https://masilotti.com/ruby-friends-in-the-app-store/"><![CDATA[<p>12 days after the first commit, Ruby Friends is officially live in the <a href="https://apps.apple.com/us/app/ruby-friends/id6748887042">App Store</a>!</p>

<p><a href="https://apps.apple.com/us/app/ruby-friends/id6748887042"><img src="/assets/images/newsletter/download-on-the-app-store.png" alt="" /></a></p>

<p>What’s Ruby Friends? Dave Thomas sums it up nicely in his <a href="https://media.pragprog.com/newsletters/2025-07-17.html">latest newsletter</a>:</p>

<blockquote>
  <p>You create a profile, and it gives you a URL and a QR code. When you chat with people [at a conference or meetup], they can scan your code to see your profile, and if they want to, they can add you as a friend. And that’s it. No posts, no transitive-closures of connections; just you and a list of people who wanted you to remember them.</p>
</blockquote>

<p>Think of it like a conference companion that helps turn introductions into friendships. I’ve been building it in public on <a href="https://www.youtube.com/@joemasilotti">my YouTube channel</a>.</p>

<h2 id="100-profiles-in-48-hours-now-250-and-counting">100 profiles in 48 hours… now 250 and counting</h2>

<p>This blew me away.</p>

<p>Within 48 hours of launch, Ruby Friends hit 100 profiles.</p>

<p>Lucky profile #100? <a href="https://rubyfriends.app/profiles/FFCZ">Erin</a> - congrats and thanks for being part of this!</p>

<p>Since then, we’ve more than doubled that. As of writing, there are over 250 Ruby Friends using the app. That means more than 250 chances to meet someone new, start a conversation, and reconnect later.</p>

<figure>
  <img src="/assets/images/newsletter/ruby-friends-admin.png" alt="Ruby Friends admin screen" />
  <figcaption>Ruby Friends admin screen</figcaption>
</figure>

<h2 id="a-peek-at-the-app">A peek at the app</h2>

<p>Here’s a quick look at what’s live in v1.0:</p>

<figure class="unstyled">
  <img src="/assets/images/newsletter/ruby-friends-app.png" alt="Ruby Friends app" />
  <figcaption>Ruby Friends app</figcaption>
</figure>

<p>You can create your profile, add other Ruby Friends, and manage your notifications. Super simple - and super early. But it’s already working. Up next? Push notifications, of course!</p>

<h2 id="building-it-live">Building it live</h2>

<p>If you missed it, I started building the iOS app live on stream. We covered:</p>

<ul>
  <li>Spinning up the iOS app from scratch</li>
  <li>Adding a native tab bar</li>
  <li>Wiring up the sign-in flow with Hotwire Native</li>
</ul>

<p>You can <a href="https://www.youtube.com/live/UuONfuzjTfA?si=8xo5nb4xcfVbhlg7">watch the full session here</a>.</p>

<p>At first, I tried configuring the tabs after the user signed in. It worked… kind of. But it felt messy. So I tossed it and found something better: swapping the <code class="language-plaintext highlighter-rouge">rootViewController</code> once the user creates a profile.</p>

<p>At a high level, here’s what my <code class="language-plaintext highlighter-rouge">SceneDelegate</code> is doing. It renders a single <code class="language-plaintext highlighter-rouge">Navigator</code> on every app launch.</p>

<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">class</span> <span class="kt">SceneDelegate</span><span class="p">:</span> <span class="kt">UIResponder</span><span class="p">,</span> <span class="kt">UIWindowSceneDelegate</span> <span class="p">{</span>
    <span class="kd">private</span> <span class="k">let</span> <span class="nv">navigator</span> <span class="o">=</span> <span class="kt">Navigator</span><span class="p">()</span>
    <span class="kd">private</span> <span class="k">let</span> <span class="nv">tabBarController</span> <span class="o">=</span> <span class="kt">HotwireTabBarController</span><span class="p">()</span>

    <span class="kd">func</span> <span class="nf">scene</span><span class="p">(</span><span class="n">_</span> <span class="nv">scene</span><span class="p">:</span> <span class="kt">UIScene</span><span class="p">,</span> <span class="n">willConnectTo</span> <span class="nv">session</span><span class="p">:</span> <span class="kt">UISceneSession</span> <span class="o">...</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">window</span><span class="p">?</span><span class="o">.</span><span class="n">rootViewController</span> <span class="o">=</span> <span class="n">navigator</span><span class="o">.</span><span class="n">rootViewController</span>
        <span class="n">navigator</span><span class="o">.</span><span class="nf">start</span><span class="p">()</span>
    <span class="p">}</span>

    <span class="kd">private</span> <span class="kd">func</span> <span class="nf">didSignIn</span><span class="p">()</span> <span class="p">{</span>
        <span class="k">if</span> <span class="n">window</span><span class="p">?</span><span class="o">.</span><span class="n">rootViewController</span> <span class="o">!=</span> <span class="n">tabBarController</span> <span class="p">{</span>
            <span class="n">window</span><span class="p">?</span><span class="o">.</span><span class="n">rootViewController</span> <span class="o">=</span> <span class="n">tabBarController</span>
        <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>And when the user signs in, a bridge component swaps out the <code class="language-plaintext highlighter-rouge">rootViewController</code> to the tab bar controller.</p>

<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">class</span> <span class="kt">AuthenticationComponent</span><span class="p">:</span> <span class="kt">BridgeComponent</span> <span class="p">{</span>
    <span class="k">override</span> <span class="kd">func</span> <span class="nf">onReceive</span><span class="p">(</span><span class="nv">message</span><span class="p">:</span> <span class="kt">Message</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">guard</span> <span class="k">let</span> <span class="nv">data</span><span class="p">:</span> <span class="kt">MessageData</span> <span class="o">=</span> <span class="n">message</span><span class="o">.</span><span class="nf">data</span><span class="p">()</span> <span class="k">else</span> <span class="p">{</span> <span class="k">return</span> <span class="p">}</span>

        <span class="k">if</span> <span class="n">data</span><span class="o">.</span><span class="n">profileURL</span> <span class="o">!=</span> <span class="kc">nil</span> <span class="p">{</span>
            <span class="kt">SceneController</span><span class="o">.</span><span class="nf">didSignIn</span><span class="p">()</span>
        <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>I’ll dive into that code in the next stream, tomorrow (Thursday). Come say hi!</p>

<iframe class="w-full aspect-video" src="https://www.youtube-nocookie.com/embed/i8-1nWPc_OA" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen=""></iframe>

<hr />

<p>That’s it for this week.</p>

<p>If you haven’t already, <a href="https://apps.apple.com/us/app/ruby-friends/id6748887042">download Ruby Friends from the App Store</a>, create a profile, and meet a new Ruby Friend. Or two. Or five.</p>

<p>And if you’re enjoying it, forward this to someone you think might like it too. The more the merrier.</p>

<p>P.S. If you’re organizing a Ruby conference, then let me know! Maybe we can get some Ruby Friends QR codes printed on the badges.</p>]]></content><author><name>Joe Masilotti</name><email>joe@masilotti.com</email></author><summary type="html"><![CDATA[250+ Rubyists have already joined. Want to make a new friend next time you say "hello world"?]]></summary></entry><entry><title type="html">RailsConf inspired me to build something new</title><link href="https://masilotti.com/inspired-by-railsconf/" rel="alternate" type="text/html" title="RailsConf inspired me to build something new" /><published>2025-07-15T00:00:00+00:00</published><updated>2025-07-15T00:00:00+00:00</updated><id>https://masilotti.com/inspired-by-railsconf</id><content type="html" xml:base="https://masilotti.com/inspired-by-railsconf/"><![CDATA[<p>Last week I attended the last RailsConf ever. A bittersweet moment, since the conference has been such an integral part of the Ruby community for the last 20 years.</p>

<p>But the 800+ attendees brought an energy I’ve never seen before at a code-related meetup. And it was infectious. So much so, that I too decided to build something new. More on that below. 😉</p>

<h2 id="the-hallway-track">The hallway track</h2>

<figure>
  <img src="/assets/images/inspired-by-railsconf/tiny-notebook.jpeg" alt="Small notebook, big ideas" />
  <figcaption>Small notebook, big ideas</figcaption>
</figure>

<p>Over the three days in Philadelphia I kept track of everyone I spoke with on my tiny little notebook. Here are some of the conversations that stood out.</p>

<ul>
  <li><a href="https://adrianthedev.com">Adrian Marin</a> – We talked about the challenge of pricing developer-focused tools. His work on <a href="https://avohq.io">Avo</a> gave me a lot of ideas for how to improve the team licensing model for <a href="/bridge-components/">Bridge Components</a>. I walked away thinking I should make it easier to buy for teams and double down on screencasts.</li>
  <li><a href="https://www.linkedin.com/in/camilacsouza/">Camila</a> and <a href="https://www.linkedin.com/in/eduardogsouza/">Eduardo</a> Souza – Easily one of the highlights of the conference. Camila launched a production-ready iOS app <strong>in just two weeks</strong> after reading my book - with no prior Swift or Kotlin experience. I loved hearing about how it went live in the App Store and their experience going all-in on Hotwire Native.</li>
  <li><a href="https://andyatkinson.com">Andy Atkinson</a> – Like myself, Andy is also a consultant and Pragmatic Bookshelf author (<a href="https://andyatkinson.com/pgrailsbook">High Performance PostgreSQL for Rails</a>). We jammed on an idea for a book club that would meet weekly for two months or so. It could be a great way to combine our love of writing with our consulting businesses. We also swapped tips on how to promote our books and find new clients.</li>
</ul>

<h2 id="teaching-hotwire-native-at-railsconf">Teaching Hotwire Native at RailsConf</h2>

<figure>
  <img src="/assets/images/inspired-by-railsconf/workshop.jpeg" alt="Joe Masilotti presents at RailsConf 2025" />
  <figcaption>Joe Masilotti presents at RailsConf 2025</figcaption>
</figure>

<p>On Wednesday I hosted a two-hour workshop teaching Hotwire Native from scratch. Every seat was full and folks were sitting on the floor! Together we:</p>

<ul>
  <li>Took a plain old Rails app and brought it to iOS and Android</li>
  <li>Added native tab navigation</li>
  <li>Built a custom iOS bridge component</li>
</ul>

<p>I also forgot how to delete a record in Rails. 😪 Luckily, the audience helped me out.</p>

<p>As promised, here’s links to the <a href="/slides/railsconf-2025/">slides</a> and all of the <a href="https://github.com/joemasilotti/railsconf-2025-code">code</a> we wrote together.</p>

<h2 id="talks-that-sparked-new-ideas">Talks that sparked new ideas</h2>

<figure>
  <img src="/assets/images/inspired-by-railsconf/authn-vs-authz.jpeg" alt="AuthN vs. AuthZ slide from Alicia Rojas talk at RailsConf 2025" />
  <figcaption>AuthN vs. AuthZ slide from Alicia Rojas talk at RailsConf 2025</figcaption>
</figure>

<p>RailsConf wasn’t just socializing and teaching. I also learned a ton from the talks. Here are two that really stuck out.</p>

<h3 id="unraveling-the-black-box-past-present-and-future-of-authentication-in-rails">Unraveling The Black Box: Past, Present And Future Of Authentication In Rails</h3>

<p>Alicia Rojas gave the clearest explanation I’ve ever heard of the difference between authentication and authorization. If you’ve ever confused AuthN with AuthZ, here’s a definitive answer.</p>

<h3 id="the-future-of-pwas-on-rails">The Future Of: PWAs On Rails</h3>

<p>Edy Silva’s talk lit a fire under me. As I watched, I wondered: <em>could I get this working in a Hotwire Native app?</em> After the talk I opened my laptop and two hours later had offline access working natively. I’ll share a full write-up soon - this could be <em>huge</em> for Hotwire Native.</p>

<h2 id="announcing-ruby-friends">Announcing: Ruby Friends</h2>

<figure class="max-w-sm">
  <img src="/assets/images/inspired-by-railsconf/favorite-part-of-railsconf.jpeg" alt="What is your favorite part of RailsConf?" />
  <figcaption>What is your favorite part of RailsConf?</figcaption>
</figure>

<p>One thing I heard over and over again at RailsConf: “I love meeting people at conferences, but I always forget who I talked to once I get home.”</p>

<p>Same here. So I’m building something new: <a href="https://rubyfriends.app">RubyFriends.app</a></p>

<p>It’s a simple site (and soon-to-be app) that helps you:</p>

<ul>
  <li>Meet someone new at a Ruby event</li>
  <li>Spark a real conversation</li>
  <li>Reconnect later</li>
</ul>

<p>Think of it like a conference companion that helps turn introductions into friendships. I’m building it in public and starting development of the Hotwire Native app this week.</p>

<p>This Thursday at 11am PT I’ll be live coding the Hotwire Native integration on YouTube. Come hang out, ask questions, and see how it all comes together.</p>

<iframe class="w-full aspect-video" src="https://www.youtube-nocookie.com/embed/UuONfuzjTfA" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen=""></iframe>

<h2 id="what-are-you-building">What are you building?</h2>

<p>RailsConf left me feeling fired up and full of ideas. I’m grateful to everyone I talked to and learned from last week.</p>

<p>Now I want to hear from you: <strong>What are you building next?</strong></p>

<p>Reply to this email and let me know - I’d love to check it out!</p>]]></content><author><name>Joe Masilotti</name><email>joe@masilotti.com</email></author><summary type="html"><![CDATA[Reflecting on RailsConf chats, building Ruby Friends, and learning new things in the Ruby community!]]></summary></entry><entry><title type="html">Hotwire Native at RailsConf</title><link href="https://masilotti.com/hotwire-native-at-railsconf/" rel="alternate" type="text/html" title="Hotwire Native at RailsConf" /><published>2025-07-07T00:00:00+00:00</published><updated>2025-07-07T00:00:00+00:00</updated><id>https://masilotti.com/hotwire-native-at-railsconf</id><content type="html" xml:base="https://masilotti.com/hotwire-native-at-railsconf/"><![CDATA[<p>Hey y’all, who’s going to be at RailsConf this week?</p>

<p>I’m hosting a <a href="/slides/railsconf-2025/">Hotwire Native workshop on Wednesday at 10:15am</a>. And I’d love to see you there!</p>

<p>During this two-hour session, you’ll build an iOS and Android app from scratch. You’ll learn the essentials, practical tips, and common pitfalls of building maintainable Hotwire Native apps.</p>

<p>And the best part? Zero Swift or Kotlin experience is required!</p>

<p>A thin wrapper for each platform enables continuous updates by only making changes to your Rails codebase. Deploy your code, and all three platforms get your changes immediately.</p>

<figure>
  <img src="/assets/images/newsletter/railsconf-workshop.png" alt="Hotwire Native workshop at RailsConf 2025" />
  <figcaption>Hotwire Native workshop at RailsConf 2025</figcaption>
</figure>

<p>Before you attend, be sure your development environment is set up. You’ll need:</p>

<ul>
  <li>macOS</li>
  <li>Ruby 3.4 (or higher)</li>
  <li>Xcode 16 (<em>not</em> Xcode 26)</li>
  <li>Android Studio Meerkat (or later)</li>
  <li>SQLite 3.8 (or higher)</li>
</ul>

<p>And make sure to clone <a href="https://github.com/joemasilotti/hotwire-native-blog-demo">this Rails demo app</a> and run the quick start via <code class="language-plaintext highlighter-rouge">bin/setup</code>.</p>

<p>Hit reply or <a href="mailto:joe@masilotti.com">send me an email</a> if you run into any issues.</p>

<h2 id="meet-the-authors">Meet the Authors</h2>

<p>Later that day I’ll also be at the Meet the Authors table at 3pm.</p>

<p>This is a great opportunity to get more information on my book, <a href="https://pragprog.com/titles/jmnative/hotwire-native-for-rails-developers/"><em>Hotwire Native for Rails Developers</em></a>, and pick my brain.</p>

<p>I’ll also be giving out event-exclusive discount codes and running a book giveaway.</p>

<figure class="max-w-sm">
  <img src="/assets/images/newsletter/meet-the-authors-timetable.png" alt="Meet the Authors timetable" />
  <figcaption>Meet the Authors timetable</figcaption>
</figure>

<p>If you’re attending RailsConf, let me know - I’d love to connect!</p>]]></content><author><name>Joe Masilotti</name><email>joe@masilotti.com</email></author><summary type="html"><![CDATA[Join me at RailsConf for a Hotwire Native workshop and a book meet-up later!]]></summary></entry><entry><title type="html">Hotwire Native v1.2.x and Hotwire Native LIVE #4</title><link href="https://masilotti.com/hotwire-native-v1.2.x/" rel="alternate" type="text/html" title="Hotwire Native v1.2.x and Hotwire Native LIVE #4" /><published>2025-06-25T00:00:00+00:00</published><updated>2025-06-25T00:00:00+00:00</updated><id>https://masilotti.com/hotwire-native-v1.2.x</id><content type="html" xml:base="https://masilotti.com/hotwire-native-v1.2.x/"><![CDATA[<p>Hey folks, everyone getting ready for RailsConf? Can you believe it is only two weeks away!</p>

<p>I just wrapped up the slides for the workshop I’m running on Wednesday. Attendees will build Hotwire Native apps on iOS and Android from scratch, including a native tab bar and bridge component.</p>

<p>You’ll walk away from the workshop with a solid foundation on how to bring your own Rails app to mobile.</p>

<p>If you’re heading to the conference please say hello! I’d love to meet you IRL.</p>

<h2 id="hotwire-native-v12x-released">Hotwire Native v1.2.x released</h2>

<p>Hotwire Native saw two patch releases this week with v1.2.1 on iOS and v1.2.3 on Android.</p>

<p>This is the first time the different platforms diverged on releases. Here’s what’s included in each.</p>

<h3 id="android">Android</h3>

<p>Earlier this month Android received two patch releases with <a href="https://github.com/hotwired/hotwire-native-android/releases/tag/1.2.1">v1.2.1</a> and <a href="https://github.com/hotwired/hotwire-native-android/releases/tag/1.2.2">v1.2.2</a>. Both of these updated under-the-hood infrastructure. From a developer’s perspective, nothing actually changed but the version number.</p>

<p><strong>It’s safe to ignore these and go right to <a href="https://github.com/hotwired/hotwire-native-android/releases/tag/1.2.3">v1.2.3</a></strong>, which adds two new features:</p>

<ol>
  <li><a href="https://github.com/hotwired/hotwire-native-android/pull/148">PR #148</a>: If you’ve ever seen a 406 error then you’ll appreciate this one. Out-of-date Android clients will now see a more descriptive error message if the underlying web browser is out of date.</li>
  <li><a href="https://github.com/hotwired/hotwire-native-android/pull/149">PR #149</a>: This adds a way to show/hide the first-party tab bar programatically. While already included by default on iOS, we now have feature parity between the two platforms. I’m working on a <code class="language-plaintext highlighter-rouge">TabBarComponent</code> for my <a href="/bridge-components/">bridge component library</a> to take advantage of this. Stay tuned!</li>
</ol>

<h3 id="ios">iOS</h3>

<p>iOS’s sole release with <a href="https://github.com/hotwired/hotwire-native-ios/releases/tag/1.2.1">v1.2.1</a> fixed some tests in <a href="https://github.com/hotwired/hotwire-native-ios/pull/131">PR #131</a> and restored support for running the demo app on iOS 15 in <a href="https://github.com/hotwired/hotwire-native-ios/pull/128">PR #128</a>.</p>

<p>But most importantly it added a new path configuration property, <code class="language-plaintext highlighter-rouge">queryStringPresentation</code>, to match behavior on Android.</p>

<p>Set this to <code class="language-plaintext highlighter-rouge">"replace"</code> and navigating between URLs where <em>only the query string changes</em> will replace the current screen on the stack (instead of pushing a new one).</p>

<p>This is mostly helpful for web-based tabs that require roundtrips to the server. However, it does <em>not</em> fix the flickering issue outlined in <a href="https://github.com/hotwired/hotwire-native-ios/issues/53">#53</a>. Hopefully we can get that fixed soon!</p>

<h2 id="tomorrow-hotwire-native-live---route-decision-handlers">Tomorrow: Hotwire Native LIVE - Route Decision Handlers</h2>

<p>While reviewing through the code on these releases I realized I still haven’t used the new <a href="https://github.com/hotwired/hotwire-native-ios/blob/main/Source/Turbo/Navigator/Routing/RouteDecisionHandler.swift">Route Decision Handlers</a> on iOS. These were brought over from Android in <a href="https://github.com/hotwired/hotwire-native-ios/releases/tag/1.2.0">v1.2.0</a>.</p>

<p>We can use these to customize behavior when navigating between URLs. Think “external URL handlers” but on steroids.</p>

<p>I’m exploring how to use these tomorrow (Thursday)! Join me for <a href="https://youtube.com/live/t6niKGnKJQs">episode #4 of Hotwire Native LIVE</a>. And please, bring your questions - I’ll dedicate time at the end for Q&amp;A.</p>

<iframe class="w-full aspect-video" src="https://www.youtube-nocookie.com/embed/t6niKGnKJQs" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen=""></iframe>

<p>I hope to see you there.</p>]]></content><author><name>Joe Masilotti</name><email>joe@masilotti.com</email></author><summary type="html"><![CDATA[A quick update on the latest Hotwire Native releases and a countdown to RailsConf.]]></summary></entry><entry><title type="html">iOS 26, Hotwire Native LIVE #3, and a new bridge component</title><link href="https://masilotti.com/ios-26/" rel="alternate" type="text/html" title="iOS 26, Hotwire Native LIVE #3, and a new bridge component" /><published>2025-06-12T00:00:00+00:00</published><updated>2025-06-12T00:00:00+00:00</updated><id>https://masilotti.com/ios-26</id><content type="html" xml:base="https://masilotti.com/ios-26/"><![CDATA[<p>Hey folks! How’s your week going so far?</p>

<p>In case you missed it, <a href="https://www.apple.com/newsroom/2025/06/apple-elevates-the-iphone-experience-with-ios-26/">Apple announced iOS 26</a> at WWDC on Monday. And with it comes a brand new design, <em>Liquid Glass</em>.</p>

<blockquote>
  <p>This translucent material reflects and refracts its surroundings, while dynamically transforming to help bring greater focus to content, delivering a new level of vitality across controls, navigation, app icons, widgets, and more. For the very first time, the new design extends across platforms — iOS 26, iPadOS 26, macOS Tahoe 26, watchOS 26, and tvOS 261 — to establish even more harmony while maintaining the distinct qualities that make each unique.</p>
</blockquote>

<figure>
  <img src="/assets/images/newsletter/ios26.png" alt="iOS 26 showing off Liquid Glass" />
  <figcaption>iOS 26 showing off Liquid Glass</figcaption>
</figure>

<p>This week I’m exploring what this means for Hotwire Native developers. Short answer: I think we are in <em>very</em> good shape.</p>

<p>Unlike other hybrid platforms that rebuild every single element to match the system UI (React Native), Hotwire Native apps rely on using the first-party components directly.</p>

<p>To demonstrate, when working through my <a href="https://pragprog.com/titles/jmnative/hotwire-native-for-rails-developers/">book on Hotwire Native</a>, you build an app to track hikes. Here’s what it looks like when running on iOS 26.</p>

<figure class="unstyled">
  <img src="/assets/images/newsletter/hiking-journal-ios26.png" alt="Hiking Journal running on iOS 26" />
  <figcaption>Hiking Journal running on iOS 26</figcaption>
</figure>

<p><strong>This required zero code changes.</strong> And we get all of the new design from Liquid Glass. For free!</p>

<p>I’ll be exploring this and the new SwiftUI WebKit API in an upcoming video on <a href="https://www.youtube.com/@joemasilotti">my YouTube channel</a> later this month.</p>

<p>And speaking of YouTube…</p>

<h2 id="hotwire-native-live-3">Hotwire Native LIVE #3</h2>

<p>Join me today (Thursday) at 11am PT / 1 pm ET for <a href="https://youtube.com/live/xHbYIsfbYzY">episode #3 of Hotwire Native LIVE</a>.</p>

<p>This week we’re covering <strong>debugging</strong>: enabling Hotwire Native’s logging, attaching a browser for inspecting JavaScript, and figuring out cryptic IDE messages.</p>

<p>And as always, I’ve dedicated time at the end for Q&amp;A so you can get real-time feedback and troubleshooting help. Come say hi!</p>

<iframe class="w-full aspect-video" src="https://www.youtube-nocookie.com/embed/xHbYIsfbYzY" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen=""></iframe>

<h2 id="new-bridge-component-and-marketing-site">New bridge component and marketing site</h2>

<p>This week I also extracted a new bridge component from a client’s app. The free <a href="https://github.com/joemasilotti/bridge-components/tree/main/components/theme">Theme Component</a> helps keep the system UI in sync with your web-based design.</p>

<figure class="unstyled">
  <img src="/assets/images/newsletter/theme-component.png" alt="Theme Component example screenshots" />
  <figcaption>Theme Component example screenshots</figcaption>
</figure>

<p>And to celebrate, I’ve also created a real <a href="https://masilotti.com/bridge-components/">marketing page</a> for the component library!</p>

<p>If you’ve used the library and would like to add a testimonial then please let me know. I’d love to include your quote or company logo on the page for social proof.</p>

<p>That’s all for this week - hopefully I’ll see you at the live stream!</p>

<p>Talk soon,</p>]]></content><author><name>Joe Masilotti</name><email>joe@masilotti.com</email></author><summary type="html"><![CDATA[Apple's iOS 26 debuts Liquid Glass, enhancing Hotwire Native apps with no code changes required!]]></summary></entry><entry><title type="html">Book sale, Hotwire Native LIVE #2, and Hotwire Native around the web</title><link href="https://masilotti.com/book-sale-and-hotwire-native-live-episode-2/" rel="alternate" type="text/html" title="Book sale, Hotwire Native LIVE #2, and Hotwire Native around the web" /><published>2025-06-03T00:00:00+00:00</published><updated>2025-06-03T00:00:00+00:00</updated><id>https://masilotti.com/book-sale-and-hotwire-native-live-episode-2</id><content type="html" xml:base="https://masilotti.com/book-sale-and-hotwire-native-live-episode-2/"><![CDATA[<p>Hey folks! Can you believe it’s June already? The summer has officially begun in Portland. I mean, just look at that forecast. 😍</p>

<figure>
  <img src="/assets/images/newsletter/portland-weather-forecast.png" alt="Weather forecast of Portland, OR for this week showing no rain and perfect sunny weather." />
  <figcaption>Weather forecast of Portland, OR for this week showing no rain and perfect sunny weather.</figcaption>
</figure>

<h2 id="hotwire-native-live">Hotwire Native LIVE</h2>

<p>Last week I ran the first <a href="https://youtube.com/live/oi_dU4GlGwc">Hotwire Native LIVE</a> episode on YouTube. I built an iOS and Android app from scratch and answered 20+ questions from viewers. Between YouTube and Twitter, the recording has already been viewed over 2000 times. 😲</p>

<p>And this week I’m covering <strong>bridge components</strong>: what they are, how to add them to your iOS and Android apps, and examples of components I’ve built for clients. I’d love to see you there!</p>

<iframe class="w-full aspect-video" src="https://www.youtube-nocookie.com/embed/sG0eEjO6l2o" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen=""></iframe>

<h2 id="book-sale">Book sale</h2>

<p>My book’s publisher, Pragmatic Bookshelf, is wrapping up their spring sale. That means you can get my book, along with almost 50 others, for <strong>40% off</strong> until the end of the week.</p>

<p>Use code <code class="language-plaintext highlighter-rouge">SPRING2025</code> on the <a href="https://pragprog.com/titles/jmnative/hotwire-native-for-rails-developers/">Pragmatic Bookshelf website</a> to grab your discount.</p>

<figure>
  <img src="/assets/images/newsletter/prag-prog-spring-sale.png" alt="Pragprog.com 40% off spring sale" />
  <figcaption>Pragprog.com 40% off spring sale</figcaption>
</figure>

<h2 id="hotwire-native-around-the-web">Hotwire Native around the web</h2>

<h3 id="seamless-loading-with-hotwire-native"><a href="https://katalyst.com.au/articles/seamless-loading-hotwire-native-ios">Seamless Loading with Hotwire Native</a></h3>

<p>Stephen and Alan from Katalyst Interactive documented their approach to building a Hotwire Native app with seamless loading on launch. They weren’t satisfied with their iOS app showing the native launch screen then dropping the user directly to a blank page with a spinner.</p>

<blockquote>
  <p>By preloading the web view, detecting when it’s ready, and using a smooth crossfade transition, we made the Hotwire Native app feel truly native.</p>
</blockquote>

<h3 id="custom-android-keyboard-extension"><a href="https://williamkennedy.ninja/hotwire-native/2025/05/23/up-and-running-with-hotwire-native-android-custom-android-keyboard-extension/">Custom Android Keyboard Extension</a></h3>

<p>William Kennedy wrapped up his series on Hotwire Native Android with an article on building a custom keyboard extension. He uses a bridge component to add a native toolbar when a Trix editor is focused. Users can then tap native buttons to toggle bold, italic, and headings.</p>

<blockquote>
  <p>This is a great feature to build if you want to build a markdown editor in your app that’s accessible via mobile.</p>
</blockquote>

<p>Until next time, everyone!</p>]]></content><author><name>Joe Masilotti</name><email>joe@masilotti.com</email></author><summary type="html"><![CDATA[Summer kicks off in Portland with a new Hotwire Native LIVE episode and a book sale!]]></summary></entry></feed>