Technologie & Architektur 15. September 2025 18 min Lesezeit

NFC-App-Entwicklung 2025: Check-in, Bezahlen, Authentifizierung

NFC-Apps entwickeln: iOS vs. Android (Core NFC Limits!), Hardware-Anforderungen, Real Cases (FM 24 Wächterkontrolle, Mensa Check-in), Security, Kosten 15-80k.

Carola Schulte
Carola Schulte
Zurück zum Blog

NFC-App-Entwicklung 2025: Check-in, Bezahlen, Authentifizierung

NFC (Near Field Communication) ermöglicht kontaktlose Kommunikation über wenige Zentimeter Distanz – perfekt für Check-in-Systeme, Bezahlvorgänge, Zugangskontrollen und Wächterkontroll-Apps. Aber: iOS und Android unterscheiden sich massiv bei NFC-Zugriff, Background-Scanning ist limitiert, und die Hardware-Anforderungen sind höher als bei QR-Code-Apps.

In diesem Guide zeige ich dir:

  • iOS vs. Android: Wo liegen die Unterschiede? (Spoiler: iOS ist restriktiver)
  • Hardware-Anforderungen: Welche NFC-Chips, Tag-Typen, Reader?
  • Real Cases: FM 24 Wächterkontroll-App + Mensa Check-in System
  • Implementation: nfc_manager Package, Tag-Reading, NDEF, Hex-Conversion
  • Security: Tag-Cloning Prevention, AES-256, Encryption
  • Kosten & Timeline: 15k-80k, 2-6 Monate

TL;DR – Die Essenz

AspektZusammenfassung
iOS vs. AndroidiOS: Core NFC restriktiv (kein Background-Scan, nur NDEF/ISO 15693 nativ, User muss Scan starten). Android: Offener (Background-Scan möglich, mehr Tag-Typen, Intent-System)
HardwareNFC-Chip im Smartphone nötig (ab iPhone 7+, Android ab 4.4+). Tags: NTAG213/215/216, MIFARE Classic/Ultralight. Reader optional für Kiosk-Systeme
Use-CasesCheck-in (Mensa, Events), Wächterkontrolle (FM 24), Bezahlen (Apple Pay/Google Pay API), Authentifizierung (2FA), Inventur
Kosten15-35k (einfache Check-in-App), 35-80k (Enterprise mit Offline-Sync, GPS, Security)
Timeline2-4 Monate (MVP), 4-6 Monate (Enterprise mit Backend)
SecurityTag-Cloning-Risiko! → AES-256-GCM für Tag-IDs, Server-Validierung, UID-Signing

💡 Wann NFC statt QR-Code?

  • NFC: Schneller (1 Tap), schwerer zu fälschen (mit Crypto), funktioniert auch bei schlechtem Licht. Aber: teurer (Tags 0,30-2 €), iOS-Limits.
  • QR: Billiger (0,01 € pro Print), iOS/Android identisch, keine Hardware-Abhängigkeit. Aber: langsamer (Kamera öffnen, fokussieren), leichter zu fälschen.

Hinweis: Alle Preise netto.


1. NFC-Grundlagen: Was ist NFC und wie funktioniert es?

1.1 Technologie

NFC = Near Field Communication (ISO/IEC 18092) basiert auf RFID (Radio-Frequency Identification) und ermöglicht drahtlose Kommunikation über 4-10 cm Distanz bei 13,56 MHz.

Drei Modi:

  1. Reader/Writer Mode: Smartphone liest passive NFC-Tags (z. B. NTAG213). → Häufigster Mode für Apps
  2. Peer-to-Peer Mode: Zwei NFC-Geräte tauschen Daten aus (z. B. Android Beam, inzwischen deprecated)
  3. Card Emulation Mode: Smartphone emuliert Kreditkarte/Ausweis (z. B. Apple Pay, Google Pay)

Für App-Entwicklung relevant: Primär Reader/Writer Mode – App liest NFC-Tags (Check-in, Wächterkontrolle, Inventur).

1.2 NFC-Tag-Typen

Tag-TypSpeicherKostenTypische Nutzung
NTAG213144 Byte0,30-0,60 €Check-in, Marketing (günstig, einmalig beschreibbar)
NTAG215504 Byte0,50-1,00 €Längere URLs, mehrere Datensätze
NTAG216888 Byte0,60-1,20 €Komplexe Datenstrukturen
MIFARE Classic1-4 KB0,80-2,00 ۀlterer Standard (iOS nur mit Tricks lesbar!)
MIFARE Ultralight64 Byte0,30-0,50 €Billig, wenig Speicher (Events, Einweg-Tickets)
ISO 15693256 Byte - 8 KB1,50-5,00 €Längere Reichweite (bis 1 m), Enterprise

💡 Empfehlung für Business-Apps:

  • NTAG213/215: Standard für Check-in/Wächterkontrolle (iOS + Android kompatibel, günstig, NDEF-Support)
  • ISO 15693: Wenn längere Reichweite nötig (z. B. Fahrzeug-Scanning)
  • MIFARE Classic vermeiden: iOS-Support schlecht (nur ab iOS 13+ mit CoreNFC MIFARE-Support, aber umständlich). Alternative: MIFARE DESFire (Type 4, Enterprise, AES-128) oder NTAG 424 DNA (Security)

NFC Forum Tag-Types (Nerd-Info):

  • Type 2: NTAG, MIFARE Ultralight (Standard für Business-Apps)
  • Type 4: MIFARE DESFire (Enterprise, AES-128-Encryption, viele Unis nutzen DESFire)
  • Type 5: ISO 15693 (längere Reichweite bis 1m)

1.3 NDEF (NFC Data Exchange Format)

