Tutorial: Cómo usar el lector de NFC en iOS con Swift para escanear etiquetas físicas

La tecnología NFC (Near Field Communication) ha transformado la manera en que interactuamos con el mundo físico. Desde realizar pagos móviles hasta abrir cerraduras inteligentes o interactuar con carteles publicitarios, el NFC ofrece un sinfín de posibilidades.

Si eres desarrollador de iOS, integrar la lectura de etiquetas NFC en tus aplicaciones puede aportar un valor interactivo enorme. Gracias al framework de Apple, Core NFC, implementar esta tecnología en Swift es un proceso directo y altamente eficiente.

En este tutorial paso a paso, aprenderás a configurar tu proyecto en Xcode y a escribir el código en Swift necesario para escanear etiquetas físicas NFC (compatibles con el formato NDEF).


¿Qué es Core NFC y qué dispositivos lo soportan?

Core NFC es el framework de Apple que permite leer etiquetas electrónicas NFC que contienen datos en formato de intercambio de datos NFC (NDEF, por sus siglas en inglés).

Para poder utilizar esta funcionalidad, debes tener en cuenta los siguientes requisitos de hardware y software:

  • Dispositivos compatibles: iPhone 7 y modelos posteriores.
  • Sistema operativo: iOS 11 o superior (para lectura básica de NDEF) e iOS 13 o superior (para escritura y lectura avanzada).
  • Limitación importante: El simulador de Xcode no admite el escaneo NFC. Necesitarás un iPhone físico para probar tu aplicación.

Requisitos previos

Antes de empezar a escribir código, asegúrate de tener:

  1. Xcode instalado en tu Mac.
  2. Una cuenta activa de Apple Developer (necesaria para activar las capacidades de NFC en tu perfil de provisión).
  3. Una etiqueta NFC física (preferiblemente formateada como NDEF, que es el estándar de la industria).

Paso 1: Configurar el proyecto en Xcode

La seguridad en iOS es estricta, por lo que antes de acceder al chip NFC del iPhone, debemos solicitar los permisos adecuados y configurar las capacidades del proyecto.

1. Activar la capacidad «Near Field Communication Tag Reading»

  1. Abre tu proyecto en Xcode.
  2. Selecciona el proyecto en la barra lateral izquierda y ve a la pestaña Signing & Capabilities.
  3. Haz clic en el botón + Capability (en la esquina superior izquierda).
  4. Busca Near Field Communication Tag Reading y añádela a tu proyecto.

2. Configurar el archivo Info.plist

Debes explicarle al usuario por qué tu aplicación necesita acceder al lector NFC.

  1. Abre tu archivo Info.plist.
  2. Añade una nueva clave llamada Privacy - NFC Scan Usage Description (internamente se conoce como NFCReaderUsageDescription).
  3. En el valor de esta clave, escribe un mensaje descriptivo para el usuario, por ejemplo: «Esta aplicación requiere acceso al lector NFC para escanear etiquetas y mostrar su información.»

Paso 2: Implementar Core NFC en Swift

Ahora que el entorno está configurado, es hora de escribir código. Crearemos un controlador de vista simple con un botón que active el escáner de NFC.

Código de la implementación

Crea un archivo Swift (por ejemplo, NFCViewController.swift) y añade el siguiente código:

import UIKit
import CoreNFC

class NFCViewController: UIViewController, NFCNDEFReaderSessionDelegate {

    // Sesión de lectura de NFC
    var nfcSession: NFCNDEFReaderSession?

    override func viewDidLoad() {
        super.viewDidLoad()
        setupUI()
    }

