unfc
Version:
A framework-agnostic NFC package for reading/writing NFC tags in web apps and PWAs
182 lines (181 loc) • 6.54 kB
JavaScript
/**
* NFC implementation that communicates with a native Android app via a bridge
* This provides better integration with Capacitor Android projects
*/
export class AndroidBridgeNfc {
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.nativeAndroidNfcBridge || {};
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("Android NFC bridge initialized");
}
else {
console.warn("Android 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.openNfcSettings) {
throw new Error("NFC settings cannot be opened - bridge not available");
}
try {
await this.bridge.openNfcSettings();
}
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() {
if (!this.isBridgeAvailable || !this.bridge.makeNfcTagReadOnly) {
throw new Error("makeReadOnly is not implemented in the Android bridge");
}
try {
await this.bridge.makeNfcTagReadOnly();
}
catch (error) {
console.error("Error making NFC tag read-only through bridge:", error);
throw error;
}
}
async format() {
if (!this.isBridgeAvailable || !this.bridge.formatNfcTag) {
throw new Error("format is not implemented in the Android bridge");
}
try {
await this.bridge.formatNfcTag();
}
catch (error) {
console.error("Error formatting NFC tag through bridge:", error);
throw error;
}
}
async erase() {
if (!this.isBridgeAvailable || !this.bridge.eraseNfcTag) {
throw new Error("erase is not implemented in the Android bridge");
}
try {
await this.bridge.eraseNfcTag();
}
catch (error) {
console.error("Error erasing NFC tag through bridge:", error);
throw error;
}
}
async share(options) {
if (!this.isBridgeAvailable || !this.bridge.shareNfcData) {
throw new Error("share is not implemented in the Android bridge");
}
try {
await this.bridge.shareNfcData(JSON.stringify(options));
}
catch (error) {
console.error("Error sharing NFC data through bridge:", error);
throw error;
}
}
async stopSharing() {
if (!this.isBridgeAvailable || !this.bridge.stopNfcSharing) {
throw new Error("stopSharing is not implemented in the Android bridge");
}
try {
await this.bridge.stopNfcSharing();
}
catch (error) {
console.error("Error stopping NFC sharing through bridge:", error);
throw error;
}
}
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 = {};
}
}