NDEF = Standard-Datenformat für NFC-Tags. Struktur:

  • Records: Text, URL, MIME, Smart Poster
  • Payload: Nutzlast (z. B. “https://app-entwicklerin.de”)
  • Type: MIME-Type oder RTD (Record Type Definition)

Beispiel NDEF-Record (Text):

Record Type: Text
Language: de
Payload: "Checkpoint A1 - Eingang Süd"

Für Wächterkontrolle/Check-in: Meist UID (Unique Identifier) auslesen statt NDEF – UID ist eindeutig, unveränderbar (7 Byte bei NTAG213) auf echten NTAGs; klonbare “Magic Cards” können die UID fälschen (siehe Security-Kapitel). Besser für Datenbank-Mapping.


2. iOS vs. Android: Die entscheidenden Unterschiede

DAS ist der Game-Changer bei NFC-Apps. iOS ist deutlich restriktiver als Android.

2.1 iOS Core NFC

Verfügbar ab: iPhone 7+ (iOS 11+), aber voller Zugriff erst ab iOS 13+

Einschränkungen:

  1. Kein Background-Scan: App muss im Foreground sein. User muss explizit Scan starten (Button drücken).
  2. User-Session: Scan-Session muss vom User initiiert werden (keine automatische Tag-Erkennung wie bei Android).
  3. Tag-Typen: iOS 11-12: Nur NDEF. iOS 13+: NDEF, ISO 15693, ISO 7816/IsoDep (z. B. MIFARE DESFire), MIFARE (Classic eingeschränkt, Ultralight, Plus). iOS 14+: zusätzlich FeliCa (Japan). Proprietäre Tags schwierig.
  4. Keine Dauersession: Nach 60 Sekunden bricht Session ab (muss neu gestartet werden).

Code-Beispiel iOS (Flutter nfc_manager):

import 'package:nfc_manager/nfc_manager.dart';

void startNFCScan() async {
  bool isAvailable = await NfcManager.instance.isAvailable();
  if (!isAvailable) {
    print("NFC nicht verfügbar");
    return;
  }

  NfcManager.instance.startSession(
    onDiscovered: (NfcTag tag) async {
      // iOS: User hat Tag angehalten, Session läuft
      var ndef = Ndef.from(tag);
      if (ndef == null) {
        print("Kein NDEF-Tag");
        return;
      }

      // Tag-ID auslesen (UID)
      var id = tag.data['nfca']?['identifier'] ??
               tag.data['nfcb']?['identifier'];
      String hexID = _convertToHex(id);

      print("Tag ID: $hexID");

      // Session beenden (iOS zwingend!)
      NfcManager.instance.stopSession();
    },
  );
}

String _convertToHex(List<int> bytes) {
  return bytes.map((b) => b.toRadixString(16).padLeft(2, '0')).join('').toUpperCase();
}

⚠️ iOS-Stolperfalle: User muss jeden Scan manuell starten – kein “Smartphone hinhalten und automatisch scannen” wie bei Android. UX-Impact: +2-3 Sekunden pro Scan.

2.2 Android NFC

Verfügbar ab: Android 4.4+ (KitKat), API Level 19+

Vorteile:

  1. Background-Scan möglich: App kann per Intent-Filter im Hintergrund auf NFC-Tags reagieren (auch wenn App geschlossen). ⚠️ Hinweis: Seit Android 10/11 reagiert das System nicht in allen OEM-Skins identisch auf Hintergrund-Intents (Samsung/MIUI-Eigenheiten). Foreground-Dispatch in der App ist die robusteste Strategie.
  2. Automatische Tag-Erkennung: User hält Smartphone an Tag → App öffnet automatisch (oder zeigt Dialog).
  3. Mehr Tag-Typen: NfcA, NfcB, NfcF, NfcV, IsoDep, MifareClassic, MifareUltralight, NdefFormatable.
  4. Foreground-Dispatch: App kann NFC-Priorität übernehmen, wenn im Foreground.

Code-Beispiel Android (Flutter nfc_manager):

void startNFCScan() async {
  NfcManager.instance.startSession(
    onDiscovered: (NfcTag tag) async {
      // Android: Tag wurde erkannt (automatisch oder per Foreground-Dispatch)
      var nfcA = NfcA.from(tag);
      if (nfcA != null) {
        List<int> id = nfcA.identifier;
        String hexID = _convertToHex(id);
        print("Tag ID: $hexID");

        // Checkpoint validieren (Datenbank-Abgleich)
        await _validateCheckpoint(hexID);
      }

      // Android: Session nicht zwingend beenden (läuft weiter bis stopSession)
    },
  );
}

💡 Android-Vorteil für Wächterkontrolle: Foreground-Dispatch = App im Vordergrund → Tag wird sofort erkannt, kein Button-Druck nötig. 1-2 Sekunden schneller als iOS.

2.3 Vergleichstabelle iOS vs. Android

FeatureiOS (Core NFC)Android (NFC API)Winner
Background-Scan❌ Nein (nur Foreground)✅ Ja (Intent-Filter)🏆 Android
Automatische Erkennung❌ Nein (User startet Session)✅ Ja (Foreground-Dispatch/Intent)🏆 Android
Tag-TypenNDEF, ISO 15693, MIFARE (ab iOS 13+)Alle (NfcA/B/F/V, MIFARE, IsoDep)🏆 Android
Session-Dauer⚠️ Max. 60 Sekunden✅ Unbegrenzt (bis stopSession)🏆 Android
UX-Geschwindigkeit⚠️ +2-3 Sek (User muss Button drücken)✅ Instant (Foreground-Dispatch)🏆 Android
VerfügbarkeitiPhone 7+ (iOS 11+), voll ab iOS 13+Android 4.4+ (KitKat), API 19+🏆 Android (ältere Geräte)
Security✅ Sandbox-Schutz, User-Consent✅ Permissions, Intent-Filter⚖️ Gleichstand (je nach Implementierung)

Fazit: Android ist für NFC-Apps deutlich besser geeignet – Background-Scan, automatische Erkennung, mehr Tag-Typen. iOS ist nutzbar, aber langsamer und User-manuell.

⚠️ Wichtig für Projektplanung: Wenn iOS-Nutzer 30-40% der Zielgruppe → +15-20% Entwicklungszeit für iOS-spezifische UX-Anpassungen (Custom Scan-Button, Session-Management, Fallback-Flows).


3. Hardware-Anforderungen

3.1 Smartphone-Voraussetzungen

iOS:

  • iPhone 7 oder neuer (iPhone 7, 8, X, 11, 12, 13, 14, 15, 16+)
  • iOS 11+ (NDEF), iOS 13+ (MIFARE, ISO 15693 voll nutzbar)
  • Einschränkung: iPhone 6/6S ohne NFC (nur Apple Pay, kein App-Zugriff)

Android:

  • NFC-Chip erforderlich (nicht alle Android-Geräte haben NFC!)
  • Android 4.4+ (KitKat), empfohlen: Android 8+ für moderne NFC-APIs
  • Budget-Geräte: Viele günstige Androids (<200 €) ohne NFC → Zielgruppe checken!

💡 Praxis-Tipp: Bei Enterprise-Rollout (z. B. Wächterkontrolle) → Hardware-Audit vor Projektstart:

  • Welche Smartphones haben Mitarbeiter?
  • iOS/Android-Verteilung?
  • NFC verfügbar? (Android: Settings > Connected Devices > Connection Preferences > NFC)

Kosten Hardware (falls Neuanschaffung):

  • Android mit NFC: ab 250 € (Samsung Galaxy A-Serie, Google Pixel 6a)
  • iPhone mit NFC: ab 500 € (iPhone SE, refurbished iPhone 11)

3.2 NFC-Tags

Für Check-in/Wächterkontrolle:

  • NTAG213 (144 Byte): 0,30-0,60 € pro Stück (Bulk: 500+ Stück → 0,20-0,30 €)
  • NTAG215 (504 Byte): 0,50-1,00 € (wenn längere URLs/Daten nötig)
  • Form-Faktoren: Sticker (rund/quadratisch), Key-Fobs, Wristbands, Cards

Beispiel-Kalkulation (Wächterkontrolle, 100 Checkpoints):

  • 100x NTAG213 Sticker: 30-60 €
  • Reserve (10%): 3-6 €
  • Gesamt: ~50-80 € für Tags (einmalig)

Montage/Schutz:

  • Outdoor-Tags:
    • IP67-rated Tag-Holder: Wasserdicht, staubdicht (2-5 € pro Stück)
    • UV-beständige Sticker: PVC-Material, 3-5 Jahre Outdoor-Lebensdauer
    • Metall-Montage: Ferrit-Inlay/Shielding nötig (Metall blockiert NFC-Signal!), +1-2 € pro Tag
    • Extreme Temperaturen: Industrial-Tags (-40°C bis +85°C), 5-10 € pro Stück
  • Indoor: Standard-Sticker, ggf. laminiert

3.3 NFC-Reader (optional)

Wann nötig?

  • Kiosk-Systeme: Fest installierter Reader (z. B. Kantine, Einlasskontrolle)
  • Desktop-Anwendungen: PC-basierte Tag-Verwaltung (Tags beschreiben, UID auslesen)

Hardware:

  • ACR122U USB NFC Reader: 30-50 € (PC/Mac-kompatibel, NTAG/MIFARE)
  • Feitian R502 Dual-Interface Reader: 80-120 € (NFC + Contact-Smartcard)
  • Elatec TWN4 MultiTech: 150-250 € (Enterprise, 125 kHz + 13,56 MHz)

Für reine Smartphone-Apps: nicht nötig (Smartphone = Reader).


4. Real Case 1: FM 24 – Wächterkontroll-App (NFC + GPS + Offline)

Use-Case: Sicherheitsdienstleister nutzen FM 24 App für Wächterkontrollgänge. Mitarbeiter scannen NFC-Checkpoints an definierten Stationen (Eingang, Parkplatz, Heizungsraum, etc.) und dokumentieren Rundgänge. Offline-Fähigkeit, GPS-Tracking, Betriebskontroll-Checklisten.

⚠️ Compliance-Hinweis: Standort/Zeiterfassung ist arbeitsrechtlich sensibelBetriebsrat und Datenschutzbeauftragten früh einbinden (vor Projektstart!). DSGVO-Prozess (AVV, Löschkonzept) parallel entwickeln.

4.1 Funktionen

Kerntechnologie:

  • NFC-Checkpoint-Scanning: NTAG213-Tags an Stationen (UID-Mapping zu Checkpoint-Datenbank)
  • GPS-Logging: Standort bei jedem Scan (Validierung: Ist User wirklich am Checkpoint?)
  • Offline-First: SQLite/SQLCipher für lokale Speicherung, Sync bei Netzverbindung
  • Prüfintervalle: Daily, Weekly, Monthly, Quarterly, Yearly (automatische Betriebskontroll-Trigger)
  • Anti-Double-Scan: Checkpoint kann nicht 2x direkt hintereinander gescannt werden (30-Sekunden-Sperre)
  • PRIO-Checkpoints: Pflicht-Checkpoints, die nicht übersprungen werden dürfen

Architektur:

[NFC-Scan] → [Tag-ID (Hex)] → [Checkpoint-Validierung (SQLite)]
→ [GPS-Logging] → [Prüfintervall-Check] → [Datenbank-Update]
→ [Sync-Queue (offline)] → [Backend-Sync (online)]

4.2 Code-Einblicke (NFC-Tag-Reading)

Tag-ID auslesen und in Hex konvertieren:

void readTag() {
  NfcManager.instance.startSession(onDiscovered: (NfcTag tag) async {
    // Tag-Daten auslesen (NfcA-Identifier = UID)
    var nfcA = NfcA.from(tag);
    if (nfcA == null) return;

    List<int> identifier = nfcA.identifier;

    // Decimal zu Hex konvertieren (7 Bytes → 14 Hex-Chars)
    String hexID = identifier
      .map((byte) => byte.toRadixString(16).padLeft(2, '0'))
      .join('')
      .toUpperCase();

    print("Tag UID: $hexID"); // z. B. "04A1B2C3D4E5F6"

    // Checkpoint validieren
    validateCheckpoint(hexID);

    // iOS: Session beenden
    if (Platform.isIOS) {
      NfcManager.instance.stopSession();
    }
  });
}

Checkpoint-Validierung (Anti-Double-Scan):

Future<void> validateCheckpoint(String tagID) async {
  // Checkpoint aus DB laden
  Checkpoint? cp = await db.getCheckpointByTagID(tagID);

  if (cp == null) {
    showToast("Unbekannter Checkpoint!");
    return;
  }

  // Anti-Double-Scan: Letzter Scan < 30 Sekunden?
  if (cp.lastScan != null &&
      DateTime.now().difference(cp.lastScan!) < Duration(seconds: 30)) {
    showToast("Checkpoint bereits gescannt! Bitte 30 Sek warten.");
    return;
  }

  // Prüfintervall-Check (z. B. "Wöchentlich: Montag, Freitag")
  if (!_isCheckDue(cp)) {
    showToast("Checkpoint heute nicht fällig (Prüfintervall).");
    return;
  }

  // GPS-Position loggen
  Position? position = await _getCurrentPosition();

  // Scan speichern
  await db.insertScan(
    checkpointID: cp.id,
    tagID: tagID,
    timestamp: DateTime.now(),
    gpsLat: position?.latitude,
    gpsLon: position?.longitude,
  );

  showToast("✓ Checkpoint ${cp.name} erfolgreich gescannt!");
}

bool _isCheckDue(Checkpoint cp) {
  // Prüfintervall-Logik (z. B. "Wöchentlich: Mo, Mi, Fr")
  if (cp.interval == "weekly") {
    List<String> allowedDays = cp.checkDays; // ["Monday", "Wednesday", "Friday"]
    String today = DateFormat('EEEE').format(DateTime.now());
    return allowedDays.contains(today);
  }

  if (cp.interval == "monthly") {
    // Letzte Prüfung > 30 Tage?
    return DateTime.now().difference(cp.lastCheck!) > Duration(days: 30);
  }

  // ... Quarterly, Yearly analog

  return true; // Daily = immer fällig
}

Offline-Sync-Logik:

// Beim App-Start oder Netz-Reconnect: Sync-Queue abarbeiten
Future<void> syncPendingScans() async {
  if (!await _hasInternet()) return;

  List<Scan> pendingScans = await db.getPendingScans();

  for (var scan in pendingScans) {
    try {
      await api.postScan(scan);
      await db.markScanSynced(scan.id);
    } catch (e) {
      print("Sync failed: $e");
      // Retry später (Exponential Backoff)
    }
  }
}

4.3 Kosten & Timeline (FM 24-ähnliches Projekt)

Features:

  • NFC-Checkpoint-Scanning (NTAG213-Tags)
  • GPS-Logging + Offline-Sync
  • Prüfintervalle (Daily/Weekly/Monthly/Quarterly/Yearly)
  • Betriebskontroll-Checklisten
  • Anti-Double-Scan + PRIO-Checkpoints
  • Android + iOS (Flutter)
  • Backend (Node.js/PHP + MySQL/PostgreSQL)
  • Admin-Dashboard (Web, React/Vue)

Kosten:

  • App-Entwicklung (Flutter): 25-35k € (3-4 Monate)
  • Backend + API: 10-15k € (2-3 Monate)
  • Admin-Dashboard: 8-12k € (2 Monate)
  • Security-Audit + Pentest: 3-5k €
  • Deployment + CI/CD: 2-3k €
  • Gesamt: 48-70k € (Netto)

Timeline: 5-6 Monate (MVP → Beta → Rollout)

Hardware:

  • 100x NTAG213 Tags: 50-80 €
  • 10x Android-Smartphones (falls nötig): 2.500 € (Samsung Galaxy A-Serie)

5. Real Case 2: Mensa-App – NFC-Check-in mit Ampel-Status

Use-Case: Studenten/Mitarbeiter checken mit NFC-Studentenausweis oder NFC-Wristband in der Mensa ein. App zeigt Ampel-Status (Grün = freie Plätze, Gelb = mittel, Rot = voll). Master-Slave-Architektur: Haupt-Gerät (Master) koordiniert Check-ins, Slave-Geräte synchronisieren per WebSocket (funktioniert offline im WLAN).

5.1 Funktionen

Kerntechnologie:

  • NFC-Check-in: MIFARE Ultralight oder NTAG215 auf Studentenausweis/Wristband
  • Ampel-Logik: Realtime-Kapazität (basierend auf Check-ins/Check-outs)
  • Master-Slave-Sync: WebSocket-Kommunikation (kein Internet nötig, nur lokales WLAN)
  • Offline-First: SQLite für Check-in-Historie, Sync bei Netzverbindung
  • Suchfunktion: User nach Name/Matrikelnummer suchen (Allergien/Diätprefs anzeigen)

Architektur:

[NFC-Scan] → [UID → User-DB-Lookup] → [Check-in/Check-out]
→ [Kapazität berechnen] → [Ampel-Status aktualisieren]
→ [WebSocket-Broadcast (Master → Slaves)]
→ [UI-Update (alle Geräte)]

5.2 Code-Einblicke (Master-Slave-Sync)

Master: Check-in verarbeiten und an Slaves broadcasten:

// Master-Gerät: Check-in empfangen
Future<void> processCheckIn(String tagUID) async {
  // User aus DB laden (UID → User-Mapping)
  User? user = await db.getUserByNFC(tagUID);

  if (user == null) {
    showToast("Unbekannter Ausweis!");
    return;
  }

  // Check-in speichern
  await db.insertCheckIn(
    userID: user.id,
    timestamp: DateTime.now(),
    location: "Mensa Nord",
  );

  // Kapazität aktualisieren
  int currentCapacity = await db.getCurrentCapacity();
  String ampelStatus = _calculateAmpel(currentCapacity);

  // An alle Slaves senden (WebSocket)
  websocketServer.broadcast(jsonEncode({
    'type': 'check_in',
    'user': user.name,
    'capacity': currentCapacity,
    'ampel': ampelStatus,
  }));

  // UI aktualisieren
  setState(() {
    this.ampelStatus = ampelStatus;
  });

  showToast("✓ ${user.name} eingecheckt! Aktuell: $currentCapacity Personen");
}

String _calculateAmpel(int capacity) {
  int maxCapacity = 300; // Mensa-Gesamtkapazität
  double percentage = capacity / maxCapacity;

  if (percentage < 0.6) return "green";
  if (percentage < 0.85) return "yellow";
  return "red";
}

Slave: Check-in-Updates empfangen:

// Slave-Gerät: WebSocket-Updates verarbeiten
void connectToMaster(String masterIP) {
  IOWebSocketChannel channel = IOWebSocketChannel.connect("ws://$masterIP:8080");

  channel.stream.listen((message) {
    Map<String, dynamic> data = jsonDecode(message);

    if (data['type'] == 'check_in') {
      setState(() {
        ampelStatus = data['ampel'];
        currentCapacity = data['capacity'];
      });

      showToast("${data['user']} hat eingecheckt!");
    }
  });
}

Ampel-UI (Flutter):

Widget buildAmpel() {
  Color color;
  String text;

  switch (ampelStatus) {
    case "green":
      color = Colors.green;
      text = "Freie Plätze";
      break;
    case "yellow":
      color = Colors.yellow;
      text = "Mittlere Auslastung";
      break;
    case "red":
      color = Colors.red;
      text = "Sehr voll";
      break;
    default:
      color = Colors.grey;
      text = "Unbekannt";
  }

  return Container(
    width: 200,
    height: 200,
    decoration: BoxDecoration(
      shape: BoxShape.circle,
      color: color,
    ),
    child: Center(
      child: Text(
        text,
        style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold, color: Colors.white),
        textAlign: TextAlign.center,
      ),
    ),
  );
}

