Writing a URL or deep link into an NFC tag enables seamless integration between the physical and digital worlds. It offers instant access to online content and enhanced user experiences. Additionally, it creates automation opportunities, simplifying interactions such as opening web pages, accessing app-specific features, or triggering IoT actions. These capabilities make NFC tags valuable for marketing, smart environments, and personalization. This technology finds applications in retail, events, tourism, and healthcare, bringing convenience, innovation, and a modern touch.
In this post, we will continue evolving the app created in the “Harnessing NFC Technology in Your iOS App” post by adding two more functionalities: one for storing a regular web URL and another for adding a deep link to open the same app. By the end of this guide, you’ll be equipped to expand your app’s NFC capabilities and create an even more seamless user experience.
Storing web url into NFC tag
func startWritingURL() async {
nfcOperation = .writeURL
startSesstion()
}
private func startSesstion() {
nfcSession = NFCNDEFReaderSession(delegate: self, queue: nil, invalidateAfterFirstRead: false)
nfcSession?.begin()
}
The
readerSession
delegate function handles connecting to the NFC tag and querying its status.func readerSession(_ session: NFCNDEFReaderSession, didDetect tags: [NFCNDEFTag]) {
guard let tag = tags.first else { return }
session.connect(to: tag) { error in
if let error = error {
session.invalidate(errorMessage: "Connection error: \(error.localizedDescription)")
return
}
tag.queryNDEFStatus { status, capacity, error in
guard error == nil else {
session.invalidate(errorMessage: "Error checking NDEF status")
return
}
switch status {
case .notSupported:
session.invalidate(errorMessage: "Not compatible tat")
case .readOnly:
session.invalidate(errorMessage: "Tag is read-only")
case .readWrite:
switch self.nfcOperation {
case .read:
self.read(session: session, tag: tag)
case .write:
self.write(session: session, tag: tag)
case .writeURL:
self.writeUrl(session: session, tag: tag)
}
@unknown default:
session.invalidate(errorMessage: "Unknown NDEF status")
}
}
}
}
.writeURL
, the method responsible for writing the URL to the tag will be called. private func writeUrl(session: NFCNDEFReaderSession, tag: NFCNDEFTag) {
guard let url = URL(string: "https://javios.eu/portfolio/"),
let payload = NFCNDEFPayload.wellKnownTypeURIPayload(string: url.absoluteString) else {
session.invalidate(errorMessage: "No se pudo crear el payload NDEF.")
return
}
write(session, tag, payload) { error in
guard error == nil else { return }
print(">>> Write: \(url.absoluteString)")
}
}
private func write(_ session: NFCNDEFReaderSession,
_ tag: NFCNDEFTag,
_ nfcNdefPayload: NFCNDEFPayload, completion: @escaping ((Error?) -> Void)) {
let NDEFMessage = NFCNDEFMessage(records: [nfcNdefPayload])
tag.writeNDEF(NDEFMessage) { error in
if let error = error {
session.invalidate(errorMessage: "Writing error: \(error.localizedDescription)")
completion(error)
} else {
session.alertMessage = "Writing succeeded"
session.invalidate()
completion(nil)
}
}
}
writeUrl
function generates an NDEF payload containing a well-known type URI record that points to the URL “https://javios.eu/portfolio/“. If the payload is valid, the function invokes the write
method, passing the NFC session, tag, and payload as parameters. The write
function then creates an NFC NDEF message containing the payload and writes it to the NFC tag.Deeplinks
A deeplink in iOS is a type of link that directs users to a specific location within an app, rather than just opening the app’s home screen. This helps enhance the user experience by providing a direct path to particular content or features within the app.
In this example, we will create a deeplink that will open our current NFCApp directly:


When iOS detects the ‘nfcreader://jca.nfcreader.open’ deep link, it will open the currently post development app on iOS.
@main
struct NFCAppApp: App {
var body: some Scene {
WindowGroup {
ContentView()
.onOpenURL { url in
handleDeeplink(url: url)
}
}
}
func handleDeeplink(url: URL) {
// Maneja el deeplink aquí
print("Se abrió la app con el URL: \(url)")
}
}
By adding the .onOpenURL
modifier, the app will be able to detect when it is launched (or awakened) via a deep link.
Finally, implement the deep link writing functionality by adapting the previously created writeUrl
method:
private func writeUrl(session: NFCNDEFReaderSession, tag: NFCNDEFTag, urlString: String) {
guard let url = URL(string: urlString),
let payload = NFCNDEFPayload.wellKnownTypeURIPayload(string: url.absoluteString) else {
session.invalidate(errorMessage: "No se pudo crear el payload NDEF.")
return
}
write(session, tag, payload) { error in
guard error == nil else { return }
print(">>> Write: \(url.absoluteString)")
}
}
It would be called in the following way for creating deeplink
case .readWrite:
switch self.nfcOperation {
case .read:
self.read(session: session, tag: tag)
case .write:
self.write(session: session, tag: tag)
case .writeURL:
self.writeUrl(session: session, tag: tag, urlString: "https://javios.eu/portfolio/")
case .writeDeeplink:
self.writeUrl(session: session, tag: tag, urlString: "nfcreader://jca.nfcreader.open")
}
Deploy project on a real device for validating behaviour
Once the tag is written, when the deep link is triggered, the app will be closed and then reopened. You will be prompted to open the app again.
Conclusions
In this post, I have extended the functionalities we can implement with NFC tags by using URLs. You can find source code used for writing this post in following repository.
References
- Core NFC
Apple Developer Documentation
- Core NFC Enhancements
WWDC 2020
- What's new in Core NFC
WWDC 2019
- Harnessing NFC Technology in Your iOS App
JaviOS post