unfc
Version:
A framework-agnostic NFC package for reading/writing NFC tags in web apps and PWAs
187 lines (186 loc) • 6.87 kB
JavaScript
import { NfcErrorType, } from "./definitions.js";
import { WebNfc } from "./web.js";
import { IosBridgeNfc } from "./ios-bridge.js";
import { AndroidBridgeNfc } from "./android-bridge.js";
import { IosDetection } from "./ios-detection.js";
import { AndroidDetection } from "./android-detection.js";
/**
* Main NFC class that provides access to NFC functionality.
* It automatically chooses the appropriate implementation for the current platform.
*/
export class Nfc {
constructor() {
this.listeners = new Map();
this.iosInfo = IosDetection.getIosSupportInfo();
this.androidInfo = AndroidDetection.getAndroidSupportInfo();
// Choose the appropriate implementation based on platform detection
if (this.iosInfo.isIos &&
typeof window.nativeNfcBridge !== "undefined") {
console.log("Using iOS Native Bridge for NFC");
this.implementation = new IosBridgeNfc();
}
else if (this.androidInfo.isAndroid && this.androidInfo.useNativeBridge) {
console.log("Using Android Native Bridge for NFC");
this.implementation = new AndroidBridgeNfc();
}
else {
// Fall back to Web NFC for supported browsers
console.log("Using Web NFC implementation");
this.implementation = new WebNfc();
}
// Set up status monitoring to track NFC availability
this.monitorNfcStatus();
}
/**
* Internal method to monitor NFC status changes
*/
async monitorNfcStatus() {
try {
// Set up listener for NFC status changes from implementation
await this.implementation.addListener("nfcStatusChanged", (status) => {
// Propagate to our own listeners
this.notifyListeners("nfcStatusChanged", status);
});
}
catch (error) {
console.warn("Failed to set up NFC status monitoring:", error);
}
}
/**
* Check if NFC is enabled (Android) or available (iOS/Web).
* @returns Promise resolving to an object with an `enabled` boolean property
*/
async isEnabled() {
try {
return await this.implementation.isEnabled();
}
catch (error) {
console.error("Error checking NFC status:", error);
return { enabled: false };
}
}
/**
* Open NFC settings (Android) or app settings (iOS) or shows guidance (Web).
* This helps users enable NFC if it's disabled.
*/
async openSettings() {
return this.implementation.openSettings();
}
/**
* Start scanning for NFC tags.
* @param options Configuration options for the scan session
*/
async startScanSession(options) {
var _a, _b, _c;
try {
return await this.implementation.startScanSession(options);
}
catch (error) {
// Convert to a standardized error object if possible
const nfcError = new Error(error.message || "Failed to start NFC scan");
if (((_a = error.message) === null || _a === void 0 ? void 0 : _a.includes("not supported")) ||
error.name === "NotSupportedError") {
nfcError.code = NfcErrorType.NOT_SUPPORTED;
}
else if (((_b = error.message) === null || _b === void 0 ? void 0 : _b.includes("permission")) ||
error.name === "NotAllowedError") {
nfcError.code = NfcErrorType.PERMISSION_DENIED;
}
else if ((_c = error.message) === null || _c === void 0 ? void 0 : _c.includes("not enabled")) {
nfcError.code = NfcErrorType.NOT_ENABLED;
}
else {
nfcError.code = NfcErrorType.UNEXPECTED_ERROR;
}
throw nfcError;
}
}
/**
* Stop the current NFC scan session.
*/
async stopScanSession() {
return this.implementation.stopScanSession();
}
/**
* Write an NDEF message to an NFC tag.
* @param options Object containing the NDEF message to write
*/
async write(options) {
return this.implementation.write(options);
}
/**
* Make an NFC tag read-only.
* WARNING: This is a permanent operation that cannot be undone.
*/
async makeReadOnly() {
return this.implementation.makeReadOnly();
}
/**
* Format an NFC tag, erasing its contents and preparing it for writing.
*/
async format() {
return this.implementation.format();
}
/**
* Erase the contents of an NFC tag.
*/
async erase() {
return this.implementation.erase();
}
/**
* Share NDEF data via NFC (Android only, not available on iOS or Web).
* @param options Object containing the NDEF message to share
*/
async share(options) {
return this.implementation.share(options);
}
/**
* Stop sharing NDEF data via NFC (Android only).
*/
async stopSharing() {
return this.implementation.stopSharing();
}
async addListener(eventName, listenerFunc) {
var _a;
// Add to our internal listener registry
if (!this.listeners.has(eventName)) {
this.listeners.set(eventName, new Set());
}
(_a = this.listeners.get(eventName)) === null || _a === void 0 ? void 0 : _a.add(listenerFunc);
// Register with the implementation
const handle = await this.implementation.addListener(eventName, listenerFunc);
// Return a handle that will clean up properly
return {
remove: async () => {
var _a;
(_a = this.listeners.get(eventName)) === null || _a === void 0 ? void 0 : _a.delete(listenerFunc);
return handle.remove();
},
};
}
/**
* Remove all event listeners registered for this plugin.
*/
async removeAllListeners() {
// Clear our internal listener registry
this.listeners.clear();
// Remove listeners from the implementation
return this.implementation.removeAllListeners();
}
/**
* Internal method to notify listeners of events
*/
notifyListeners(eventName, data) {
const listeners = this.listeners.get(eventName);
if (listeners) {
for (const listener of listeners) {
try {
listener(data);
}
catch (error) {
console.error(`Error in ${eventName} listener:`, error);
}
}
}
}
}