5.3 Kosten & Timeline (Mensa-App)

Features:

  • NFC-Check-in (MIFARE Ultralight/NTAG215)
  • Ampel-Status (Realtime-Kapazität)
  • Master-Slave-Sync (WebSocket, Offline-WLAN)
  • Suchfunktion (User nach Name/Matrikelnummer)
  • Allergien/Diätprefs-Anzeige
  • Android + iOS (Flutter)
  • Backend (Node.js + PostgreSQL)

Kosten:

  • App-Entwicklung (Flutter): 18-28k € (2-3 Monate)
  • Backend + WebSocket-Server: 8-12k € (1,5-2 Monate)
  • NFC-Studentenausweis-Integration: 3-5k € (UID-Mapping, Schnittstelle zur Uni-DB)
  • Deployment + Testing: 2-3k €
  • Gesamt: 31-48k € (Netto)

Timeline: 3-4 Monate (MVP → Beta → Rollout)

Hardware:

  • 2-3x Android-Tablets (Master + Slaves): 600-900 € (Samsung Galaxy Tab A)
  • NFC-Tags (falls Wristbands statt Studentenausweis): 500x NTAG215 Wristbands = 250-500 €

6. Implementation: Flutter + nfc_manager Package

6.1 Package-Setup

Dependency (pubspec.yaml):

