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
| Aspekt | Zusammenfassung |
|---|---|
| iOS vs. Android | iOS: 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) |
| Hardware | NFC-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-Cases | Check-in (Mensa, Events), Wächterkontrolle (FM 24), Bezahlen (Apple Pay/Google Pay API), Authentifizierung (2FA), Inventur |
| Kosten | 15-35k (einfache Check-in-App), 35-80k (Enterprise mit Offline-Sync, GPS, Security) |
| Timeline | 2-4 Monate (MVP), 4-6 Monate (Enterprise mit Backend) |
| Security | Tag-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:
- Reader/Writer Mode: Smartphone liest passive NFC-Tags (z. B. NTAG213). → Häufigster Mode für Apps
- Peer-to-Peer Mode: Zwei NFC-Geräte tauschen Daten aus (z. B. Android Beam, inzwischen deprecated)
- 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-Typ | Speicher | Kosten | Typische Nutzung |
|---|---|---|---|
| NTAG213 | 144 Byte | 0,30-0,60 € | Check-in, Marketing (günstig, einmalig beschreibbar) |
| NTAG215 | 504 Byte | 0,50-1,00 € | Längere URLs, mehrere Datensätze |
| NTAG216 | 888 Byte | 0,60-1,20 € | Komplexe Datenstrukturen |
| MIFARE Classic | 1-4 KB | 0,80-2,00 € | Älterer Standard (iOS nur mit Tricks lesbar!) |
| MIFARE Ultralight | 64 Byte | 0,30-0,50 € | Billig, wenig Speicher (Events, Einweg-Tickets) |
| ISO 15693 | 256 Byte - 8 KB | 1,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:
- Kein Background-Scan: App muss im Foreground sein. User muss explizit Scan starten (Button drücken).
- User-Session: Scan-Session muss vom User initiiert werden (keine automatische Tag-Erkennung wie bei Android).
- 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.
- 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:
- 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.
- Automatische Tag-Erkennung: User hält Smartphone an Tag → App öffnet automatisch (oder zeigt Dialog).
- Mehr Tag-Typen: NfcA, NfcB, NfcF, NfcV, IsoDep, MifareClassic, MifareUltralight, NdefFormatable.
- 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
| Feature | iOS (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-Typen | NDEF, 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ügbarkeit | iPhone 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 sensibel → Betriebsrat 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:
- Tag-UID auslesen (mit beliebiger NFC-App oder Reader)
- Leeren Tag mit gleicher UID beschreiben (UID-änderbare Tags: Chinese Magic Cards, ca. 1-2 € pro Stück)
- 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:
- Tag generiert bei jedem Scan einzigartige Signatur (AES-128-CMAC + Counter-basiert)
- App sendet Tag-UID + Signatur + Timestamp an Backend
- Backend validiert Signatur mit geheimem Key (nur Backend kennt Key)
- 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)
| Position | Aufwand | Kosten (Netto) |
|---|---|---|
| Anforderungsanalyse | 3-5 Tage | 2.500-4.000 € |
| UI/UX-Design | 8-12 Tage | 6.000-9.000 € |
| App-Entwicklung (Flutter) | 30-40 Tage | 22.500-30.000 € |
| Backend + API | 12-18 Tage | 9.000-13.500 € |
| Offline-Sync-Logik | 5-8 Tage | 3.750-6.000 € |
| Testing (Unit/Integration/E2E) | 8-10 Tage | 6.000-7.500 € |
| Feldtest/Rollout (Pilotstandort) | 5-10 Tage | 3.750-7.500 € |
| Security-Audit | 3-5 Tage | 2.500-4.000 € |
| Deployment + CI/CD | 3-4 Tage | 2.250-3.000 € |
| Gesamt | 82-117 Tage | 61.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?
| Kriterium | NFC | QR-Code | Empfehlung |
|---|---|---|---|
| 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:
- App-Entwicklung Kosten 2025 – Was kostet eine Business-App?
- Offline-App-Entwicklung 2025 – SQLite, SQLCipher, Sync-Strategien
- App-Sicherheit & DSGVO 2025 – Security-by-Design, OWASP
- Flutter App-Entwicklung 2025 – Der komplette Guide
- Business-App-Entwicklung 2025 – B2B-Apps für Unternehmen
- Native App vs. Cross-Platform 2025 – Wann Flutter?
- Android App-Entwicklung 2025 – Material Design 3
- iOS App-Entwicklung 2025 – Core NFC Basics
- MVP-Entwicklung 2025 – Schneller Launch mit Flutter
- 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