    // Configuración básica de la interfaz
    private func setupUI() {
        view.backgroundColor = .white

        let scanButton = UIButton(type: .system)
        scanButton.setTitle("Escanear Etiqueta NFC", for: .normal)
        scanButton.titleLabel?.font = UIFont.boldSystemFont(ofSize: 18)
        scanButton.addTarget(self, action: #selector(startScanning), for: .touchUpInside)

        scanButton.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(scanButton)

        NSLayoutConstraint.activate([
            scanButton.centerXAnchor.constraint(equalTo: view.centerXAnchor),
            scanButton.centerYAnchor.constraint(equalTo: view.centerYAnchor)
        ])
    }

    // Acción para iniciar el escaneo
    @objc func startScanning() {
        // Verificamos si el dispositivo soporta el escaneo NFC
        guard NFCNDEFReaderSession.readingAvailable else {
            let alert = UIAlertController(title: "No compatible", message: "Este dispositivo no soporta lectura NFC.", preferredStyle: .alert)
            alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
            present(alert, animated: true, completion: nil)
            return
        }

        // Inicializamos la sesión de lectura
        nfcSession = NFCNDEFReaderSession(delegate: self, queue: nil, invalidateAfterFirstRead: true)
        nfcSession?.alertMessage = "Acerca el iPhone a la parte trasera de la etiqueta NFC."
        nfcSession?.begin()
    }

    // MARK: - NFCNDEFReaderSessionDelegate

    // Caso 1: Error o finalización de la sesión
    func readerSession(_ session: NFCNDEFReaderSession, didInvalidateWithError error: Error) {
        print("La sesión NFC se invalidó debido al error: \(error.localizedDescription)")
    }

    // Caso 2: Se detectaron mensajes NDEF en la etiqueta
    func readerSession(_ session: NFCNDEFReaderSession, didDetectNDEFs messages: [NFCNDEFMessage]) {
        for message in messages {
            for record in message.records {
                // Parseamos la información del payload
                if let payloadString = String(data: record.payload, encoding: .utf8) {
                    print("Contenido de la etiqueta: \(payloadString)")

                    // Mostrar los datos en la interfaz principal
                    DispatchQueue.main.async {
                        self.mostrarAlerta(mensaje: payloadString)
                    }
                }
            }
        }
    }

    // Función auxiliar para mostrar el resultado
    func mostrarAlerta(mensaje: String) {
        let alert = UIAlertController(title: "¡Etiqueta Escaneada!", message: mensaje, preferredStyle: .alert)
        alert.addAction(UIAlertAction(title: "Cerrar", style: .default, handler: nil))
        self.present(alert, animated: true, completion: nil)
    }
}

Análisis detallado del código

Entender cómo interactúan estos componentes es clave para dominar el desarrollo NFC en iOS:

  1. NFCNDEFReaderSession: Es la clase encargada de gestionar el ciclo de vida del lector de NFC. Al llamar al método begin(), el sistema operativo despliega la hoja estándar de escaneo de iOS.
  2. NFCNDEFReaderSessionDelegate: Este protocolo maneja los eventos de la sesión. Es obligatorio implementar dos métodos:
    • didInvalidateWithError: Se ejecuta cuando el escaneo falla, el usuario lo cancela manualmente o se alcanza el tiempo límite (60 segundos por sesión).
    • didDetectNDEFs: Se dispara cuando el chip NFC lee con éxito una etiqueta. Devuelve un array de mensajes NFCNDEFMessage.
  3. NFCNDEFPayload: Las etiquetas contienen registros (records). En nuestro ejemplo, convertimos los datos en crudo (record.payload) en una cadena legible de texto UTF-8.

Formateo del Payload NFC: Un detalle crucial

Por defecto, los payloads NDEF de texto suelen incluir un prefijo con información del idioma (como «en» o «es»). Si al escanear ves caracteres extraños al inicio del texto, es debido a estos bytes de metadatos del idioma.

Para obtener un texto completamente limpio, puedes añadir este método helper para parsear los payloads de texto de manera profesional:

func parsearPayloadDeTexto(record: NFCNDEFPayload) -> String? {
    let payload = record.payload
    guard !payload.isEmpty else { return nil }

    // El primer byte contiene la longitud del código de idioma
    let statusByte = payload[0]
    let languageCodeLength = Int(statusByte & 0x1F)

    // Saltamos el byte de estado y los bytes del código de idioma para obtener el texto real
    let textStartIndex = 1 + languageCodeLength
    guard textStartIndex < payload.count else { return nil }

    let textData = payload.subdata(in: textStartIndex..<payload.count)
    return String(data: textData, encoding: .utf8)
}

Buenas prácticas para trabajar con NFC en iOS

Para asegurar una excelente experiencia de usuario en tu aplicación móvil, te sugerimos seguir las siguientes pautas:

  • Retroalimentación háptica (vibración): El sistema emite automáticamente una vibración de éxito al leer con CoreNFC, pero si diseñas flujos personalizados, asegúrate de acompañar los errores con retroalimentación visual clara.
  • Tiempo de espera: Las sesiones de lectura de iOS se cierran automáticamente a los 60 segundos si no detectan ninguna etiqueta. Diseña tu app pensando en este límite.
  • Uso del hilo principal: Los métodos delegados de CoreNFC no se ejecutan en el hilo principal. Si deseas actualizar componentes de la UI (como etiquetas de texto o alertas) tras el escaneo, asegúrate de envolver ese código en DispatchQueue.main.async.

Conclusión

Integrar el escaneo de etiquetas NFC en iOS con Swift es sumamente sencillo gracias a Core NFC. Con solo configurar la capacidad en tu proyecto Xcode, solicitar los permisos del usuario en el archivo Info.plist y heredar del delegado adecuado, tendrás un lector NFC funcional en cuestión de minutos.

Esta tecnología abre las puertas a la creación de aplicaciones innovadoras y conectadas con el mundo físico. ¿Estás listo para dar el salto y transformar la experiencia física de tus usuarios en código digital? ¡Empieza a experimentar hoy mismo!

Deja una respuesta