dependencies:
  nfc_manager: ^3.5.0

Android-Konfiguration (android/app/src/main/AndroidManifest.xml):

<uses-permission android:name="android.permission.NFC" />
<uses-feature android:name="android.hardware.nfc" android:required="false" />

<application>
  <activity
    android:name=".MainActivity"
    android:launchMode="singleTop">

    <!-- Intent-Filter für NFC-Tags (Background-Scan) -->
    <intent-filter>
      <action android:name="android.nfc.action.NDEF_DISCOVERED" />
      <category android:name="android.intent.category.DEFAULT" />
      <data android:mimeType="text/plain" />
    </intent-filter>

    <intent-filter>
      <action android:name="android.nfc.action.TAG_DISCOVERED" />
      <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
  </activity>
</application>

iOS-Konfiguration (ios/Runner/Info.plist):

<key>NFCReaderUsageDescription</key>
<string>Wir benötigen NFC-Zugriff für Checkpoint-Scanning</string>

<key>com.apple.developer.nfc.readersession.formats</key>
<array>
  <string>NDEF</string>
  <string>TAG</string>
</array>

6.2 Basis-Implementation

NFC verfügbar prüfen:

Future<bool> isNFCAvailable() async {
  return await NfcManager.instance.isAvailable();
}

NFC-Scan starten (Foreground):

