●RORK MAX — Rork Max can now build native Swift apps for iPhone, iPad, Apple Watch, Apple TV, and Vision Pro●PUBLISH — Rork Max offers two-click App Store publishing with no Xcode required, cutting the friction of getting an app shipped●EXPO — The standard Rork is built on React Native (Expo), generating native iOS and Android apps from plain-English descriptions●PRICING — Rork is free to start, with paid plans beginning at $25/month, an accessible tier for solo developers●FUNDING — Rork raised $2.8M from a16z (Andreessen Horowitz) as investment keeps flowing into AI app builders●REVIEW — In real use the keys are generated-code readability and maintainability, Expo-related constraints, and how easily billing, push, and ad SDKs slot in●RORK MAX — Rork Max can now build native Swift apps for iPhone, iPad, Apple Watch, Apple TV, and Vision Pro●PUBLISH — Rork Max offers two-click App Store publishing with no Xcode required, cutting the friction of getting an app shipped●EXPO — The standard Rork is built on React Native (Expo), generating native iOS and Android apps from plain-English descriptions●PRICING — Rork is free to start, with paid plans beginning at $25/month, an accessible tier for solo developers●FUNDING — Rork raised $2.8M from a16z (Andreessen Horowitz) as investment keeps flowing into AI app builders●REVIEW — In real use the keys are generated-code readability and maintainability, Expo-related constraints, and how easily billing, push, and ad SDKs slot in
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.
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.
Enable the Near Field Communication Tag Reading capability on your App ID in the Apple Developer portal.
Add an .entitlements file and put NDEF into com.apple.developer.nfc.readersession.formats.
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."
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 CoreNFCfinal 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.
An NDEF text record carries the length of the language code in its first byte. Stringify the payload without knowing that and you get garbage at the front.
For a URL record (type 0x55), the first byte is a prefix code like https://www. instead. Knowing that text and URL records decode differently up front saves you a wasted investigation.
What Bit Me in Production
These are the quirks that surfaced only once real tags met real registers, listed in the order they cost me time.
The iPhone antenna sits at the top of the device. Many users try to touch the middle of the screen to the tag and fail. Just spelling out "hold the top near it" in alertMessage visibly cut my read-failure questions.
Core NFC does nothing in the simulator. readingAvailable always returns false, so keep one physical device on hand from day one.
Background tag reading (reacting to a tap without launching the app) needs a special format with a Universal Link and is a different mechanism from NFCNDEFReaderSession. If the requirement says "without opening the app," do not confuse the two.
A user cancel also arrives at didInvalidateWithError. Show "read failed" without checking the error code and you flash an error at someone who deliberately closed it. Check for NFCReaderError.readerSessionInvalidationErrorUserCanceled and show nothing in that case; that is the production-safe handling.
Choosing and Writing Tags in Practice
Once the reading side is solid, the next step is the practical question of which tag to use. Off-the-shelf NFC tags come in several standards, but for general stamp use NTAG213 or NTAG215 are safe picks. Their small capacity keeps them cheap and is plenty for text or a short URL. In my case I hand out NTAG213 tags written with a per-store identifier, keeping the unit cost to a few tens of yen.
Writing is the reverse of reading. You can push writeNDEF to a tag through connect on an NFCNDEFReaderSession, but writing one at a time on an iPhone is not realistic at volume. I batch-write with a dedicated tool and keep the shipping app read-only. Splitting the roles keeps the production app's capability limited to reading and makes the review explanation simpler.
On reliability, sticking a tag directly to a metal surface drops the read rate, because metal absorbs the radio field. Use a metal-rated tag (one with a ferrite layer on the back) or just put a few millimeters of non-metal between them. The bulk of "stuck it on the metal fixture by the register and it will not read" questions traced back to this placement. Only after testing the physical mounting surface too does it hold up in real use.
What to Delegate to Rork Max, What to Hand-Write
My call is to hand-write the NFC reading logic itself. The entitlement and decoding rules are rigid, so writing it correctly the first time beats round trips between generation and fixes. The result screen and the stamp-collecting animation, on the other hand, I draft with Rork Max and refine from there.
NFC is not a flashy feature, but it shines for "instant, on the spot" moments at counters and events. On a different axis from a revenue pillar like AdMob, it pays back slowly as repeat rate. The tactile feel of bridging the physical world and the app with a single tap is something I could not give up once I added it.
I hope this helps anyone working on the same problem.
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.