@icedevml/react-native-host-card-emulation 0.6.1 → 0.6.3
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.
- package/README.md +19 -17
- package/js/NativeHCEModule.ts +28 -6
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -117,7 +117,7 @@ Afterwards, follow the subsections below for each platform that you need to supp
|
|
|
117
117
|
This module provides a uniform low-level HCE API for both mobile platforms.
|
|
118
118
|
|
|
119
119
|
> [!NOTE]
|
|
120
|
-
> Raw native module's API specification is available in [packages/host-card-emulation/js
|
|
120
|
+
> Raw native module's API specification is available in [packages/host-card-emulation/js](https://github.com/icedevml/react-native-host-card-emulation/blob/master/packages/host-card-emulation/js) subdirectory.
|
|
121
121
|
> Check it out in order to understand what methods you can call against the module and what are the expected parameters/return values.
|
|
122
122
|
|
|
123
123
|
> [!NOTE]
|
|
@@ -128,7 +128,7 @@ This module provides a uniform low-level HCE API for both mobile platforms.
|
|
|
128
128
|
1. Subscribe to the event stream. There is a single global event stream, so you can subscribe early and remain subscribed to events for the entire application's lifetime.
|
|
129
129
|
```typescript
|
|
130
130
|
useEffect(() => {
|
|
131
|
-
const subscription = NativeHCEModule
|
|
131
|
+
const subscription = NativeHCEModule.onEvent(async (event: HCEModuleEvent) => {
|
|
132
132
|
switch (event.type) {
|
|
133
133
|
/* ... implement event handlers here ... */
|
|
134
134
|
}
|
|
@@ -142,28 +142,28 @@ This module provides a uniform low-level HCE API for both mobile platforms.
|
|
|
142
142
|
```
|
|
143
143
|
2. When user indicates that he/she wants to perform the HCE action, call the following function from the button's onClick routine:
|
|
144
144
|
```typescript
|
|
145
|
-
await NativeHCEModule
|
|
145
|
+
await NativeHCEModule.beginSession();
|
|
146
146
|
```
|
|
147
147
|
This will emit `sessionStarted` event right after the function call, on both iOS and Android platforms. After the session is started, you can decide to start HCE emulation right away in the event handler:
|
|
148
148
|
```typescript
|
|
149
|
-
// inside NativeHCEModule
|
|
149
|
+
// inside NativeHCEModule.onEvent handler's switch
|
|
150
150
|
case 'sessionStarted':
|
|
151
|
-
NativeHCEModule
|
|
152
|
-
await NativeHCEModule
|
|
151
|
+
NativeHCEModule.setSessionAlertMessage('Tap towards the reader'); // only for iOS, no-op in Android
|
|
152
|
+
await NativeHCEModule.startHCE();
|
|
153
153
|
break;
|
|
154
154
|
```
|
|
155
|
-
Calling `await NativeHCEModule
|
|
155
|
+
Calling `await NativeHCEModule.startHCE()` causes:
|
|
156
156
|
* iOS: Your smartphone will start listening for C-APDUs (Command APDUs originating from reader devices) right after that function is called, which will be additionally indicated by the operating system popping out the NFC scanning user interface prompt.
|
|
157
157
|
* Android: HCE commands will be forwarded to your application from that point on. No specific user interface is displayed (you have to implement it on your own, within your app).
|
|
158
158
|
3. Optionally, you can handle `readerDetected` and `readerDeselected` events to enhance user's experience.
|
|
159
159
|
```typescript
|
|
160
|
-
// inside NativeHCEModule
|
|
160
|
+
// inside NativeHCEModule.onEvent handler's switch
|
|
161
161
|
case 'readerDetected':
|
|
162
|
-
NativeHCEModule
|
|
162
|
+
NativeHCEModule.setSessionAlertMessage('Reader detected'); // only for iOS, no-op in Android
|
|
163
163
|
break;
|
|
164
164
|
|
|
165
165
|
case 'readerDeselected':
|
|
166
|
-
NativeHCEModule
|
|
166
|
+
NativeHCEModule.setSessionAlertMessage('Lost reader'); // only for iOS, no-op in Android
|
|
167
167
|
break;
|
|
168
168
|
```
|
|
169
169
|
For those events, trigger mechanisms are platform dependent:
|
|
@@ -171,16 +171,16 @@ This module provides a uniform low-level HCE API for both mobile platforms.
|
|
|
171
171
|
* Android: The `readerDetected` event will be emitted as soon as the first matching SELECT AID command is observed. The `readerDeselected` event will be emitted if the reader is physically disconnected or a non-matching AID is selected by the reader.
|
|
172
172
|
4. Receive incoming C-APDU and respond to it:
|
|
173
173
|
```typescript
|
|
174
|
-
// inside NativeHCEModule
|
|
174
|
+
// inside NativeHCEModule.onEvent handler's switch
|
|
175
175
|
case 'received':
|
|
176
|
-
NativeHCEModule
|
|
176
|
+
NativeHCEModule.setSessionAlertMessage('Keep holding the tag'); // only for iOS, no-op on Android
|
|
177
177
|
|
|
178
178
|
// decode incoming C-APDU to bytes
|
|
179
179
|
const capdu = Buffer.from(event.arg!, 'hex');
|
|
180
180
|
console.log('Received C-APDU, capdu.toString('hex'));
|
|
181
181
|
|
|
182
182
|
// for the demo purposes, we always want to respond with [0x0A] + status code 0x9000 (success)
|
|
183
|
-
await NativeHCEModule
|
|
183
|
+
await NativeHCEModule.respondAPDU(null, Buffer.from([0x0A, 0x90, 0x00]).toString("hex"));
|
|
184
184
|
break;
|
|
185
185
|
```
|
|
186
186
|
You don't have to respond to the APDU right away from within the event handler, but please remember that the reader might time out if you will be lingering with the response for too long.
|
|
@@ -189,16 +189,18 @@ This module provides a uniform low-level HCE API for both mobile platforms.
|
|
|
189
189
|
|
|
190
190
|
If you need to utilize `NFCPresentmentIntentAssertion` for enhanced user experience, call:
|
|
191
191
|
```typescript
|
|
192
|
-
NativeHCEModule
|
|
192
|
+
await NativeHCEModule.acquireExclusiveNFC();
|
|
193
193
|
```
|
|
194
194
|
This function will acquire an exclusive NFC access for 15 seconds. On system services or other applications will be able to interfere with NFC during that period. For example, the NFC background tag reading will be disabled so it would not generate any distracting notifications.
|
|
195
195
|
|
|
196
|
+
While both session and exclusive NFC access are active, you will receive `readerDetected` events even when the HCE emulation is not started at the time (without any explicit UI being displayed by the system). You can then make a call to `startHCE` to initiate the interaction automatically, without needing the user to click anything beforehand.
|
|
197
|
+
|
|
196
198
|
This function will throw an exception if:
|
|
197
199
|
* the presentment intent assertion was already acquired and is still active;
|
|
198
200
|
* you are in the cooldown period where you are not allowed to acquire the presentment intent assertion (cooldown is 15 seconds after the previous assertion had expired);
|
|
199
201
|
* the feature is not supported or the device is not eligible for whatever reason;
|
|
200
202
|
|
|
201
|
-
Call `NativeHCEModule
|
|
203
|
+
Call `NativeHCEModule.isExclusiveNFC()` to check if exclusive NFC access is still active.
|
|
202
204
|
|
|
203
205
|
### Android: Handle HCE calls when the app is not running
|
|
204
206
|
|
|
@@ -216,7 +218,7 @@ for instance - your app may emulate an NDEF tag even when it's not launched on t
|
|
|
216
218
|
}
|
|
217
219
|
});
|
|
218
220
|
```
|
|
219
|
-
2. Register onBackgroundEvent listener in your `runBackground()` function and call to `await NativeHCEModule
|
|
221
|
+
2. Register onBackgroundEvent listener in your `runBackground()` function and call to `await NativeHCEModule.initBackgroundHCE()` at the very end, after the event listener is fully set up.
|
|
220
222
|
```typescript
|
|
221
223
|
import { Buffer } from 'buffer/';
|
|
222
224
|
import {
|
|
@@ -254,5 +256,5 @@ for instance - your app may emulate an NDEF tag even when it's not launched on t
|
|
|
254
256
|
|
|
255
257
|
### More resources
|
|
256
258
|
|
|
257
|
-
* [Module's API specification](https://github.com/icedevml/react-native-host-card-emulation/blob/master/packages/host-card-emulation/js
|
|
259
|
+
* [Module's API specification](https://github.com/icedevml/react-native-host-card-emulation/blob/master/packages/host-card-emulation/js)
|
|
258
260
|
* [Demo App's Code (Example Library Usage)](https://github.com/icedevml/react-native-host-card-emulation/blob/master/packages/demo-ndef-app/App.tsx)
|
package/js/NativeHCEModule.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import type {TurboModule
|
|
1
|
+
import type {TurboModule} from 'react-native';
|
|
2
|
+
import type {EventEmitter} from 'react-native/Libraries/Types/CodegenTypes';
|
|
2
3
|
import {TurboModuleRegistry} from 'react-native';
|
|
3
4
|
|
|
4
5
|
export type HCEModuleEventType =
|
|
@@ -74,9 +75,6 @@ export interface Spec extends TurboModule {
|
|
|
74
75
|
*/
|
|
75
76
|
isSessionRunning(): boolean;
|
|
76
77
|
|
|
77
|
-
beginBackgroundHCE(handle: string): boolean;
|
|
78
|
-
finishBackgroundHCE(handle: string): boolean;
|
|
79
|
-
|
|
80
78
|
/**
|
|
81
79
|
* iOS: Start the card emulation.
|
|
82
80
|
* Android: Enable HCE service.
|
|
@@ -89,6 +87,7 @@ export interface Spec extends TurboModule {
|
|
|
89
87
|
stopHCE(status: HCEModuleStopReason): Promise<void>;
|
|
90
88
|
/**
|
|
91
89
|
* Send R-APDU (hex-encoded string) as a response to the last received C-APDU event.
|
|
90
|
+
* Set handle=null when calling this function from foreground app.
|
|
92
91
|
*/
|
|
93
92
|
respondAPDU(handle: string | null, rapdu: string): Promise<void>;
|
|
94
93
|
/**
|
|
@@ -97,8 +96,31 @@ export interface Spec extends TurboModule {
|
|
|
97
96
|
*/
|
|
98
97
|
isHCERunning(): Promise<boolean>;
|
|
99
98
|
|
|
100
|
-
|
|
101
|
-
|
|
99
|
+
/**
|
|
100
|
+
* Android: Report that the JS headless task is ready to handle HCE interaction in the background.
|
|
101
|
+
* NOTE: Don't call this API directly, use wrapper hceBackground.ts:createBackgroundHCE.
|
|
102
|
+
* See demo app or README.md for example wrapper usage.
|
|
103
|
+
*/
|
|
104
|
+
beginBackgroundHCE(handle: string): boolean;
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Android: Report the background HCE interaction was finished.
|
|
108
|
+
* NOTE: Don't call this API directly, use wrapper hceBackground.ts:createBackgroundHCE.
|
|
109
|
+
* See demo app or README.md for example wrapper usage.
|
|
110
|
+
*/
|
|
111
|
+
finishBackgroundHCE(handle: string): boolean;
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Event handler for foreground HCE interactions.
|
|
115
|
+
*/
|
|
116
|
+
readonly onEvent: EventEmitter<HCEModuleEvent>;
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Event handler for background HCE interactions.
|
|
120
|
+
* NOTE: Don't subscribe to that handler directly, use wrapper hceBackground.ts:createBackgroundHCE.
|
|
121
|
+
* See demo app or README.md for example wrapper usage.
|
|
122
|
+
*/
|
|
123
|
+
readonly onBackgroundEvent: EventEmitter<HCEModuleBackgroundEvent>;
|
|
102
124
|
}
|
|
103
125
|
|
|
104
126
|
export default TurboModuleRegistry.getEnforcing<Spec>(
|
package/package.json
CHANGED