void startNFCScan() async {
  if (!await isNFCAvailable()) {
    showDialog(
      context: context,
      builder: (_) => AlertDialog(
        title: Text("NFC nicht verfügbar"),
        content: Text("Ihr Gerät unterstützt kein NFC oder NFC ist deaktiviert."),
        actions: [
          TextButton(
            onPressed: () => Navigator.pop(context),
            child: Text("OK"),
          ),
        ],
      ),
    );
    return;
  }

  NfcManager.instance.startSession(
    onDiscovered: (NfcTag tag) async {
      // Tag-Daten auslesen
      print("Tag entdeckt: ${tag.data}");

      // UID extrahieren (NfcA/NfcB)
      var nfcA = NfcA.from(tag);
      var nfcB = NfcB.from(tag);

      List<int>? identifier = nfcA?.identifier ?? nfcB?.identifier;

      if (identifier == null) {
        print("Konnte UID nicht auslesen");
        return;
      }

      String hexUID = identifier
        .map((byte) => byte.toRadixString(16).padLeft(2, '0'))
        .join('')
        .toUpperCase();

      print("Tag UID: $hexUID");

      // Checkpoint validieren
      await validateCheckpoint(hexUID);

      // iOS: Session beenden
      if (Platform.isIOS) {
        NfcManager.instance.stopSession(alertMessage: "Scan erfolgreich!");
      }
    },
    onError: (error) async {
      print("NFC Error: $error");
      if (Platform.isIOS) {
        NfcManager.instance.stopSession(errorMessage: "Scan fehlgeschlagen");
      }
    },
  );
}

NFC-Scan stoppen:

void stopNFCScan() {
  NfcManager.instance.stopSession();
}

6.3 NDEF-Record lesen

NDEF-Record auslesen (z. B. URL oder Text):

void readNDEF(NfcTag tag) async {
  var ndef = Ndef.from(tag);

  if (ndef == null) {
    print("Kein NDEF-Tag");
    return;
  }

  NdefMessage? message = await ndef.cachedMessage;

  if (message == null) {
    print("Kein NDEF-Message");
    return;
  }

  for (var record in message.records) {
    // Payload dekodieren
    String payload = String.fromCharCodes(record.payload);

    // TNF (Type Name Format) prüfen
    if (record.typeNameFormat == NdefTypeNameFormat.nfcWellknown) {
      // RTD (Record Type Definition) prüfen
      if (String.fromCharCodes(record.type) == "T") {
        // Text-Record
        // Erstes Byte = Language Code Length + Encoding
        int languageCodeLength = record.payload[0] & 0x3F;
        String languageCode = String.fromCharCodes(record.payload.sublist(1, 1 + languageCodeLength));
        String text = String.fromCharCodes(record.payload.sublist(1 + languageCodeLength));

        print("NDEF Text ($languageCode): $text");
      } else if (String.fromCharCodes(record.type) == "U") {
        // URI-Record
        // Erstes Byte = URI Identifier Code
        int uriIdentifier = record.payload[0];
        String uriPrefix = _getURIPrefix(uriIdentifier);
        String uri = uriPrefix + String.fromCharCodes(record.payload.sublist(1));

        print("NDEF URI: $uri");
      }
    }
  }
}

