@capgo/capacitor-nfc
Advanced tools
@@ -42,3 +42,3 @@ package app.capgo.nfc; | ||
| private static final String pluginVersion = "7.0.5"; | ||
| private static final int DEFAULT_READER_FLAGS = | ||
| static final int DEFAULT_READER_FLAGS = | ||
| NfcAdapter.FLAG_READER_NFC_A | | ||
@@ -48,3 +48,2 @@ NfcAdapter.FLAG_READER_NFC_B | | ||
| NfcAdapter.FLAG_READER_NFC_V | | ||
| NfcAdapter.FLAG_READER_SKIP_NDEF_CHECK | | ||
| NfcAdapter.FLAG_READER_NO_PLATFORM_SOUNDS; | ||
@@ -174,2 +173,4 @@ | ||
| } | ||
| } catch (SecurityException | IllegalStateException e) { | ||
| call.reject("Tag connection lost.", e); | ||
| } catch (IOException e) { | ||
@@ -323,2 +324,4 @@ call.reject("Failed to make the tag read only.", e); | ||
| } | ||
| } catch (SecurityException | IllegalStateException e) { | ||
| call.reject("Tag connection lost.", e); | ||
| } catch (IOException | FormatException e) { | ||
@@ -325,0 +328,0 @@ call.reject("Failed to write NDEF message.", e); |
+41
-1
@@ -215,2 +215,26 @@ { | ||
| "slug": "addlistenernfcstatechange-" | ||
| }, | ||
| { | ||
| "name": "addListener", | ||
| "signature": "(eventName: 'nfcSessionEnd', listenerFunc: (event: NfcSessionEndEvent) => void) => Promise<PluginListenerHandle>", | ||
| "parameters": [ | ||
| { | ||
| "name": "eventName", | ||
| "docs": "", | ||
| "type": "'nfcSessionEnd'" | ||
| }, | ||
| { | ||
| "name": "listenerFunc", | ||
| "docs": "", | ||
| "type": "(event: NfcSessionEndEvent) => void" | ||
| } | ||
| ], | ||
| "returns": "Promise<PluginListenerHandle>", | ||
| "tags": [], | ||
| "docs": "", | ||
| "complexTypes": [ | ||
| "PluginListenerHandle", | ||
| "NfcSessionEndEvent" | ||
| ], | ||
| "slug": "addlistenernfcsessionend-" | ||
| } | ||
@@ -261,3 +285,3 @@ ], | ||
| "tags": [], | ||
| "docs": "Android-only: raw flags passed to `NfcAdapter.enableReaderMode`.\nDefaults to enabling all tag types with skipping NDEF checks.", | ||
| "docs": "Android-only: raw flags passed to `NfcAdapter.enableReaderMode`.\nDefaults to enabling all tag types and Android's NDEF discovery so that\ndetected tags remain available for writing and formatting.", | ||
| "complexTypes": [], | ||
@@ -475,2 +499,18 @@ "type": "number | undefined" | ||
| ] | ||
| }, | ||
| { | ||
| "name": "NfcSessionEndEvent", | ||
| "slug": "nfcsessionendevent", | ||
| "docs": "Event emitted when an iOS NFC reader session ends.\n\nThis event is not emitted when a session closes normally after its first successful read.", | ||
| "tags": [], | ||
| "methods": [], | ||
| "properties": [ | ||
| { | ||
| "name": "reason", | ||
| "tags": [], | ||
| "docs": "", | ||
| "complexTypes": [], | ||
| "type": "'userCancelled' | 'sessionTimeout' | 'invalidated'" | ||
| } | ||
| ] | ||
| } | ||
@@ -477,0 +517,0 @@ ], |
@@ -129,3 +129,4 @@ import type { PluginListenerHandle } from '@capacitor/core'; | ||
| * Android-only: raw flags passed to `NfcAdapter.enableReaderMode`. | ||
| * Defaults to enabling all tag types with skipping NDEF checks. | ||
| * Defaults to enabling all tag types and Android's NDEF discovery so that | ||
| * detected tags remain available for writing and formatting. | ||
| */ | ||
@@ -162,2 +163,10 @@ androidReaderModeFlags?: number; | ||
| /** | ||
| * Event emitted when an iOS NFC reader session ends. | ||
| * | ||
| * This event is not emitted when a session closes normally after its first successful read. | ||
| */ | ||
| export interface NfcSessionEndEvent { | ||
| reason: 'userCancelled' | 'sessionTimeout' | 'invalidated'; | ||
| } | ||
| /** | ||
| * Public API surface for the Capacitor NFC plugin. | ||
@@ -229,3 +238,4 @@ * | ||
| addListener(eventName: 'nfcStateChange', listenerFunc: (event: NfcStateChangeEvent) => void): Promise<PluginListenerHandle>; | ||
| addListener(eventName: 'nfcSessionEnd', listenerFunc: (event: NfcSessionEndEvent) => void): Promise<PluginListenerHandle>; | ||
| } | ||
| export type { PluginListenerHandle } from '@capacitor/core'; |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"definitions.js","sourceRoot":"","sources":["../../src/definitions.ts"],"names":[],"mappings":"","sourcesContent":["import type { PluginListenerHandle } from '@capacitor/core';\n\n/**\n * Possible NFC adapter states returned by {@link CapacitorNfcPlugin.getStatus}.\n *\n * Matches the constants provided by the original PhoneGap NFC plugin for\n * compatibility with existing applications.\n */\nexport type NfcStatus = 'NFC_OK' | 'NO_NFC' | 'NFC_DISABLED' | 'NDEF_PUSH_DISABLED';\n\n/**\n * Event type describing the kind of NFC discovery that happened.\n *\n * - `tag`: A generic NFC tag (no NDEF payload).\n * - `ndef`: A tag exposing an NDEF payload.\n * - `ndef-mime`: An NDEF tag that matched one of the MIME type filters.\n * - `ndef-formatable`: A tag that can be formatted to NDEF.\n */\nexport type NfcEventType = 'tag' | 'ndef' | 'ndef-mime' | 'ndef-formatable';\n\n/**\n * iOS-specific polling options for NFC scanning sessions.\n * These options determine the type of tags that a reader session\n * should detect during a polling sequence.\n *\n * - 'iso14443': Polls for ISO 14443 tags\n * - 'iso15693': Polls for ISO 15693 tags\n * - 'iso18092': Polls for ISO 18092 tags\n * - 'pace': Polls for PACE tags (available on iOS 16 and later)\n */\nexport type NfcIosPollingOption = 'iso14443' | 'iso15693' | 'iso18092' | 'pace';\n\n/**\n * JSON structure representing a single NDEF record.\n *\n * Mirrors the data format returned by the legacy Cordova implementation and\n * uses integer arrays instead of strings to preserve the original payload\n * bytes.\n */\nexport interface NdefRecord {\n /**\n * Type Name Format identifier.\n */\n tnf: number;\n /**\n * Type field expressed as an array of byte values.\n */\n type: number[];\n /**\n * Record identifier expressed as an array of byte values.\n */\n id: number[];\n /**\n * Raw payload expressed as an array of byte values.\n */\n payload: number[];\n}\n\n/**\n * Representation of the full tag information returned by the native layers.\n *\n * Supports standard NFC Forum tags as well as MIFARE Ultralight cards (including\n * EV1 and NTAG variants). NDEF data is automatically extracted from MIFARE Ultralight\n * tags when available.\n */\nexport interface NfcTag {\n /**\n * Raw identifier bytes for the tag.\n */\n id?: number[];\n /**\n * List of Android tech strings (e.g. `android.nfc.tech.Ndef`).\n */\n techTypes?: string[];\n /**\n * Human readable tag type when available (e.g. `NFC Forum Type 2`, `MIFARE Ultralight`).\n */\n type?: string | null;\n /**\n * Maximum writable size in bytes for tags that expose NDEF information.\n */\n maxSize?: number | null;\n /**\n * Indicates whether the tag can be written to.\n */\n isWritable?: boolean | null;\n /**\n * Indicates whether the tag can be permanently locked.\n */\n canMakeReadOnly?: boolean | null;\n /**\n * Array of NDEF records discovered on the tag.\n */\n ndefMessage?: NdefRecord[] | null;\n}\n\n/**\n * Generic NFC discovery event dispatched by the plugin.\n */\nexport interface NfcEvent {\n type: NfcEventType;\n tag: NfcTag;\n}\n\n/**\n * Options controlling the behaviour of {@link CapacitorNfcPlugin.startScanning}.\n */\nexport interface StartScanningOptions {\n /**\n * iOS-only: closes the NFC session automatically after the first successful tag read.\n * Defaults to `true`.\n */\n invalidateAfterFirstRead?: boolean;\n /**\n * iOS-only: custom message displayed in the NFC system sheet while scanning.\n */\n alertMessage?: string;\n /**\n * iOS-only: session type to use for NFC scanning.\n * - `'ndef'`: Uses NFCNDEFReaderSession (default). Only detects NDEF-formatted tags.\n * - `'tag'`: Uses NFCTagReaderSession. Detects both NDEF and non-NDEF tags (e.g., raw MIFARE tags).\n * Allows reading UID from unformatted tags.\n * **Requires** the `Near Field Communication Tag Reader Session Formats` entitlement\n * in your app with the `TAG` format included. Without it the session will fail to\n * start and the promise will reject with a `NO_NFC` error code.\n * Defaults to `'ndef'` for backward compatibility.\n */\n iosSessionType?: 'ndef' | 'tag';\n /**\n * iOS-only: polling options to use for NFC scanning.\n * Defaults to `['iso14443', 'iso15693', 'iso18092']` for backward compatibility.\n */\n iosPollingOptions?: NfcIosPollingOption[];\n /**\n * Android-only: raw flags passed to `NfcAdapter.enableReaderMode`.\n * Defaults to enabling all tag types with skipping NDEF checks.\n */\n androidReaderModeFlags?: number;\n}\n\n/**\n * Options used when writing an NDEF message on the current tag.\n */\nexport interface WriteTagOptions {\n /**\n * Array of records that compose the NDEF message to be written.\n */\n records: NdefRecord[];\n /**\n * When `true`, the plugin attempts to format NDEF-formattable tags before writing.\n * Defaults to `true`.\n */\n allowFormat?: boolean;\n}\n\n/**\n * Options used when sharing an NDEF message with another device using Android Beam / P2P mode.\n */\nexport interface ShareTagOptions {\n records: NdefRecord[];\n}\n\n/**\n * Event emitted whenever the NFC adapter availability changes.\n */\nexport interface NfcStateChangeEvent {\n status: NfcStatus;\n enabled: boolean;\n}\n\n/**\n * Public API surface for the Capacitor NFC plugin.\n *\n * The interface intentionally mirrors the behaviour of the reference PhoneGap\n * implementation to ease migration while embracing idiomatic Capacitor APIs.\n */\nexport interface CapacitorNfcPlugin {\n /**\n * Starts listening for NFC tags.\n */\n startScanning(options?: StartScanningOptions): Promise<void>;\n /**\n * Stops the ongoing NFC scanning session.\n */\n stopScanning(): Promise<void>;\n /**\n * Writes the provided NDEF records to the last discovered tag.\n */\n write(options: WriteTagOptions): Promise<void>;\n /**\n * Attempts to erase the last discovered tag by writing an empty NDEF message.\n */\n erase(): Promise<void>;\n /**\n * Attempts to make the last discovered tag read-only.\n */\n makeReadOnly(): Promise<void>;\n /**\n * Shares an NDEF message with another device via peer-to-peer (Android only).\n */\n share(options: ShareTagOptions): Promise<void>;\n /**\n * Stops sharing previously provided NDEF message (Android only).\n */\n unshare(): Promise<void>;\n /**\n * Returns the current NFC adapter status.\n */\n getStatus(): Promise<{ status: NfcStatus }>;\n /**\n * Opens the system settings page where the user can enable NFC.\n */\n showSettings(): Promise<void>;\n /**\n * Returns the version string baked into the native plugin.\n */\n getPluginVersion(): Promise<{ version: string }>;\n /**\n * Checks whether the device has NFC hardware support.\n *\n * Returns `true` if NFC hardware is present on the device, regardless of\n * whether NFC is currently enabled or disabled. Returns `false` if the\n * device does not have NFC hardware.\n *\n * Use this method to determine if NFC features should be shown in your\n * app's UI. To check if NFC is currently enabled, use `getStatus()`.\n */\n isSupported(): Promise<{ supported: boolean }>;\n\n addListener(eventName: 'nfcEvent', listenerFunc: (event: NfcEvent) => void): Promise<PluginListenerHandle>;\n addListener(\n eventName: 'tagDiscovered' | 'ndefDiscovered' | 'ndefMimeDiscovered' | 'ndefFormatableDiscovered',\n listenerFunc: (event: NfcEvent) => void,\n ): Promise<PluginListenerHandle>;\n addListener(\n eventName: 'nfcStateChange',\n listenerFunc: (event: NfcStateChangeEvent) => void,\n ): Promise<PluginListenerHandle>;\n}\n\nexport type { PluginListenerHandle } from '@capacitor/core';\n"]} | ||
| {"version":3,"file":"definitions.js","sourceRoot":"","sources":["../../src/definitions.ts"],"names":[],"mappings":"","sourcesContent":["import type { PluginListenerHandle } from '@capacitor/core';\n\n/**\n * Possible NFC adapter states returned by {@link CapacitorNfcPlugin.getStatus}.\n *\n * Matches the constants provided by the original PhoneGap NFC plugin for\n * compatibility with existing applications.\n */\nexport type NfcStatus = 'NFC_OK' | 'NO_NFC' | 'NFC_DISABLED' | 'NDEF_PUSH_DISABLED';\n\n/**\n * Event type describing the kind of NFC discovery that happened.\n *\n * - `tag`: A generic NFC tag (no NDEF payload).\n * - `ndef`: A tag exposing an NDEF payload.\n * - `ndef-mime`: An NDEF tag that matched one of the MIME type filters.\n * - `ndef-formatable`: A tag that can be formatted to NDEF.\n */\nexport type NfcEventType = 'tag' | 'ndef' | 'ndef-mime' | 'ndef-formatable';\n\n/**\n * iOS-specific polling options for NFC scanning sessions.\n * These options determine the type of tags that a reader session\n * should detect during a polling sequence.\n *\n * - 'iso14443': Polls for ISO 14443 tags\n * - 'iso15693': Polls for ISO 15693 tags\n * - 'iso18092': Polls for ISO 18092 tags\n * - 'pace': Polls for PACE tags (available on iOS 16 and later)\n */\nexport type NfcIosPollingOption = 'iso14443' | 'iso15693' | 'iso18092' | 'pace';\n\n/**\n * JSON structure representing a single NDEF record.\n *\n * Mirrors the data format returned by the legacy Cordova implementation and\n * uses integer arrays instead of strings to preserve the original payload\n * bytes.\n */\nexport interface NdefRecord {\n /**\n * Type Name Format identifier.\n */\n tnf: number;\n /**\n * Type field expressed as an array of byte values.\n */\n type: number[];\n /**\n * Record identifier expressed as an array of byte values.\n */\n id: number[];\n /**\n * Raw payload expressed as an array of byte values.\n */\n payload: number[];\n}\n\n/**\n * Representation of the full tag information returned by the native layers.\n *\n * Supports standard NFC Forum tags as well as MIFARE Ultralight cards (including\n * EV1 and NTAG variants). NDEF data is automatically extracted from MIFARE Ultralight\n * tags when available.\n */\nexport interface NfcTag {\n /**\n * Raw identifier bytes for the tag.\n */\n id?: number[];\n /**\n * List of Android tech strings (e.g. `android.nfc.tech.Ndef`).\n */\n techTypes?: string[];\n /**\n * Human readable tag type when available (e.g. `NFC Forum Type 2`, `MIFARE Ultralight`).\n */\n type?: string | null;\n /**\n * Maximum writable size in bytes for tags that expose NDEF information.\n */\n maxSize?: number | null;\n /**\n * Indicates whether the tag can be written to.\n */\n isWritable?: boolean | null;\n /**\n * Indicates whether the tag can be permanently locked.\n */\n canMakeReadOnly?: boolean | null;\n /**\n * Array of NDEF records discovered on the tag.\n */\n ndefMessage?: NdefRecord[] | null;\n}\n\n/**\n * Generic NFC discovery event dispatched by the plugin.\n */\nexport interface NfcEvent {\n type: NfcEventType;\n tag: NfcTag;\n}\n\n/**\n * Options controlling the behaviour of {@link CapacitorNfcPlugin.startScanning}.\n */\nexport interface StartScanningOptions {\n /**\n * iOS-only: closes the NFC session automatically after the first successful tag read.\n * Defaults to `true`.\n */\n invalidateAfterFirstRead?: boolean;\n /**\n * iOS-only: custom message displayed in the NFC system sheet while scanning.\n */\n alertMessage?: string;\n /**\n * iOS-only: session type to use for NFC scanning.\n * - `'ndef'`: Uses NFCNDEFReaderSession (default). Only detects NDEF-formatted tags.\n * - `'tag'`: Uses NFCTagReaderSession. Detects both NDEF and non-NDEF tags (e.g., raw MIFARE tags).\n * Allows reading UID from unformatted tags.\n * **Requires** the `Near Field Communication Tag Reader Session Formats` entitlement\n * in your app with the `TAG` format included. Without it the session will fail to\n * start and the promise will reject with a `NO_NFC` error code.\n * Defaults to `'ndef'` for backward compatibility.\n */\n iosSessionType?: 'ndef' | 'tag';\n /**\n * iOS-only: polling options to use for NFC scanning.\n * Defaults to `['iso14443', 'iso15693', 'iso18092']` for backward compatibility.\n */\n iosPollingOptions?: NfcIosPollingOption[];\n /**\n * Android-only: raw flags passed to `NfcAdapter.enableReaderMode`.\n * Defaults to enabling all tag types and Android's NDEF discovery so that\n * detected tags remain available for writing and formatting.\n */\n androidReaderModeFlags?: number;\n}\n\n/**\n * Options used when writing an NDEF message on the current tag.\n */\nexport interface WriteTagOptions {\n /**\n * Array of records that compose the NDEF message to be written.\n */\n records: NdefRecord[];\n /**\n * When `true`, the plugin attempts to format NDEF-formattable tags before writing.\n * Defaults to `true`.\n */\n allowFormat?: boolean;\n}\n\n/**\n * Options used when sharing an NDEF message with another device using Android Beam / P2P mode.\n */\nexport interface ShareTagOptions {\n records: NdefRecord[];\n}\n\n/**\n * Event emitted whenever the NFC adapter availability changes.\n */\nexport interface NfcStateChangeEvent {\n status: NfcStatus;\n enabled: boolean;\n}\n\n/**\n * Event emitted when an iOS NFC reader session ends.\n *\n * This event is not emitted when a session closes normally after its first successful read.\n */\nexport interface NfcSessionEndEvent {\n reason: 'userCancelled' | 'sessionTimeout' | 'invalidated';\n}\n\n/**\n * Public API surface for the Capacitor NFC plugin.\n *\n * The interface intentionally mirrors the behaviour of the reference PhoneGap\n * implementation to ease migration while embracing idiomatic Capacitor APIs.\n */\nexport interface CapacitorNfcPlugin {\n /**\n * Starts listening for NFC tags.\n */\n startScanning(options?: StartScanningOptions): Promise<void>;\n /**\n * Stops the ongoing NFC scanning session.\n */\n stopScanning(): Promise<void>;\n /**\n * Writes the provided NDEF records to the last discovered tag.\n */\n write(options: WriteTagOptions): Promise<void>;\n /**\n * Attempts to erase the last discovered tag by writing an empty NDEF message.\n */\n erase(): Promise<void>;\n /**\n * Attempts to make the last discovered tag read-only.\n */\n makeReadOnly(): Promise<void>;\n /**\n * Shares an NDEF message with another device via peer-to-peer (Android only).\n */\n share(options: ShareTagOptions): Promise<void>;\n /**\n * Stops sharing previously provided NDEF message (Android only).\n */\n unshare(): Promise<void>;\n /**\n * Returns the current NFC adapter status.\n */\n getStatus(): Promise<{ status: NfcStatus }>;\n /**\n * Opens the system settings page where the user can enable NFC.\n */\n showSettings(): Promise<void>;\n /**\n * Returns the version string baked into the native plugin.\n */\n getPluginVersion(): Promise<{ version: string }>;\n /**\n * Checks whether the device has NFC hardware support.\n *\n * Returns `true` if NFC hardware is present on the device, regardless of\n * whether NFC is currently enabled or disabled. Returns `false` if the\n * device does not have NFC hardware.\n *\n * Use this method to determine if NFC features should be shown in your\n * app's UI. To check if NFC is currently enabled, use `getStatus()`.\n */\n isSupported(): Promise<{ supported: boolean }>;\n\n addListener(eventName: 'nfcEvent', listenerFunc: (event: NfcEvent) => void): Promise<PluginListenerHandle>;\n addListener(\n eventName: 'tagDiscovered' | 'ndefDiscovered' | 'ndefMimeDiscovered' | 'ndefFormatableDiscovered',\n listenerFunc: (event: NfcEvent) => void,\n ): Promise<PluginListenerHandle>;\n addListener(\n eventName: 'nfcStateChange',\n listenerFunc: (event: NfcStateChangeEvent) => void,\n ): Promise<PluginListenerHandle>;\n addListener(\n eventName: 'nfcSessionEnd',\n listenerFunc: (event: NfcSessionEndEvent) => void,\n ): Promise<PluginListenerHandle>;\n}\n\nexport type { PluginListenerHandle } from '@capacitor/core';\n"]} |
| import { WebPlugin } from '@capacitor/core'; | ||
| import type { CapacitorNfcPlugin, NfcStateChangeEvent, NfcEvent, ShareTagOptions, StartScanningOptions, WriteTagOptions, PluginListenerHandle } from './definitions'; | ||
| import type { CapacitorNfcPlugin, NfcSessionEndEvent, NfcStateChangeEvent, NfcEvent, ShareTagOptions, StartScanningOptions, WriteTagOptions, PluginListenerHandle } from './definitions'; | ||
| export declare class CapacitorNfcWeb extends WebPlugin implements CapacitorNfcPlugin { | ||
@@ -25,2 +25,3 @@ private unsupported; | ||
| addListener(eventName: 'nfcStateChange', listenerFunc: (event: NfcStateChangeEvent) => void): Promise<PluginListenerHandle>; | ||
| addListener(eventName: 'nfcSessionEnd', listenerFunc: (event: NfcSessionEndEvent) => void): Promise<PluginListenerHandle>; | ||
| } |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"web.js","sourceRoot":"","sources":["../../src/web.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAY5C,MAAM,OAAO,eAAgB,SAAQ,SAAS;IACpC,WAAW,CAAC,MAAc;QAChC,MAAM,IAAI,CAAC,aAAa,CAAC,gBAAgB,MAAM,6CAA6C,CAAC,CAAC;IAChG,CAAC;IAED,KAAK,CAAC,aAAa,CAAC,QAA+B;QACjD,IAAI,CAAC,WAAW,CAAC,eAAe,CAAC,CAAC;IACpC,CAAC;IAED,KAAK,CAAC,YAAY;QAChB,IAAI,CAAC,WAAW,CAAC,cAAc,CAAC,CAAC;IACnC,CAAC;IAED,KAAK,CAAC,KAAK,CAAC,QAAyB;QACnC,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;IAC5B,CAAC;IAED,KAAK,CAAC,KAAK;QACT,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;IAC5B,CAAC;IAED,KAAK,CAAC,YAAY;QAChB,IAAI,CAAC,WAAW,CAAC,cAAc,CAAC,CAAC;IACnC,CAAC;IAED,KAAK,CAAC,KAAK,CAAC,QAAyB;QACnC,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;IAC5B,CAAC;IAED,KAAK,CAAC,OAAO;QACX,IAAI,CAAC,WAAW,CAAC,SAAS,CAAC,CAAC;IAC9B,CAAC;IAED,KAAK,CAAC,SAAS;QACb,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC;IAC9B,CAAC;IAED,KAAK,CAAC,YAAY;QAChB,IAAI,CAAC,WAAW,CAAC,cAAc,CAAC,CAAC;IACnC,CAAC;IAED,KAAK,CAAC,gBAAgB;QACpB,OAAO,EAAE,OAAO,EAAE,WAAW,EAAE,CAAC;IAClC,CAAC;IAED,KAAK,CAAC,WAAW;QACf,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;IAC9B,CAAC;IAWD,KAAK,CAAC,WAAW,CAAC,SAAiB,EAAE,aAAuC;QAC1E,IAAI,CAAC,WAAW,CAAC,eAAe,SAAS,GAAG,CAAC,CAAC;IAChD,CAAC;CACF","sourcesContent":["import { WebPlugin } from '@capacitor/core';\n\nimport type {\n CapacitorNfcPlugin,\n NfcStateChangeEvent,\n NfcEvent,\n ShareTagOptions,\n StartScanningOptions,\n WriteTagOptions,\n PluginListenerHandle,\n} from './definitions';\n\nexport class CapacitorNfcWeb extends WebPlugin implements CapacitorNfcPlugin {\n private unsupported(method: string): never {\n throw this.unimplemented(`CapacitorNfc.${method} is not available in a browser environment.`);\n }\n\n async startScanning(_options?: StartScanningOptions): Promise<void> {\n this.unsupported('startScanning');\n }\n\n async stopScanning(): Promise<void> {\n this.unsupported('stopScanning');\n }\n\n async write(_options: WriteTagOptions): Promise<void> {\n this.unsupported('write');\n }\n\n async erase(): Promise<void> {\n this.unsupported('erase');\n }\n\n async makeReadOnly(): Promise<void> {\n this.unsupported('makeReadOnly');\n }\n\n async share(_options: ShareTagOptions): Promise<void> {\n this.unsupported('share');\n }\n\n async unshare(): Promise<void> {\n this.unsupported('unshare');\n }\n\n async getStatus(): Promise<{ status: 'NO_NFC' }> {\n return { status: 'NO_NFC' };\n }\n\n async showSettings(): Promise<void> {\n this.unsupported('showSettings');\n }\n\n async getPluginVersion(): Promise<{ version: string }> {\n return { version: '0.0.0-web' };\n }\n\n async isSupported(): Promise<{ supported: boolean }> {\n return { supported: false };\n }\n\n addListener(eventName: 'nfcEvent', listenerFunc: (event: NfcEvent) => void): Promise<PluginListenerHandle>;\n addListener(\n eventName: 'tagDiscovered' | 'ndefDiscovered' | 'ndefMimeDiscovered' | 'ndefFormatableDiscovered',\n listenerFunc: (event: NfcEvent) => void,\n ): Promise<PluginListenerHandle>;\n addListener(\n eventName: 'nfcStateChange',\n listenerFunc: (event: NfcStateChangeEvent) => void,\n ): Promise<PluginListenerHandle>;\n async addListener(eventName: string, _listenerFunc: (..._args: any[]) => any): Promise<PluginListenerHandle> {\n this.unsupported(`addListener(${eventName})`);\n }\n}\n"]} | ||
| {"version":3,"file":"web.js","sourceRoot":"","sources":["../../src/web.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAa5C,MAAM,OAAO,eAAgB,SAAQ,SAAS;IACpC,WAAW,CAAC,MAAc;QAChC,MAAM,IAAI,CAAC,aAAa,CAAC,gBAAgB,MAAM,6CAA6C,CAAC,CAAC;IAChG,CAAC;IAED,KAAK,CAAC,aAAa,CAAC,QAA+B;QACjD,IAAI,CAAC,WAAW,CAAC,eAAe,CAAC,CAAC;IACpC,CAAC;IAED,KAAK,CAAC,YAAY;QAChB,IAAI,CAAC,WAAW,CAAC,cAAc,CAAC,CAAC;IACnC,CAAC;IAED,KAAK,CAAC,KAAK,CAAC,QAAyB;QACnC,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;IAC5B,CAAC;IAED,KAAK,CAAC,KAAK;QACT,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;IAC5B,CAAC;IAED,KAAK,CAAC,YAAY;QAChB,IAAI,CAAC,WAAW,CAAC,cAAc,CAAC,CAAC;IACnC,CAAC;IAED,KAAK,CAAC,KAAK,CAAC,QAAyB;QACnC,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;IAC5B,CAAC;IAED,KAAK,CAAC,OAAO;QACX,IAAI,CAAC,WAAW,CAAC,SAAS,CAAC,CAAC;IAC9B,CAAC;IAED,KAAK,CAAC,SAAS;QACb,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC;IAC9B,CAAC;IAED,KAAK,CAAC,YAAY;QAChB,IAAI,CAAC,WAAW,CAAC,cAAc,CAAC,CAAC;IACnC,CAAC;IAED,KAAK,CAAC,gBAAgB;QACpB,OAAO,EAAE,OAAO,EAAE,WAAW,EAAE,CAAC;IAClC,CAAC;IAED,KAAK,CAAC,WAAW;QACf,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;IAC9B,CAAC;IAeD,KAAK,CAAC,WAAW,CAAC,SAAiB,EAAE,aAAuC;QAC1E,IAAI,CAAC,WAAW,CAAC,eAAe,SAAS,GAAG,CAAC,CAAC;IAChD,CAAC;CACF","sourcesContent":["import { WebPlugin } from '@capacitor/core';\n\nimport type {\n CapacitorNfcPlugin,\n NfcSessionEndEvent,\n NfcStateChangeEvent,\n NfcEvent,\n ShareTagOptions,\n StartScanningOptions,\n WriteTagOptions,\n PluginListenerHandle,\n} from './definitions';\n\nexport class CapacitorNfcWeb extends WebPlugin implements CapacitorNfcPlugin {\n private unsupported(method: string): never {\n throw this.unimplemented(`CapacitorNfc.${method} is not available in a browser environment.`);\n }\n\n async startScanning(_options?: StartScanningOptions): Promise<void> {\n this.unsupported('startScanning');\n }\n\n async stopScanning(): Promise<void> {\n this.unsupported('stopScanning');\n }\n\n async write(_options: WriteTagOptions): Promise<void> {\n this.unsupported('write');\n }\n\n async erase(): Promise<void> {\n this.unsupported('erase');\n }\n\n async makeReadOnly(): Promise<void> {\n this.unsupported('makeReadOnly');\n }\n\n async share(_options: ShareTagOptions): Promise<void> {\n this.unsupported('share');\n }\n\n async unshare(): Promise<void> {\n this.unsupported('unshare');\n }\n\n async getStatus(): Promise<{ status: 'NO_NFC' }> {\n return { status: 'NO_NFC' };\n }\n\n async showSettings(): Promise<void> {\n this.unsupported('showSettings');\n }\n\n async getPluginVersion(): Promise<{ version: string }> {\n return { version: '0.0.0-web' };\n }\n\n async isSupported(): Promise<{ supported: boolean }> {\n return { supported: false };\n }\n\n addListener(eventName: 'nfcEvent', listenerFunc: (event: NfcEvent) => void): Promise<PluginListenerHandle>;\n addListener(\n eventName: 'tagDiscovered' | 'ndefDiscovered' | 'ndefMimeDiscovered' | 'ndefFormatableDiscovered',\n listenerFunc: (event: NfcEvent) => void,\n ): Promise<PluginListenerHandle>;\n addListener(\n eventName: 'nfcStateChange',\n listenerFunc: (event: NfcStateChangeEvent) => void,\n ): Promise<PluginListenerHandle>;\n addListener(\n eventName: 'nfcSessionEnd',\n listenerFunc: (event: NfcSessionEndEvent) => void,\n ): Promise<PluginListenerHandle>;\n async addListener(eventName: string, _listenerFunc: (..._args: any[]) => any): Promise<PluginListenerHandle> {\n this.unsupported(`addListener(${eventName})`);\n }\n}\n"]} |
@@ -5,5 +5,18 @@ import Capacitor | ||
| func nfcSessionEndReason(for error: Error) -> String? { | ||
| switch (error as NSError).code { | ||
| case NFCReaderError.readerSessionInvalidationErrorFirstNDEFTagRead.rawValue: | ||
| return nil | ||
| case NFCReaderError.readerSessionInvalidationErrorUserCanceled.rawValue: | ||
| return "userCancelled" | ||
| case NFCReaderError.readerSessionInvalidationErrorSessionTimeout.rawValue: | ||
| return "sessionTimeout" | ||
| default: | ||
| return "invalidated" | ||
| } | ||
| } | ||
| @objc(NfcPlugin) | ||
| public class NfcPlugin: CAPPlugin, CAPBridgedPlugin { | ||
| private let pluginVersion: String = "8.1.7" | ||
| private let pluginVersion: String = "8.2.0" | ||
@@ -50,2 +63,12 @@ public let identifier = "NfcPlugin" | ||
| private func notifySessionEnd(for error: Error) { | ||
| guard let reason = nfcSessionEndReason(for: error) else { | ||
| return | ||
| } | ||
| DispatchQueue.main.async { | ||
| self.notifyListeners("nfcSessionEnd", data: ["reason": reason], retainUntilConsumed: true) | ||
| } | ||
| } | ||
| private func pollingOptions(_ requestedPollingOptions: JSArray) -> NFCTagReaderSession.PollingOption { | ||
@@ -497,2 +520,3 @@ var pollingOptions: NFCTagReaderSession.PollingOption = [] | ||
| currentTag = nil | ||
| notifySessionEnd(for: error) | ||
| if (error as NSError).code != NFCReaderError.readerSessionInvalidationErrorFirstNDEFTagRead.rawValue { | ||
@@ -638,2 +662,3 @@ DispatchQueue.main.async { | ||
| notifySessionEnd(for: error) | ||
| pendingStartCall = nil | ||
@@ -658,2 +683,3 @@ pendingStartSession = nil | ||
| currentTag = nil | ||
| notifySessionEnd(for: error) | ||
@@ -660,0 +686,0 @@ // Don't emit state change for normal session completion (user canceled) |
@@ -0,1 +1,2 @@ | ||
| import CoreNFC | ||
| import XCTest | ||
@@ -10,2 +11,16 @@ | ||
| } | ||
| func testSessionEndReasons() { | ||
| XCTAssertEqual(reason(for: NFCReaderError.readerSessionInvalidationErrorUserCanceled.rawValue), "userCancelled") | ||
| XCTAssertEqual(reason(for: NFCReaderError.readerSessionInvalidationErrorSessionTimeout.rawValue), "sessionTimeout") | ||
| XCTAssertEqual(reason(for: -1), "invalidated") | ||
| } | ||
| func testFirstReadCompletionDoesNotHaveSessionEndReason() { | ||
| XCTAssertNil(reason(for: NFCReaderError.readerSessionInvalidationErrorFirstNDEFTagRead.rawValue)) | ||
| } | ||
| private func reason(for errorCode: Int) -> String? { | ||
| nfcSessionEndReason(for: NSError(domain: "NfcPluginTests", code: errorCode)) | ||
| } | ||
| } |
+1
-1
| { | ||
| "name": "@capgo/capacitor-nfc", | ||
| "version": "8.1.7", | ||
| "version": "8.2.0", | ||
| "description": "Native NFC tag discovery, reading and writing for Capacitor apps on iOS and Android.", | ||
@@ -5,0 +5,0 @@ "main": "dist/plugin.cjs.js", |
+46
-1
@@ -150,2 +150,19 @@ # @capgo/capacitor-nfc | ||
| ### Handling iOS session endings | ||
| Listen for `nfcSessionEnd` to distinguish a user cancellation from a session timeout or another Core NFC error. The event is available for both `ndef` and `tag` iOS sessions. A normal first-read completion does not emit this event. | ||
| ```ts | ||
| const sessionEndListener = await CapacitorNfc.addListener('nfcSessionEnd', ({ reason }) => { | ||
| if (reason === 'userCancelled') { | ||
| return; | ||
| } | ||
| console.warn(reason === 'sessionTimeout' ? 'No tag detected. Try again.' : 'The NFC session failed.'); | ||
| }); | ||
| // Later, when the listener is no longer needed | ||
| await sessionEndListener.remove(); | ||
| ``` | ||
| ## API | ||
@@ -169,2 +186,3 @@ | ||
| * [`addListener('nfcStateChange', ...)`](#addlistenernfcstatechange-) | ||
| * [`addListener('nfcSessionEnd', ...)`](#addlistenernfcsessionend-) | ||
| * [Interfaces](#interfaces) | ||
@@ -377,2 +395,18 @@ * [Type Aliases](#type-aliases) | ||
| ### addListener('nfcSessionEnd', ...) | ||
| ```typescript | ||
| addListener(eventName: 'nfcSessionEnd', listenerFunc: (event: NfcSessionEndEvent) => void) => Promise<PluginListenerHandle> | ||
| ``` | ||
| | Param | Type | | ||
| | ------------------ | ------------------------------------------------------------------------------------- | | ||
| | **`eventName`** | <code>'nfcSessionEnd'</code> | | ||
| | **`listenerFunc`** | <code>(event: <a href="#nfcsessionendevent">NfcSessionEndEvent</a>) => void</code> | | ||
| **Returns:** <code>Promise<<a href="#pluginlistenerhandle">PluginListenerHandle</a>></code> | ||
| -------------------- | ||
| ### Interfaces | ||
@@ -391,3 +425,3 @@ | ||
| | **`iosPollingOptions`** | <code>NfcIosPollingOption[]</code> | iOS-only: polling options to use for NFC scanning. Defaults to `['iso14443', 'iso15693', 'iso18092']` for backward compatibility. | | ||
| | **`androidReaderModeFlags`** | <code>number</code> | Android-only: raw flags passed to `NfcAdapter.enableReaderMode`. Defaults to enabling all tag types with skipping NDEF checks. | | ||
| | **`androidReaderModeFlags`** | <code>number</code> | Android-only: raw flags passed to `NfcAdapter.enableReaderMode`. Defaults to enabling all tag types and Android's NDEF discovery so that detected tags remain available for writing and formatting. | | ||
@@ -476,2 +510,13 @@ | ||
| #### NfcSessionEndEvent | ||
| Event emitted when an iOS NFC reader session ends. | ||
| This event is not emitted when a session closes normally after its first successful read. | ||
| | Prop | Type | | ||
| | ------------ | ----------------------------------------------------------------- | | ||
| | **`reason`** | <code>'userCancelled' \| 'sessionTimeout' \| 'invalidated'</code> | | ||
| ### Type Aliases | ||
@@ -478,0 +523,0 @@ |
160602
4%1787
3.12%556
8.81%