Files
Vorrania/ios/Sources/NFCViews.swift
T
ScarriffleandClaude Opus 5 140b81798c NFC: Entitlement TAG statt NDEF, Tag-Session statt NDEF-Session
Der Upload nach App Store Connect scheiterte an der Entitlement-Pruefung:
"NDEF is disallowed" und "TAG is missing in the entitlement". Apple hat den Wert
NDEF zugunsten von TAG abgeloest; mit dem SDK von iOS 26/27 wird er abgelehnt.

TAG ist der Wert fuer NFCTagReaderSession, deshalb laeuft der Lese- und
Schreibweg jetzt darueber statt ueber NFCNDEFReaderSession. Die NDEF-Befehle
bleiben dabei vollstaendig erhalten: alle vier Tag-Protokolle (MiFare, ISO7816,
ISO15693, FeliCa) erben laut SDK-Header von NFCNDEFTag, also gibt es weiterhin
queryNDEFStatus, readNDEF, writeNDEF und writeLock. Gepollt wird iso14443 (die
ueblichen NTAG-Aufkleber) und iso15693 (Waeschetags mancher Hersteller).

Die eigene Klasse hiess NFCTag und kollidierte damit mit dem gleichnamigen
CoreNFC-Protokoll, das der neue Weg braucht - sie heisst jetzt NFCDienst.

Info.plist enthaelt ausserdem die Neuformatierung durch Xcode (Schluessel
sortiert, Kommentare entfernt). Inhaltlich unveraendert.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-12 13:48:40 +02:00

125 lines
4.1 KiB
Swift
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import SwiftUI
/// Ein NFC-Tag mit dem Link auf ein Einzelstück beschreiben.
///
/// Gedacht für Kleidung: Das Tag wird eingenäht und ersetzt den QR, der die
/// Wäsche nicht überstehen würde. Auf das Tag kommt genau das, was auch im QR
/// steht – `vorrania://i/<UID>`.
struct NFCSchreibenView: View {
let item: Item
@Environment(\.dismiss) private var dismiss
@State private var sperren = false
@State private var laeuft = false
@State private var erfolg = false
@State private var fehler: String?
private var nutzlast: String { einzelstueckLink(fuer: item.uid) }
var body: some View {
Form {
Section {
if let name = item.productName {
LabeledContent("Artikel", value: name)
}
LabeledContent("UID", value: item.uid)
} footer: {
Text("Auf das Tag wird geschrieben: \(nutzlast)")
}
Section {
Toggle("Tag dauerhaft schreibschützen", isOn: $sperren)
} footer: {
if sperren {
Text("Das lässt sich nicht rückgängig machen. Das Tag gehört danach "
+ "für immer zu diesem Einzelstück und kann nicht neu beschrieben werden.")
.foregroundStyle(.orange)
} else {
Text("Ohne Schreibschutz kannst du das Tag später einem anderen "
+ "Einzelstück zuweisen.")
}
}
Section {
Button(laeuft ? "Tag anhalten…" : "Tag beschreiben") {
Task { await schreiben() }
}
.disabled(laeuft)
}
if erfolg {
Section {
Label("Tag beschrieben.", systemImage: "checkmark.circle")
.foregroundStyle(.green)
}
}
if let fehler {
Section {
Text(fehler).foregroundStyle(.red).font(.callout)
}
}
}
.navigationTitle("NFC-Tag")
.navigationBarTitleDisplayMode(.inline)
.toolbar { ToolbarItem(placement: .topBarLeading) { Button("Fertig") { dismiss() } } }
}
private func schreiben() async {
laeuft = true
fehler = nil
erfolg = false
defer { laeuft = false }
do {
try await NFCDienst.schreiben(nutzlast, sperren: sperren)
erfolg = true
} catch NFCDienst.Fehler.abgebrochen {
// Kein Fehler, sondern eine Entscheidung – nichts anzeigen.
} catch {
fehler = error.localizedDescription
}
}
}
/// Knopf, der ein NFC-Tag liest und die gefundene Einzelstück-UID zurückgibt.
///
/// Blendet sich auf Geräten ohne NFC (iPad) selbst aus, damit die umgebenden
/// Ansichten das nicht jedes Mal selbst prüfen müssen.
struct NFCLesenButton: View {
var titel: String = "NFC-Tag lesen"
var onUid: (String) -> Void
var onFehler: (String) -> Void
@State private var laeuft = false
var body: some View {
if NFCDienst.verfuegbar {
Button {
Task { await lesen() }
} label: {
Label(laeuft ? "Tag anhalten…" : titel, systemImage: "wave.3.right")
}
.disabled(laeuft)
}
}
private func lesen() async {
laeuft = true
defer { laeuft = false }
do {
let roh = try await NFCDienst.lesen()
// Ein selbst beschriebenes Tag darf auch die nackte UID tragen – anders
// als bei der Kamera droht hier keine Verwechslung mit einem Barcode.
guard let uid = einzelstueckCode(aus: roh, nackteUidErlauben: true) else {
onFehler("Auf dem Tag steht kein Einzelstück: \(roh)")
return
}
onUid(uid)
} catch NFCDienst.Fehler.abgebrochen {
// Nutzer hat abgebrochen – keine Meldung.
} catch {
onFehler(error.localizedDescription)
}
}
}