String _getURIPrefix(int code) {
  const Map<int, String> prefixes = {
    0x00: "",
    0x01: "http://www.",
    0x02: "https://www.",
    0x03: "http://",
    0x04: "https://",
    // ... siehe NFC Forum URI RTD Spec
  };
  return prefixes[code] ?? "";
}

6.4 MIFARE Classic lesen (Android + iOS 13+)

MIFARE Classic (1K/4K) auslesen:

void readMIFARE(NfcTag tag) async {
  var mifareClassic = MifareClassic.from(tag);

  if (mifareClassic == null) {
    print("Kein MIFARE Classic Tag");
    return;
  }

  // Authentifizierung (Default-Key: 0xFFFFFFFFFFFF)
  Uint8List keyA = Uint8List.fromList([0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]);

  try {
    // Sektor 1, Block 4 lesen (Beispiel)
    int sectorIndex = 1;
    bool authenticated = await mifareClassic.authenticateSectorWithKeyA(
      sectorIndex: sectorIndex,
      key: keyA,
    );

    if (!authenticated) {
      print("Authentifizierung fehlgeschlagen");
      return;
    }

    int blockIndex = mifareClassic.blockIndexFromSectorIndex(sectorIndex);
    Uint8List blockData = await mifareClassic.readBlock(blockIndex: blockIndex);

    print("Block $blockIndex Daten: ${blockData.map((b) => b.toRadixString(16).padLeft(2, '0')).join(' ')}");
  } catch (e) {
    print("MIFARE Read Error: $e");
  }
}

⚠️ iOS-Einschränkung: MIFARE Classic nur ab iOS 13+ lesbar (via CoreNFC MIFARE-Support). NTAG ist iOS-kompatibler.


7. Security: Tag-Cloning und Verschlüsselung

7.1 Das Tag-Cloning-Problem

NFC-Tags sind klonbar! Ein Angreifer kann:

  1. Tag-UID auslesen (mit beliebiger NFC-App oder Reader)
  2. Leeren Tag mit gleicher UID beschreiben (UID-änderbare Tags: Chinese Magic Cards, ca. 1-2 € pro Stück)
  3. Geklonten Tag nutzen (z. B. Check-in fälschen, Zugang erschleichen)

Beispiel-Angriff (Wächterkontrolle):

  • Angreifer liest UID von Checkpoint A1 aus → 04A1B2C3D4E5F6
  • Schreibt UID auf Magic Card
  • Scannt geklonten Tag von Zuhause → System denkt, Checkpoint A1 wurde besucht

7.2 Gegenmaßnahmen

1. Server-seitige Validierung (GPS, Zeitstempel)

// Backend: Check-in validieren
app.post('/api/checkin', async (req, res) => {
  const { tagUID, gpsLat, gpsLon, timestamp } = req.body;

  // Checkpoint aus DB laden
  const checkpoint = await db.getCheckpointByUID(tagUID);
  if (!checkpoint) return res.status(404).json({ error: "Unbekannter Checkpoint" });

  // GPS-Distanz prüfen (max. 50 Meter Abweichung)
  const distance = calculateDistance(gpsLat, gpsLon, checkpoint.lat, checkpoint.lon);
  if (distance > 50) {
    return res.status(403).json({ error: "GPS-Position stimmt nicht überein!" });
  }

  // Zeitstempel-Plausibilität (nicht älter als 5 Minuten)
  const now = Date.now();
  const scanTime = new Date(timestamp).getTime();
  if (now - scanTime > 5 * 60 * 1000) {
    return res.status(403).json({ error: "Zeitstempel zu alt!" });
  }

  // Check-in speichern
  await db.insertCheckIn({ tagUID, gpsLat, gpsLon, timestamp });
  res.json({ success: true });
});

2. Challenge-Response-Verfahren (NTAG 424 DNA)

NTAG 424 DNA = NFC-Tag mit AES-128-Verschlüsselung und SUN (Secure Unique NFC) / SDM (Secure Dynamic Messaging)-Funktion.

Funktionsweise:

  1. Tag generiert bei jedem Scan einzigartige Signatur (AES-128-CMAC + Counter-basiert)
  2. App sendet Tag-UID + Signatur + Timestamp an Backend
  3. Backend validiert Signatur mit geheimem Key (nur Backend kennt Key)
  4. Wenn Signatur ungültig → Geklonter Tag erkannt!

Kosten: NTAG 424 DNA Tags: 1,50-3,00 € pro Stück (teurer, aber sicherer)

⚠️ Hinweis: Vereinfachtes Beispiel unten. NTAG 424 DNA nutzt SUN mit AES-128-CMAC + Counter-basierter Signatur. Echte Implementation komplexer (siehe NXP Application Note AN12196).

Code-Beispiel (Signatur-Validierung, Backend - vereinfacht):

const crypto = require('crypto');

function validateNTAG424Signature(tagUID, signature, timestamp, secretKey) {
  // CMAC berechnen (AES-128)
  const data = Buffer.concat([
    Buffer.from(tagUID, 'hex'),
    Buffer.from(timestamp.toString(), 'utf8'),
  ]);

  const cmac = crypto.createCmac('aes-128-cbc', Buffer.from(secretKey, 'hex'));
  cmac.update(data);
  const expectedSignature = cmac.digest('hex');

  // Vergleich
  return signature === expectedSignature;
}

app.post('/api/checkin', async (req, res) => {
  const { tagUID, signature, timestamp } = req.body;

  const secretKey = process.env.NTAG424_SECRET_KEY; // z. B. "0123456789ABCDEF0123456789ABCDEF"

  if (!validateNTAG424Signature(tagUID, signature, timestamp, secretKey)) {
    return res.status(403).json({ error: "Ungültige Signatur! Tag geklont?" });
  }

  // ... Rest der Validierung
});

