@capgo/capacitor-nfc 7.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,4 @@
1
+ import type { CapacitorNfcPlugin } from './definitions';
2
+ declare const CapacitorNfc: CapacitorNfcPlugin;
3
+ export * from './definitions';
4
+ export { CapacitorNfc };
@@ -0,0 +1,7 @@
1
+ import { registerPlugin } from '@capacitor/core';
2
+ const CapacitorNfc = registerPlugin('CapacitorNfc', {
3
+ web: () => import('./web').then((m) => new m.CapacitorNfcWeb()),
4
+ });
5
+ export * from './definitions';
6
+ export { CapacitorNfc };
7
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAIjD,MAAM,YAAY,GAAG,cAAc,CAAqB,cAAc,EAAE;IACtE,GAAG,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,eAAe,EAAE,CAAC;CAChE,CAAC,CAAC;AAEH,cAAc,eAAe,CAAC;AAC9B,OAAO,EAAE,YAAY,EAAE,CAAC","sourcesContent":["import { registerPlugin } from '@capacitor/core';\n\nimport type { CapacitorNfcPlugin } from './definitions';\n\nconst CapacitorNfc = registerPlugin<CapacitorNfcPlugin>('CapacitorNfc', {\n web: () => import('./web').then((m) => new m.CapacitorNfcWeb()),\n});\n\nexport * from './definitions';\nexport { CapacitorNfc };\n"]}
@@ -0,0 +1,22 @@
1
+ import { WebPlugin } from '@capacitor/core';
2
+ import type { CapacitorNfcPlugin, NfcStateChangeEvent, NfcEvent, ShareTagOptions, StartScanningOptions, WriteTagOptions, PluginListenerHandle } from './definitions';
3
+ export declare class CapacitorNfcWeb extends WebPlugin implements CapacitorNfcPlugin {
4
+ private unsupported;
5
+ startScanning(_options?: StartScanningOptions): Promise<void>;
6
+ stopScanning(): Promise<void>;
7
+ write(_options: WriteTagOptions): Promise<void>;
8
+ erase(): Promise<void>;
9
+ makeReadOnly(): Promise<void>;
10
+ share(_options: ShareTagOptions): Promise<void>;
11
+ unshare(): Promise<void>;
12
+ getStatus(): Promise<{
13
+ status: 'NO_NFC';
14
+ }>;
15
+ showSettings(): Promise<void>;
16
+ getPluginVersion(): Promise<{
17
+ version: string;
18
+ }>;
19
+ addListener(eventName: 'nfcEvent', listenerFunc: (event: NfcEvent) => void): Promise<PluginListenerHandle>;
20
+ addListener(eventName: 'tagDiscovered' | 'ndefDiscovered' | 'ndefMimeDiscovered' | 'ndefFormatableDiscovered', listenerFunc: (event: NfcEvent) => void): Promise<PluginListenerHandle>;
21
+ addListener(eventName: 'nfcStateChange', listenerFunc: (event: NfcStateChangeEvent) => void): Promise<PluginListenerHandle>;
22
+ }
@@ -0,0 +1,40 @@
1
+ import { WebPlugin } from '@capacitor/core';
2
+ export class CapacitorNfcWeb extends WebPlugin {
3
+ unsupported(method) {
4
+ throw this.unimplemented(`CapacitorNfc.${method} is not available in a browser environment.`);
5
+ }
6
+ async startScanning(_options) {
7
+ this.unsupported('startScanning');
8
+ }
9
+ async stopScanning() {
10
+ this.unsupported('stopScanning');
11
+ }
12
+ async write(_options) {
13
+ this.unsupported('write');
14
+ }
15
+ async erase() {
16
+ this.unsupported('erase');
17
+ }
18
+ async makeReadOnly() {
19
+ this.unsupported('makeReadOnly');
20
+ }
21
+ async share(_options) {
22
+ this.unsupported('share');
23
+ }
24
+ async unshare() {
25
+ this.unsupported('unshare');
26
+ }
27
+ async getStatus() {
28
+ return { status: 'NO_NFC' };
29
+ }
30
+ async showSettings() {
31
+ this.unsupported('showSettings');
32
+ }
33
+ async getPluginVersion() {
34
+ return { version: '0.0.0-web' };
35
+ }
36
+ async addListener(eventName, _listenerFunc) {
37
+ this.unsupported(`addListener(${eventName})`);
38
+ }
39
+ }
40
+ //# sourceMappingURL=web.js.map
@@ -0,0 +1 @@
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;IAcD,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 addListener(\n eventName: 'nfcEvent',\n listenerFunc: (event: NfcEvent) => void,\n ): 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"]}
@@ -0,0 +1,54 @@
1
+ 'use strict';
2
+
3
+ var core = require('@capacitor/core');
4
+
5
+ const CapacitorNfc = core.registerPlugin('CapacitorNfc', {
6
+ web: () => Promise.resolve().then(function () { return web; }).then((m) => new m.CapacitorNfcWeb()),
7
+ });
8
+
9
+ class CapacitorNfcWeb extends core.WebPlugin {
10
+ unsupported(method) {
11
+ throw this.unimplemented(`CapacitorNfc.${method} is not available in a browser environment.`);
12
+ }
13
+ async startScanning(_options) {
14
+ this.unsupported('startScanning');
15
+ }
16
+ async stopScanning() {
17
+ this.unsupported('stopScanning');
18
+ }
19
+ async write(_options) {
20
+ this.unsupported('write');
21
+ }
22
+ async erase() {
23
+ this.unsupported('erase');
24
+ }
25
+ async makeReadOnly() {
26
+ this.unsupported('makeReadOnly');
27
+ }
28
+ async share(_options) {
29
+ this.unsupported('share');
30
+ }
31
+ async unshare() {
32
+ this.unsupported('unshare');
33
+ }
34
+ async getStatus() {
35
+ return { status: 'NO_NFC' };
36
+ }
37
+ async showSettings() {
38
+ this.unsupported('showSettings');
39
+ }
40
+ async getPluginVersion() {
41
+ return { version: '0.0.0-web' };
42
+ }
43
+ async addListener(eventName, _listenerFunc) {
44
+ this.unsupported(`addListener(${eventName})`);
45
+ }
46
+ }
47
+
48
+ var web = /*#__PURE__*/Object.freeze({
49
+ __proto__: null,
50
+ CapacitorNfcWeb: CapacitorNfcWeb
51
+ });
52
+
53
+ exports.CapacitorNfc = CapacitorNfc;
54
+ //# sourceMappingURL=plugin.cjs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin.cjs.js","sources":["esm/index.js","esm/web.js"],"sourcesContent":["import { registerPlugin } from '@capacitor/core';\nconst CapacitorNfc = registerPlugin('CapacitorNfc', {\n web: () => import('./web').then((m) => new m.CapacitorNfcWeb()),\n});\nexport * from './definitions';\nexport { CapacitorNfc };\n//# sourceMappingURL=index.js.map","import { WebPlugin } from '@capacitor/core';\nexport class CapacitorNfcWeb extends WebPlugin {\n unsupported(method) {\n throw this.unimplemented(`CapacitorNfc.${method} is not available in a browser environment.`);\n }\n async startScanning(_options) {\n this.unsupported('startScanning');\n }\n async stopScanning() {\n this.unsupported('stopScanning');\n }\n async write(_options) {\n this.unsupported('write');\n }\n async erase() {\n this.unsupported('erase');\n }\n async makeReadOnly() {\n this.unsupported('makeReadOnly');\n }\n async share(_options) {\n this.unsupported('share');\n }\n async unshare() {\n this.unsupported('unshare');\n }\n async getStatus() {\n return { status: 'NO_NFC' };\n }\n async showSettings() {\n this.unsupported('showSettings');\n }\n async getPluginVersion() {\n return { version: '0.0.0-web' };\n }\n async addListener(eventName, _listenerFunc) {\n this.unsupported(`addListener(${eventName})`);\n }\n}\n//# sourceMappingURL=web.js.map"],"names":["registerPlugin","WebPlugin"],"mappings":";;;;AACK,MAAC,YAAY,GAAGA,mBAAc,CAAC,cAAc,EAAE;AACpD,IAAI,GAAG,EAAE,MAAM,mDAAe,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,eAAe,EAAE,CAAC;AACnE,CAAC;;ACFM,MAAM,eAAe,SAASC,cAAS,CAAC;AAC/C,IAAI,WAAW,CAAC,MAAM,EAAE;AACxB,QAAQ,MAAM,IAAI,CAAC,aAAa,CAAC,CAAC,aAAa,EAAE,MAAM,CAAC,2CAA2C,CAAC,CAAC;AACrG,IAAI;AACJ,IAAI,MAAM,aAAa,CAAC,QAAQ,EAAE;AAClC,QAAQ,IAAI,CAAC,WAAW,CAAC,eAAe,CAAC;AACzC,IAAI;AACJ,IAAI,MAAM,YAAY,GAAG;AACzB,QAAQ,IAAI,CAAC,WAAW,CAAC,cAAc,CAAC;AACxC,IAAI;AACJ,IAAI,MAAM,KAAK,CAAC,QAAQ,EAAE;AAC1B,QAAQ,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC;AACjC,IAAI;AACJ,IAAI,MAAM,KAAK,GAAG;AAClB,QAAQ,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC;AACjC,IAAI;AACJ,IAAI,MAAM,YAAY,GAAG;AACzB,QAAQ,IAAI,CAAC,WAAW,CAAC,cAAc,CAAC;AACxC,IAAI;AACJ,IAAI,MAAM,KAAK,CAAC,QAAQ,EAAE;AAC1B,QAAQ,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC;AACjC,IAAI;AACJ,IAAI,MAAM,OAAO,GAAG;AACpB,QAAQ,IAAI,CAAC,WAAW,CAAC,SAAS,CAAC;AACnC,IAAI;AACJ,IAAI,MAAM,SAAS,GAAG;AACtB,QAAQ,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE;AACnC,IAAI;AACJ,IAAI,MAAM,YAAY,GAAG;AACzB,QAAQ,IAAI,CAAC,WAAW,CAAC,cAAc,CAAC;AACxC,IAAI;AACJ,IAAI,MAAM,gBAAgB,GAAG;AAC7B,QAAQ,OAAO,EAAE,OAAO,EAAE,WAAW,EAAE;AACvC,IAAI;AACJ,IAAI,MAAM,WAAW,CAAC,SAAS,EAAE,aAAa,EAAE;AAChD,QAAQ,IAAI,CAAC,WAAW,CAAC,CAAC,YAAY,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC;AACrD,IAAI;AACJ;;;;;;;;;"}
package/dist/plugin.js ADDED
@@ -0,0 +1,57 @@
1
+ var capacitorCapacitorNfc = (function (exports, core) {
2
+ 'use strict';
3
+
4
+ const CapacitorNfc = core.registerPlugin('CapacitorNfc', {
5
+ web: () => Promise.resolve().then(function () { return web; }).then((m) => new m.CapacitorNfcWeb()),
6
+ });
7
+
8
+ class CapacitorNfcWeb extends core.WebPlugin {
9
+ unsupported(method) {
10
+ throw this.unimplemented(`CapacitorNfc.${method} is not available in a browser environment.`);
11
+ }
12
+ async startScanning(_options) {
13
+ this.unsupported('startScanning');
14
+ }
15
+ async stopScanning() {
16
+ this.unsupported('stopScanning');
17
+ }
18
+ async write(_options) {
19
+ this.unsupported('write');
20
+ }
21
+ async erase() {
22
+ this.unsupported('erase');
23
+ }
24
+ async makeReadOnly() {
25
+ this.unsupported('makeReadOnly');
26
+ }
27
+ async share(_options) {
28
+ this.unsupported('share');
29
+ }
30
+ async unshare() {
31
+ this.unsupported('unshare');
32
+ }
33
+ async getStatus() {
34
+ return { status: 'NO_NFC' };
35
+ }
36
+ async showSettings() {
37
+ this.unsupported('showSettings');
38
+ }
39
+ async getPluginVersion() {
40
+ return { version: '0.0.0-web' };
41
+ }
42
+ async addListener(eventName, _listenerFunc) {
43
+ this.unsupported(`addListener(${eventName})`);
44
+ }
45
+ }
46
+
47
+ var web = /*#__PURE__*/Object.freeze({
48
+ __proto__: null,
49
+ CapacitorNfcWeb: CapacitorNfcWeb
50
+ });
51
+
52
+ exports.CapacitorNfc = CapacitorNfc;
53
+
54
+ return exports;
55
+
56
+ })({}, capacitorExports);
57
+ //# sourceMappingURL=plugin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin.js","sources":["esm/index.js","esm/web.js"],"sourcesContent":["import { registerPlugin } from '@capacitor/core';\nconst CapacitorNfc = registerPlugin('CapacitorNfc', {\n web: () => import('./web').then((m) => new m.CapacitorNfcWeb()),\n});\nexport * from './definitions';\nexport { CapacitorNfc };\n//# sourceMappingURL=index.js.map","import { WebPlugin } from '@capacitor/core';\nexport class CapacitorNfcWeb extends WebPlugin {\n unsupported(method) {\n throw this.unimplemented(`CapacitorNfc.${method} is not available in a browser environment.`);\n }\n async startScanning(_options) {\n this.unsupported('startScanning');\n }\n async stopScanning() {\n this.unsupported('stopScanning');\n }\n async write(_options) {\n this.unsupported('write');\n }\n async erase() {\n this.unsupported('erase');\n }\n async makeReadOnly() {\n this.unsupported('makeReadOnly');\n }\n async share(_options) {\n this.unsupported('share');\n }\n async unshare() {\n this.unsupported('unshare');\n }\n async getStatus() {\n return { status: 'NO_NFC' };\n }\n async showSettings() {\n this.unsupported('showSettings');\n }\n async getPluginVersion() {\n return { version: '0.0.0-web' };\n }\n async addListener(eventName, _listenerFunc) {\n this.unsupported(`addListener(${eventName})`);\n }\n}\n//# sourceMappingURL=web.js.map"],"names":["registerPlugin","WebPlugin"],"mappings":";;;AACK,UAAC,YAAY,GAAGA,mBAAc,CAAC,cAAc,EAAE;IACpD,IAAI,GAAG,EAAE,MAAM,mDAAe,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,eAAe,EAAE,CAAC;IACnE,CAAC;;ICFM,MAAM,eAAe,SAASC,cAAS,CAAC;IAC/C,IAAI,WAAW,CAAC,MAAM,EAAE;IACxB,QAAQ,MAAM,IAAI,CAAC,aAAa,CAAC,CAAC,aAAa,EAAE,MAAM,CAAC,2CAA2C,CAAC,CAAC;IACrG,IAAI;IACJ,IAAI,MAAM,aAAa,CAAC,QAAQ,EAAE;IAClC,QAAQ,IAAI,CAAC,WAAW,CAAC,eAAe,CAAC;IACzC,IAAI;IACJ,IAAI,MAAM,YAAY,GAAG;IACzB,QAAQ,IAAI,CAAC,WAAW,CAAC,cAAc,CAAC;IACxC,IAAI;IACJ,IAAI,MAAM,KAAK,CAAC,QAAQ,EAAE;IAC1B,QAAQ,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC;IACjC,IAAI;IACJ,IAAI,MAAM,KAAK,GAAG;IAClB,QAAQ,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC;IACjC,IAAI;IACJ,IAAI,MAAM,YAAY,GAAG;IACzB,QAAQ,IAAI,CAAC,WAAW,CAAC,cAAc,CAAC;IACxC,IAAI;IACJ,IAAI,MAAM,KAAK,CAAC,QAAQ,EAAE;IAC1B,QAAQ,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC;IACjC,IAAI;IACJ,IAAI,MAAM,OAAO,GAAG;IACpB,QAAQ,IAAI,CAAC,WAAW,CAAC,SAAS,CAAC;IACnC,IAAI;IACJ,IAAI,MAAM,SAAS,GAAG;IACtB,QAAQ,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE;IACnC,IAAI;IACJ,IAAI,MAAM,YAAY,GAAG;IACzB,QAAQ,IAAI,CAAC,WAAW,CAAC,cAAc,CAAC;IACxC,IAAI;IACJ,IAAI,MAAM,gBAAgB,GAAG;IAC7B,QAAQ,OAAO,EAAE,OAAO,EAAE,WAAW,EAAE;IACvC,IAAI;IACJ,IAAI,MAAM,WAAW,CAAC,SAAS,EAAE,aAAa,EAAE;IAChD,QAAQ,IAAI,CAAC,WAAW,CAAC,CAAC,YAAY,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC;IACrD,IAAI;IACJ;;;;;;;;;;;;;;;"}
@@ -0,0 +1,407 @@
1
+ import Capacitor
2
+ import CoreNFC
3
+ import UIKit
4
+
5
+ @objc(NfcPlugin)
6
+ public class NfcPlugin: CAPPlugin, CAPBridgedPlugin {
7
+ private let pluginVersion = "0.0.1"
8
+
9
+ public let identifier = "NfcPlugin"
10
+ public let jsName = "CapacitorNfc"
11
+ public let pluginMethods: [CAPPluginMethod] = [
12
+ CAPPluginMethod(name: "startScanning", returnType: CAPPluginReturnPromise),
13
+ CAPPluginMethod(name: "stopScanning", returnType: CAPPluginReturnPromise),
14
+ CAPPluginMethod(name: "write", returnType: CAPPluginReturnPromise),
15
+ CAPPluginMethod(name: "erase", returnType: CAPPluginReturnPromise),
16
+ CAPPluginMethod(name: "makeReadOnly", returnType: CAPPluginReturnPromise),
17
+ CAPPluginMethod(name: "share", returnType: CAPPluginReturnPromise),
18
+ CAPPluginMethod(name: "unshare", returnType: CAPPluginReturnPromise),
19
+ CAPPluginMethod(name: "getStatus", returnType: CAPPluginReturnPromise),
20
+ CAPPluginMethod(name: "showSettings", returnType: CAPPluginReturnPromise),
21
+ CAPPluginMethod(name: "getPluginVersion", returnType: CAPPluginReturnPromise)
22
+ ]
23
+
24
+ private var readerSession: NFCNDEFReaderSession?
25
+ private let sessionQueue = DispatchQueue(label: "app.capgo.nfc.session")
26
+ private var currentTag: NFCNDEFTag?
27
+ private var invalidateAfterFirstRead = true
28
+
29
+ @objc public func startScanning(_ call: CAPPluginCall) {
30
+ #if targetEnvironment(simulator)
31
+ call.reject("NFC is not available on the simulator.", "NO_NFC")
32
+ return
33
+ #else
34
+ guard NFCNDEFReaderSession.readingAvailable else {
35
+ call.reject("NFC is not available on this device.", "NO_NFC")
36
+ return
37
+ }
38
+
39
+ invalidateAfterFirstRead = call.getBool("invalidateAfterFirstRead", true)
40
+ let alertMessage = call.getString("alertMessage")
41
+
42
+ DispatchQueue.main.async {
43
+ self.readerSession?.invalidate()
44
+ self.readerSession = NFCNDEFReaderSession(delegate: self, queue: self.sessionQueue, invalidateAfterFirstRead: self.invalidateAfterFirstRead)
45
+ if let alertMessage, !alertMessage.isEmpty {
46
+ self.readerSession?.alertMessage = alertMessage
47
+ }
48
+ self.readerSession?.begin()
49
+ }
50
+
51
+ call.resolve()
52
+ #endif
53
+ }
54
+
55
+ @objc public func stopScanning(_ call: CAPPluginCall) {
56
+ DispatchQueue.main.async {
57
+ self.readerSession?.invalidate()
58
+ self.readerSession = nil
59
+ self.currentTag = nil
60
+ }
61
+ call.resolve()
62
+ }
63
+
64
+ @objc public func write(_ call: CAPPluginCall) {
65
+ guard let session = readerSession, let tag = currentTag else {
66
+ call.reject("No active NFC session or tag. Call startScanning and present a tag before writing.")
67
+ return
68
+ }
69
+
70
+ guard let rawRecords = call.getArray("records") as? [[String: Any]] else {
71
+ call.reject("records is required and must be an array.")
72
+ return
73
+ }
74
+
75
+ do {
76
+ let message = try buildMessage(from: rawRecords)
77
+ performWrite(message: message, on: tag, session: session, call: call)
78
+ } catch {
79
+ call.reject("Invalid NDEF records payload.", nil, error)
80
+ }
81
+ }
82
+
83
+ @objc public func erase(_ call: CAPPluginCall) {
84
+ guard let session = readerSession, let tag = currentTag else {
85
+ call.reject("No active NFC session or tag. Call startScanning and present a tag before erasing.")
86
+ return
87
+ }
88
+
89
+ let emptyRecord = NFCNDEFPayload(format: .empty, type: Data(), identifier: Data(), payload: Data())
90
+ let message = NFCNDEFMessage(records: [emptyRecord])
91
+ performWrite(message: message, on: tag, session: session, call: call)
92
+ }
93
+
94
+ @objc public func makeReadOnly(_ call: CAPPluginCall) {
95
+ call.reject("Making tags read only is not supported on iOS.", "UNSUPPORTED")
96
+ }
97
+
98
+ @objc public func share(_ call: CAPPluginCall) {
99
+ call.reject("Peer-to-peer NFC sharing is not available on iOS.", "UNSUPPORTED")
100
+ }
101
+
102
+ @objc public func unshare(_ call: CAPPluginCall) {
103
+ call.reject("Peer-to-peer NFC sharing is not available on iOS.", "UNSUPPORTED")
104
+ }
105
+
106
+ @objc public func getStatus(_ call: CAPPluginCall) {
107
+ let status = NFCNDEFReaderSession.readingAvailable ? "NFC_OK" : "NO_NFC"
108
+ call.resolve([
109
+ "status": status
110
+ ])
111
+ }
112
+
113
+ @objc public func showSettings(_ call: CAPPluginCall) {
114
+ guard let url = URL(string: UIApplication.openSettingsURLString) else {
115
+ call.reject("Unable to open application settings.")
116
+ return
117
+ }
118
+
119
+ DispatchQueue.main.async {
120
+ UIApplication.shared.open(url, options: [:], completionHandler: nil)
121
+ }
122
+ call.resolve()
123
+ }
124
+
125
+ @objc public func getPluginVersion(_ call: CAPPluginCall) {
126
+ call.resolve([
127
+ "version": pluginVersion
128
+ ])
129
+ }
130
+
131
+ private func performWrite(message: NFCNDEFMessage, on tag: NFCNDEFTag, session: NFCNDEFReaderSession, call: CAPPluginCall) {
132
+ session.connect(to: tag) { [weak self] error in
133
+ guard let self else {
134
+ DispatchQueue.main.async { call.reject("Session is no longer available.") }
135
+ return
136
+ }
137
+
138
+ if let error {
139
+ DispatchQueue.main.async {
140
+ call.reject("Failed to connect to tag.", nil, error)
141
+ }
142
+ return
143
+ }
144
+
145
+ tag.queryNDEFStatus { status, capacity, statusError in
146
+ if let statusError {
147
+ DispatchQueue.main.async {
148
+ call.reject("Failed to query tag status.", nil, statusError)
149
+ }
150
+ return
151
+ }
152
+
153
+ switch status {
154
+ case .readWrite:
155
+ if capacity < message.length {
156
+ DispatchQueue.main.async {
157
+ call.reject("Tag capacity is insufficient for the provided message.")
158
+ }
159
+ return
160
+ }
161
+ tag.writeNDEF(message) { writeError in
162
+ DispatchQueue.main.async {
163
+ if let writeError {
164
+ call.reject("Failed to write NDEF message.", nil, writeError)
165
+ } else {
166
+ call.resolve()
167
+ }
168
+ }
169
+ }
170
+ case .readOnly:
171
+ DispatchQueue.main.async {
172
+ call.reject("Tag is read only.")
173
+ }
174
+ case .notSupported:
175
+ DispatchQueue.main.async {
176
+ call.reject("Tag does not support NDEF.")
177
+ }
178
+ @unknown default:
179
+ DispatchQueue.main.async {
180
+ call.reject("Unknown tag status.")
181
+ }
182
+ }
183
+ }
184
+ }
185
+ }
186
+
187
+ private func buildMessage(from records: [[String: Any]]) throws -> NFCNDEFMessage {
188
+ if records.isEmpty {
189
+ throw NfcPluginError.invalidPayload
190
+ }
191
+
192
+ let payloads = try records.map { record -> NFCNDEFPayload in
193
+ guard let tnfValue = record["tnf"] as? NSNumber,
194
+ let typeArray = record["type"],
195
+ let idArray = record["id"],
196
+ let payloadArray = record["payload"] else {
197
+ throw NfcPluginError.invalidPayload
198
+ }
199
+
200
+ let payload = NFCNDEFPayload(
201
+ format: NFCTypeNameFormat(rawValue: UInt8(truncating: tnfValue)) ?? .unknown,
202
+ type: data(from: typeArray),
203
+ identifier: data(from: idArray),
204
+ payload: data(from: payloadArray)
205
+ )
206
+ return payload
207
+ }
208
+
209
+ return NFCNDEFMessage(records: payloads)
210
+ }
211
+
212
+ private func data(from any: Any) -> Data {
213
+ guard let numbers = any as? [NSNumber] else {
214
+ return Data()
215
+ }
216
+ var bytes = [UInt8]()
217
+ bytes.reserveCapacity(numbers.count)
218
+ numbers.forEach { number in
219
+ bytes.append(number.uint8Value)
220
+ }
221
+ return Data(bytes)
222
+ }
223
+
224
+ private func array(from data: Data?) -> [NSNumber]? {
225
+ guard let data else {
226
+ return nil
227
+ }
228
+ return data.map { NSNumber(value: $0) }
229
+ }
230
+
231
+ private func notify(event: [String: Any]) {
232
+ DispatchQueue.main.async {
233
+ self.notifyListeners("nfcEvent", data: event, retainUntilConsumed: true)
234
+ guard let type = event["type"] as? String else {
235
+ return
236
+ }
237
+ switch type {
238
+ case "ndef":
239
+ self.notifyListeners("ndefDiscovered", data: event, retainUntilConsumed: true)
240
+ default:
241
+ self.notifyListeners("tagDiscovered", data: event, retainUntilConsumed: true)
242
+ }
243
+ }
244
+ }
245
+
246
+ private func buildEvent(tag: NFCNDEFTag, status: NFCNDEFStatus, capacity: Int, message: NFCNDEFMessage?) -> [String: Any] {
247
+ var tagInfo: [String: Any] = [:]
248
+ if let identifierData = extractIdentifier(from: tag) {
249
+ tagInfo["id"] = array(from: identifierData)
250
+ }
251
+ tagInfo["techTypes"] = detectTechTypes(for: tag)
252
+ tagInfo["isWritable"] = status == .readWrite
253
+ tagInfo["maxSize"] = capacity
254
+ tagInfo["type"] = translateType(for: tag)
255
+
256
+ if let message {
257
+ tagInfo["ndefMessage"] = message.records.map { record in
258
+ [
259
+ "tnf": NSNumber(value: record.typeNameFormat.rawValue),
260
+ "type": array(from: record.type),
261
+ "id": array(from: record.identifier),
262
+ "payload": array(from: record.payload)
263
+ ].compactMapValues { $0 }
264
+ }
265
+ }
266
+
267
+ return [
268
+ "type": "ndef",
269
+ "tag": tagInfo
270
+ ]
271
+ }
272
+
273
+ private func extractIdentifier(from tag: NFCNDEFTag) -> Data? {
274
+ if let miFare = tag as? NFCMiFareTag {
275
+ return miFare.identifier
276
+ }
277
+ if #available(iOS 13.3, *), let iso7816 = tag as? NFCISO7816Tag {
278
+ return iso7816.identifier
279
+ }
280
+ if let iso15693 = tag as? NFCISO15693Tag {
281
+ return iso15693.identifier
282
+ }
283
+ if let feliCa = tag as? NFCFeliCaTag {
284
+ return Data(feliCa.currentIDm)
285
+ }
286
+ return nil
287
+ }
288
+
289
+ private func detectTechTypes(for tag: NFCNDEFTag) -> [String] {
290
+ var types: [String] = []
291
+ if tag is NFCMiFareTag {
292
+ types.append("NFCMiFareTag")
293
+ }
294
+ if tag is NFCISO7816Tag {
295
+ types.append("NFCISO7816Tag")
296
+ }
297
+ if tag is NFCISO15693Tag {
298
+ types.append("NFCISO15693Tag")
299
+ }
300
+ if tag is NFCFeliCaTag {
301
+ types.append("NFCFeliCaTag")
302
+ }
303
+ return types
304
+ }
305
+
306
+ private func translateType(for tag: NFCNDEFTag) -> String? {
307
+ if let miFare = tag as? NFCMiFareTag {
308
+ switch miFare.mifareFamily {
309
+ case .plus:
310
+ return "MIFARE Plus"
311
+ case .ultralight:
312
+ return "MIFARE Ultralight"
313
+ case .desfire:
314
+ return "MIFARE DESFire"
315
+ case .unknown:
316
+ return "MIFARE"
317
+ @unknown default:
318
+ return "MIFARE"
319
+ }
320
+ }
321
+ if tag is NFCISO7816Tag {
322
+ return "ISO 7816"
323
+ }
324
+ if tag is NFCISO15693Tag {
325
+ return "ISO 15693"
326
+ }
327
+ if tag is NFCFeliCaTag {
328
+ return "FeliCa"
329
+ }
330
+ return nil
331
+ }
332
+ }
333
+
334
+ extension NfcPlugin: NFCNDEFReaderSessionDelegate {
335
+ public func readerSession(_ session: NFCNDEFReaderSession, didInvalidateWithError error: Error) {
336
+ currentTag = nil
337
+ if (error as NSError).code != NFCReaderError.readerSessionInvalidationErrorFirstNDEFTagRead.rawValue {
338
+ DispatchQueue.main.async {
339
+ let payload: [String: Any] = [
340
+ "status": NFCNDEFReaderSession.readingAvailable ? "NFC_OK" : "NO_NFC",
341
+ "enabled": NFCNDEFReaderSession.readingAvailable
342
+ ]
343
+ self.notifyListeners("nfcStateChange", data: payload, retainUntilConsumed: true)
344
+ }
345
+ }
346
+ readerSession = nil
347
+ }
348
+
349
+ public func readerSession(_ session: NFCNDEFReaderSession, didDetect tags: [NFCNDEFTag]) {
350
+ guard let tag = tags.first else {
351
+ return
352
+ }
353
+
354
+ session.connect(to: tag) { [weak self] error in
355
+ guard let self else {
356
+ return
357
+ }
358
+
359
+ if let error {
360
+ session.invalidate(errorMessage: "Failed to connect to the tag: \(error.localizedDescription)")
361
+ return
362
+ }
363
+
364
+ tag.queryNDEFStatus { status, capacity, statusError in
365
+ if let statusError {
366
+ session.invalidate(errorMessage: "Failed to read tag status: \(statusError.localizedDescription)")
367
+ return
368
+ }
369
+
370
+ tag.readNDEF { message, readError in
371
+ if let readError {
372
+ session.invalidate(errorMessage: "Failed to read NDEF message: \(readError.localizedDescription)")
373
+ return
374
+ }
375
+
376
+ self.currentTag = tag
377
+ let event = self.buildEvent(tag: tag, status: status, capacity: capacity, message: message)
378
+ self.notify(event: event)
379
+ }
380
+ }
381
+ }
382
+ }
383
+
384
+ public func readerSession(_ session: NFCNDEFReaderSession, didDetectNDEFs messages: [NFCNDEFMessage]) {
385
+ guard !messages.isEmpty else {
386
+ return
387
+ }
388
+ let event: [String: Any] = [
389
+ "type": "ndef",
390
+ "tag": [
391
+ "ndefMessage": messages.first?.records.map { record in
392
+ [
393
+ "tnf": NSNumber(value: record.typeNameFormat.rawValue),
394
+ "type": array(from: record.type) ?? [],
395
+ "id": array(from: record.identifier) ?? [],
396
+ "payload": array(from: record.payload) ?? []
397
+ ]
398
+ } ?? []
399
+ ]
400
+ ]
401
+ notify(event: event)
402
+ }
403
+ }
404
+
405
+ enum NfcPluginError: Error {
406
+ case invalidPayload
407
+ }
@@ -0,0 +1,10 @@
1
+ import XCTest
2
+
3
+ @testable import NfcPlugin
4
+
5
+ final class NfcPluginTests: XCTestCase {
6
+ func testPluginCanBeInitialised() {
7
+ let plugin = NfcPlugin()
8
+ XCTAssertNotNil(plugin)
9
+ }
10
+ }