◉RORK LABJP
●GPT-6.1 SOL — Added to Rork's model menu (09-29) with Low, Medium and High effort; included on Pro and Max●SONNET 5.5 — Claude Sonnet 5.5 is selectable: strong at UI design and faster than Sonnet 5 (09-28)●SONNET 4.5 — Retires on the Claude API on 11/30, 26 days left. If your app calls it, check the migration target●SDK 58 — Moves to React Native 0.88. R8 is now on by default in Android release builds, and iOS prebuild generates a SceneDelegate●OBSERVE — EAS Observe now records native crashes too (SDK 57.0.21 or later, 10/07)●NEW — My App Open Ad Only Showed When the App…●GPT-6.1 SOL — Added to Rork's model menu (09-29) with Low, Medium and High effort; included on Pro and Max●SONNET 5.5 — Claude Sonnet 5.5 is selectable: strong at UI design and faster than Sonnet 5 (09-28)●SONNET 4.5 — Retires on the Claude API on 11/30, 26 days left. If your app calls it, check the migration target●SDK 58 — Moves to React Native 0.88. R8 is now on by default in Android release builds, and iOS prebuild generates a SceneDelegate●OBSERVE — EAS Observe now records native crashes too (SDK 57.0.21 or later, 10/07)●NEW — My App Open Ad Only Showed When the App…
Articles/App Dev
◇ App Dev/2026-06-16Advanced

Building an iMessage Extension with Rork Max to Bring Your App's World into Messages — Notes on Distribution as Code

A walkthrough of adding an iMessage extension to the native Swift project Rork Max generates, sharing your app's assets right inside Messages. Covers compact/expanded presentation, sending messages, and diagnosing why the extension won't appear in the drawer — from an indie developer's distribution lens.

Rork Max235iMessageMessages ExtensionSwift48DistributionApp Extension3

✦ Premium Article

Run an indie wallpaper app long enough and you notice the moment users most naturally recommend it to a friend isn't when they send an App Store link — it's when they drop a favorite image straight into a conversation. If that's true, could I bring the app's world into Messages itself, the very place sharing happens? That question is what led me to build an iMessage extension.

An iMessage extension is a native mechanism that depends on the Messages framework. It's effectively out of reach from React Native, but because Rork Max generates a native Swift project, you can add an extension target and subclass MSMessagesAppViewController. Here I'll work through presentation switching, sending messages, and the pitfalls — all through the lens of distribution.

Why a Messages extension instead of the main app

Send an app pitch as a store link and the recipient has to leave the conversation to open the App Store. An asset sent from an iMessage extension, on the other hand, stays in the conversation, and the recipient can engage with it right there. In my experience, the psychological distance to "maybe I'll try this" is far shorter with the latter. For a free, AdMob-centric app, adding one more entry point is far from trivial.

That said, the extension is a separate target from the main app, and its memory limit is stricter. Loading assets wholesale hits the ceiling fast. Designing for lightness is the starting point.

Step 1: Add the extension target and share assets with the main app

Add an iMessage extension target to the project Rork Max generated. To share assets (like images) with the main app, enable an App Group and read them through the shared container. Carrying images twice inside the extension bloats both the distribution size and memory.

// Resolve an asset URL from the shared container
func sharedAssetURL(_ name: String) -> URL? {
    let groupID = "group.net.rorklab.sample"
    let base = FileManager.default
        .containerURL(forSecurityApplicationGroupIdentifier: groupID)
    return base?.appendingPathComponent("assets/\(name)")
}

The App Group identifier must match exactly between the main app and the extension. A mismatch leaves the asset always nil on the extension side, and you lose time tracking down the cause.

✦

Thank you for reading this far.

Continue Reading

What follows includes implementation code, benchmarks, and practical content we hope you'll find useful. This site runs without ads — server and development costs are supported entirely by members like you. If it's been helpful, we'd be truly grateful for your support.

WHAT YOU'LL LEARN
✦Concrete presentationStyle transition code for switching MSMessagesAppViewController between compact and expanded layouts
✦How to assemble an MSMessage that attaches an asset like a wallpaper, and design how it persists in the recipient's conversation
✦How to diagnose the production symptom of an extension never showing in the Messages drawer, down to target settings and bundle structure
Secure payment via Stripe · Cancel anytime
✦

Unlock This Article

Get full access to the rest of this article. Buy once, read anytime. This site is ad-free — your support goes directly toward keeping it running.

or
Unlock all articles with Membership →
Share

Thank You for Reading

Rork Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.

  • ✦Copy-paste ready implementation code
  • ✦New advanced guides published daily
  • ✦$5/mo or $10 for lifetime access
View Membership →

Related Articles

⬡ Dev Tools2026-04-05
Rork Max × WidgetKit & Live Activities in Practice — From Home Screen to Dynamic Island
A complete guide to implementing iOS Widgets, Lock Screen widgets, and Dynamic Island Live Activities with Rork Max. Covers WidgetKit fundamentals, Timeline update strategies, App Intents integration, and monetization.
◇ App Dev2026-10-31
When EAS Build Stops at "Project archive is too big", Count What Gets Uploaded, Largest First
EAS Build warns at 150 MiB and fails at 2 GiB. Here is how to list what will be uploaded before you send it, find the culprit, and decide what goes into .easignore.
◇ App Dev2026-10-29
An Image Requested Once Before Its Upload Stayed a 404 at the Edge. I Split the Retention Rules by Status Code and Made Upload and Purge a Single Step
A new wallpaper stayed missing in some regions because the CDN kept a 404, fetched once before the upload, as long as it kept the image itself. Per-status retention, a two-request diagnosis, and pairing upload with purge, tested in Node.