3. AES-256-GCM-Verschlüsselung (App → Backend)

Scan-Daten verschlüsseln (verhindert Man-in-the-Middle):

⚠️ Security-Standards:

  • Kein Hardcoding von Keys! Secret-Manager (AWS Secrets Manager, Azure Key Vault)
  • Key-Rotation: ≤ 90 Tage
  • AEAD-Tag serverseitig validieren (GCM-Mode)
  • Nonce/IV nie wiederverwenden (einmalig pro Verschlüsselung)
  • Keys per Secret-Manager, niemals im Code
import 'package:encrypt/encrypt.dart';

String encryptScanData(String tagUID, double gpsLat, double gpsLon) {
  // Demo: In Produktion Key aus Secret-Manager laden!
  final key = Key.fromUtf8('32-Byte-Secret-Key-hier-einfuegen-!'); // 32 Bytes für AES-256
  final iv = IV.fromSecureRandom(16); // 16 Bytes IV

  final encrypter = Encrypter(AES(key, mode: AESMode.gcm));

  final plaintext = jsonEncode({
    'tagUID': tagUID,
    'gpsLat': gpsLat,
    'gpsLon': gpsLon,
    'timestamp': DateTime.now().toIso8601String(),
  });

  final encrypted = encrypter.encrypt(plaintext, iv: iv);

  // IV + Ciphertext zurückgeben (Base64)
  return base64Encode(iv.bytes) + '.' + encrypted.base64;
}

// Backend: Entschlüsseln
function decryptScanData(encryptedData, secretKey) {
  const [ivBase64, ciphertextBase64] = encryptedData.split('.');
  const iv = Buffer.from(ivBase64, 'base64');
  const ciphertext = Buffer.from(ciphertextBase64, 'base64');

  const decipher = crypto.createDecipheriv('aes-256-gcm', Buffer.from(secretKey, 'utf8'), iv);
  const plaintext = decipher.update(ciphertext, null, 'utf8') + decipher.final('utf8');

  return JSON.parse(plaintext);
}

7.3 Security-Checkliste

  • GPS-Validierung: Checkpoint-Position mit Scan-GPS vergleichen (max. 50-100m Abweichung)
  • Zeitstempel-Plausibilität: Scan nicht älter als 5 Minuten
  • Anti-Replay: Scan-ID (UUID) tracken → doppelte Scan-IDs ablehnen
  • NTAG 424 DNA: Für High-Security-Anwendungen (Bezahlen, Zugang)
  • AES-256-GCM: App → Backend Kommunikation verschlüsseln
  • TLS 1.3: HTTPS mit Certificate Pinning
  • Rate-Limiting: Max. 10 Scans/Minute pro User (verhindert Brute-Force)

8. Kosten & Timeline

8.1 Projekttypen

Typ A: Einfache Check-in-App (Events, Mensa)

  • Features: NFC-Check-in, User-DB, Ampel-Status, Basis-UI
  • Kosten: 15-25k €
  • Timeline: 2-3 Monate

Typ B: Business-App (Wächterkontrolle, Inventur)

  • Features: NFC + GPS, Offline-Sync, Prüfintervalle, Checklisten, Admin-Dashboard
  • Kosten: 35-55k €
  • Timeline: 4-5 Monate

Typ C: Enterprise mit Security (Banking, Bezahlen)

  • Features: NTAG 424 DNA, Challenge-Response, AES-256, Pentest, DSGVO-Audit
  • Kosten: 60-80k €
  • Timeline: 5-6 Monate

8.2 Kostenaufschlüsselung (Typ B-Beispiel)

PositionAufwandKosten (Netto)
Anforderungsanalyse3-5 Tage2.500-4.000 €
UI/UX-Design8-12 Tage6.000-9.000 €
App-Entwicklung (Flutter)30-40 Tage22.500-30.000 €
Backend + API12-18 Tage9.000-13.500 €
Offline-Sync-Logik5-8 Tage3.750-6.000 €
Testing (Unit/Integration/E2E)8-10 Tage6.000-7.500 €
Feldtest/Rollout (Pilotstandort)5-10 Tage3.750-7.500 €
Security-Audit3-5 Tage2.500-4.000 €
Deployment + CI/CD3-4 Tage2.250-3.000 €
Gesamt82-117 Tage61.500-88.500 €

Hinweis: Bandbreiten aus DACH-Projekten; abhängig von Seniorität, Projekt-Scope und Region. Tagessatz: 750 €.

8.3 Hardware-Kosten

NFC-Tags (Beispiel: 500 Checkpoints):

  • 500x NTAG213 Sticker: 150-300 €
  • 500x NTAG 424 DNA (Security): 750-1.500 €

Smartphones (falls Neuanschaffung):

  • 10x Android (Samsung Galaxy A34): 3.500 €
  • 10x iPhone SE: 5.000 €

NFC-Reader (optional, Kiosk):

  • 2x ACR122U USB Reader: 60-100 €

8.4 Laufende Kosten (nach Launch)

  • Server/Hosting: 30-100 €/Monat (AWS/Hetzner, abhängig von Traffic)
  • Wartung/Support: 600-1.500 €/Monat (Bug-Fixes, OS-Updates, Feature-Requests)
  • DSGVO-Audit (jährlich): 1.500-3.000 €
  • Pentest (jährlich): 2.500-5.000 €

9. Wann NFC? Wann QR-Code?

KriteriumNFCQR-CodeEmpfehlung
Geschwindigkeit✅ 1-2 Sek (Tap)⚠️ 3-5 Sek (Kamera öffnen, fokussieren)🏆 NFC (schneller)
iOS-Support⚠️ Eingeschränkt (Foreground, User-Start)✅ Identisch zu Android🏆 QR (einfacher)
Android-Support✅ Voll (Background-Scan)✅ Voll⚖️ Gleichstand
Hardware-Anforderung⚠️ NFC-Chip nötig (nicht alle Androids!)✅ Nur Kamera (jedes Smartphone)🏆 QR (universeller)
Tag-Kosten⚠️ 0,30-3,00 € pro Tag✅ 0,01 € pro Print (Papier/Sticker)🏆 QR (billiger)
Fälschungssicherheit✅ Mit NTAG 424 DNA sehr gut⚠️ Leicht klonbar (Print/Copy)🏆 NFC (mit Security-Tags)
Outdoor-Tauglichkeit✅ Wetterfest (geschützte Tags)⚠️ Verblassen/Verschmutzen🏆 NFC (robuster)
Entwicklungskosten⚠️ +15-20% (iOS-Anpassungen)✅ Standard🏆 QR (günstiger)

