◉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-15Intermediate

Adding NFC Tag Reading to a Rork Max App with Core NFC

How to add Core NFC to a Swift app generated by Rork Max and read NDEF tags, covering the entitlement and Info.plist setup through the production gotchas, with real code.

Rork Max235Core NFCNFCNDEFSwift48

✦ Premium Article

While building a stamp-card app, someone asked me to record store visits by tapping a physical tag instead of a QR code. Launching the camera and lining up a code is surprisingly fiddly in the few seconds you have at a counter. With an NFC tag, a tap is all it takes.

Rork Max generates the Swift app, but a feature like Core NFC that involves an Apple entitlement will not run from the generated code alone. Unless you fix up the signing and the plist by hand, the build succeeds yet the session closes instantly on a device. Here is the order I used as an indie developer, including where I tripped.

Set the Entitlement and Info.plist First

Configuration comes before code. Miss this and no amount of correct code will run. Three things are required.

  1. Enable the Near Field Communication Tag Reading capability on your App ID in the Apple Developer portal.
  2. Add an .entitlements file and put NDEF into com.apple.developer.nfc.readersession.formats.
  3. Add NFCReaderUsageDescription to Info.plist and explain why you use NFC.

Reviewers read that third string. "Reads tags" is vague and invites a rejection. I write something that shows the use case, like "Reads the NFC tag at the register to record visit points."

<!-- App.entitlements -->
<key>com.apple.developer.nfc.readersession.formats</key>
<array>
    <string>NDEF</string>
</array>

Write the NDEF Reading Session

With configuration done, build the reader. Make a small reader class that owns an NFCNDEFReaderSession and can be called from the screen Rork Max generated.

import CoreNFC
 
final class TagReader: NSObject, ObservableObject, NFCNDEFReaderSessionDelegate {
    @Published var lastPayload: String?
    private var session: NFCNDEFReaderSession?
 
    func begin() {
        guard NFCNDEFReaderSession.readingAvailable else {
            print("NFC not available on this device")
            return
        }
        session = NFCNDEFReaderSession(
            delegate: self,
            queue: nil,
            invalidateAfterFirstRead: true
        )
        session?.alertMessage = "Hold the top of your iPhone near the tag"
        session?.begin()
    }
 
    func readerSession(_ session: NFCNDEFReaderSession,
                       didDetectNDEFs messages: [NFCNDEFMessage]) {
        guard let record = messages.first?.records.first else { return }
        let text = decodeText(from: record) ?? "(empty)"
        DispatchQueue.main.async { self.lastPayload = text }
    }
 
    func readerSession(_ session: NFCNDEFReaderSession,
                       didInvalidateWithError error: Error) {
        // User cancel and read failures also land here
        print("session invalidated: \(error.localizedDescription)")
    }
}

With invalidateAfterFirstRead: true the session closes after one tag. To read several in a row, set it to false and call invalidate() yourself. For one-at-a-time cases like a stamp card, true is the straightforward choice.

✦

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
✦A checklist for the three required entitlement and Info.plist settings so none are missed
✦Complete working code for reading with NFCNDEFReaderSession and its delegate
✦Fixes for read failures, iPhone antenna placement, and background reading in production
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.