UNPKG

unfc

Version:

A framework-agnostic NFC package for reading/writing NFC tags in web apps and PWAs

136 lines (135 loc) 4.91 kB
/** * NFC implementation that communicates with a native iOS app via a bridge * Note: This requires custom implementation in a native iOS app */ export class IosBridgeNfc { constructor() { this.listeners = {}; this.isBridgeAvailable = false; // Look for the bridge in the global scope // The native app needs to inject this object this.bridge = window.nativeNfcBridge || {}; this.isBridgeAvailable = !!(this.bridge.isNfcEnabled && this.bridge.startNfcScan); // Set up message listener for tag detection events from native app if (this.isBridgeAvailable) { window.addEventListener('message', this.handleNativeMessage.bind(this)); console.log('iOS NFC bridge initialized'); } else { console.warn('iOS NFC bridge not found'); } } handleNativeMessage(event) { if (!event.data || typeof event.data !== 'object') return; // Handle tag detected message from native app if (event.data.type === 'nfcTagDetected' && event.data.tag) { const tagListeners = this.listeners['tagDetected'] || []; const tag = event.data.tag; for (const listener of tagListeners) { listener(tag); } } // Handle NFC status change from native app if (event.data.type === 'nfcStatusChanged' && event.data.enabled !== undefined) { const statusListeners = this.listeners['nfcStatusChanged'] || []; for (const listener of statusListeners) { listener({ enabled: !!event.data.enabled }); } } } async isEnabled() { if (!this.isBridgeAvailable) { return { enabled: false }; } try { const enabled = await this.bridge.isNfcEnabled(); return { enabled }; } catch (error) { console.error('Error checking NFC status through bridge:', error); return { enabled: false }; } } async openSettings() { if (!this.isBridgeAvailable || !this.bridge.openSettings) { throw new Error('NFC settings cannot be opened - bridge not available'); } try { await this.bridge.openSettings(); } catch (error) { console.error('Error opening NFC settings through bridge:', error); throw error; } } async startScanSession(options) { if (!this.isBridgeAvailable) { throw new Error('NFC scan cannot be started - bridge not available'); } try { await this.bridge.startNfcScan(JSON.stringify(options || {})); } catch (error) { console.error('Error starting NFC scan through bridge:', error); throw error; } } async stopScanSession() { if (!this.isBridgeAvailable || !this.bridge.stopNfcScan) { return; // Just silently return if bridge not available } try { await this.bridge.stopNfcScan(); } catch (error) { console.error('Error stopping NFC scan through bridge:', error); } } async write(options) { if (!this.isBridgeAvailable || !this.bridge.writeNfcTag) { throw new Error('NFC write is not supported - bridge not available'); } try { await this.bridge.writeNfcTag(JSON.stringify(options)); } catch (error) { console.error('Error writing NFC tag through bridge:', error); throw error; } } async makeReadOnly() { throw new Error('makeReadOnly is not implemented in the iOS bridge'); } async format() { throw new Error('format is not implemented in the iOS bridge'); } async erase() { throw new Error('erase is not implemented in the iOS bridge'); } async share() { throw new Error('share is not supported in iOS'); } async stopSharing() { throw new Error('share is not supported in iOS'); } async addListener(eventName, listenerFunc) { if (!this.listeners[eventName]) { this.listeners[eventName] = []; } this.listeners[eventName].push(listenerFunc); return { remove: async () => { this.removeListener(eventName, listenerFunc); }, }; } removeListener(eventName, listenerFunc) { if (this.listeners[eventName]) { this.listeners[eventName] = this.listeners[eventName].filter(listener => listener !== listenerFunc); } } async removeAllListeners() { this.listeners = {}; } }