Web NFC isn't exposed in Capacitor's WebView, so the APK needs a native writer.
Adds packages/skatespots-nfc — a local Capacitor Android plugin (Kotlin,
enableReaderMode + NDEF URL record), registered BY NAME (not bundled). lib/nfc.ts
now uses the plugin on native and Web NFC on the web. iOS can't write tags.
⚠️ UNVERIFIED (needs cap sync + a device). README documents it.
49 lines
1.8 KiB
TypeScript
49 lines
1.8 KiB
TypeScript
/**
|
|
* NFC tag writing.
|
|
*
|
|
* Two paths, one purpose — write ONLY the verify URL (the same pointer the QR
|
|
* carries). A tag is passive and clonable, exactly like copying a QR; the trust
|
|
* still comes from the signature on the relay.
|
|
*
|
|
* • Native (Capacitor APK): the local `SkateSpotsNfc` Android plugin, registered
|
|
* by name — Web NFC isn't exposed in the WebView.
|
|
* • Web (Chrome on Android over HTTPS): Web NFC (`NDEFReader`).
|
|
*
|
|
* iOS can't write tags either way; reading works everywhere by tapping.
|
|
*/
|
|
import { Capacitor, registerPlugin } from '@capacitor/core';
|
|
|
|
interface NativeNfc {
|
|
isSupported(): Promise<{ supported: boolean }>;
|
|
writeUrl(options: { url: string }): Promise<void>;
|
|
cancel(): Promise<void>;
|
|
}
|
|
const NativeNfc = registerPlugin<NativeNfc>('SkateSpotsNfc');
|
|
|
|
interface NdefWriter {
|
|
write(message: { records: Array<{ recordType: string; data: string }> }): Promise<void>;
|
|
}
|
|
type NdefCtor = new () => NdefWriter;
|
|
|
|
function ndefCtor(): NdefCtor | undefined {
|
|
if (typeof window === 'undefined') return undefined;
|
|
return (window as unknown as { NDEFReader?: NdefCtor }).NDEFReader;
|
|
}
|
|
|
|
/** Whether we can attempt a write here. On native the plugin validates the adapter. */
|
|
export function isNfcSupported(): boolean {
|
|
if (Capacitor.isNativePlatform()) return true;
|
|
return !!ndefCtor();
|
|
}
|
|
|
|
/** Write a URL record to an NFC tag. Rejects if unsupported or the write fails. */
|
|
export async function writeNfcUrl(url: string): Promise<void> {
|
|
if (Capacitor.isNativePlatform()) {
|
|
await NativeNfc.writeUrl({ url });
|
|
return;
|
|
}
|
|
const Ctor = ndefCtor();
|
|
if (!Ctor) throw new Error('NFC writing is not supported on this device/browser.');
|
|
const writer = new Ctor();
|
|
await writer.write({ records: [{ recordType: 'url', data: url }] });
|
|
}
|