💡 Faustregel:

  • NFC: Wenn Geschwindigkeit wichtig (Wächterkontrolle, High-Frequency Check-ins), Security relevant (Bezahlen, Zugang), Android-Fokus (>80% Android-User).
  • QR: Wenn Budget begrenzt (<20k), iOS-Nutzer dominant, Outdoor-Einsatz mit häufigem Tag-Austausch, keine Security-kritischen Daten.

Hybrid-Ansatz (beide Technologien):

  • Use-Case: Events mit gemischtem Publikum → NFC-Wristbands (schnell) + QR-Code-Fallback (für iOS-User ohne NFC-App-Erfahrung)
  • Kosten: +10-15% (beide Scan-Modi implementieren)

10. Checkliste: NFC-App-Projekt starten

Vor Projektstart

  • Zielgruppe analysieren: iOS/Android-Verteilung? NFC-verfügbare Geräte?
  • Use-Case definieren: Check-in? Wächterkontrolle? Bezahlen? Inventur?
  • iOS-Einschränkungen bewerten: Ist Foreground-Scan akzeptabel? Oder Android-Only?
  • Security-Level festlegen: Standard-Tags (NTAG213) oder Security-Tags (NTAG 424 DNA)?
  • Budget kalkulieren: 15k (Basic) vs. 50k (Business) vs. 80k (Enterprise)?

Technische Entscheidungen

  • Framework: Flutter (Cross-Platform) vs. Native (iOS/Android separat)?
  • Backend: Node.js, PHP, Python? Cloud (AWS) oder On-Prem?
  • Offline-Strategie: SQLite/SQLCipher + Sync? Oder Online-Only?
  • Tag-Typ: NTAG213 (Standard), NTAG 424 DNA (Security), MIFARE (Legacy)?
  • GPS-Validierung: Ja (für Wächterkontrolle/Outdoor) oder Nein (Indoor)?

Nach Entwicklung

  • Field-Test: Real-World-Testing mit Ziel-Hardware (iOS + Android)
  • Security-Audit: Tag-Cloning-Tests, Backend-Pentesting
  • DSGVO-Check: Datenschutzerklärung, AVV, Löschkonzept
  • User-Training: Besonders iOS-User (wie startet man NFC-Scan?)
  • Wartungsvertrag: Bug-Fixes, OS-Updates (iOS 18, Android 15, etc.)

11. Fazit: NFC-Apps sind schnell, aber iOS ist tricky

NFC-Apps sind perfekt für:

  • High-Frequency Check-ins (Wächterkontrolle, Mensa, Events)
  • Security-kritische Anwendungen (mit NTAG 424 DNA)
  • Offline-First Business-Apps (Baustellenkontrollen, Inventur)
  • Android-dominierte Zielgruppen (>70% Android)

Aber:

  • ⚠️ iOS ist restriktiver als Android (Foreground-only, User muss Scan starten)
  • ⚠️ Tag-Cloning-Risiko ohne Security-Maßnahmen (GPS, NTAG 424 DNA)
  • ⚠️ Entwicklungskosten +15-20% höher als QR-Code (iOS-Anpassungen)

Alternativen prüfen:

  • QR-Code: Wenn Budget <20k, iOS-Fokus, keine Security-Anforderungen
  • Hybrid (NFC + QR): Für gemischte Zielgruppen (z. B. Events)

Kosten-Richtwerte (Netto):

  • Check-in-App (Basic): 15-25k €, 2-3 Monate
  • Business-App (Offline + GPS): 35-55k €, 4-5 Monate
  • Enterprise (Security + Pentest): 60-80k €, 5-6 Monate

Hardware:

  • NTAG213 Tags: 0,30-0,60 € pro Stück
  • NTAG 424 DNA (Security): 1,50-3,00 € pro Stück
  • Smartphones: ab iPhone 7 (iOS), ab Android 4.4+ (mit NFC-Chip)

Du willst eine NFC-App entwickeln lassen?

Ich entwickle seit 25+ Jahren Business-Apps, davon 5+ Jahre mit NFC-Fokus (Wächterkontrolle, Check-in, Inventur). GPS, Offline-Sync und Security-by-Design sind meine Standards.

Meine NFC-Projekte:

  • FM 24 Wächterkontroll-App: NFC-Checkpoint-Scanning + GPS + Prüfintervalle
  • Mensa-App: NFC-Check-in + Master-Slave-Sync + Ampel-Status

Was du bekommst:

  • Realistische Einschätzung: iOS vs. Android, Kosten, Timeline
  • Security-by-Design: Tag-Cloning-Prevention, AES-256, GPS-Validierung
  • Offline-First: SQLite/SQLCipher + Sync (funktioniert auch ohne Netz)
  • DSGVO-konform: Datenschutz, AVV, Löschkonzept

Weitere hilfreiche Artikel:

  1. App-Entwicklung Kosten 2025 – Was kostet eine Business-App?
  2. Offline-App-Entwicklung 2025 – SQLite, SQLCipher, Sync-Strategien
  3. App-Sicherheit & DSGVO 2025 – Security-by-Design, OWASP
  4. Flutter App-Entwicklung 2025 – Der komplette Guide
  5. Business-App-Entwicklung 2025 – B2B-Apps für Unternehmen
  6. Native App vs. Cross-Platform 2025 – Wann Flutter?
  7. Android App-Entwicklung 2025 – Material Design 3
  8. iOS App-Entwicklung 2025 – Core NFC Basics
  9. MVP-Entwicklung 2025 – Schneller Launch mit Flutter
  10. App-Wartung & Support 2025 – Kosten nach Launch

Hinweis: Alle Preise netto.

Ihr App-Projekt besprechen?

Lassen Sie uns in einem kostenlosen Erstgespräch über Ihre Anforderungen sprechen.

Jetzt Kontakt aufnehmen