@onekeyfe/react-native-lite-card 3.0.146 → 3.0.148

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.
@@ -40,6 +40,9 @@
40
40
  @property (nonatomic, strong) OKLiteV1 *lite;
41
41
 
42
42
  @property (nonatomic, strong) NSMutableDictionary *completionBlocks;
43
+ // CoreNFC reports the app's own invalidateSession with the same code as a user
44
+ // cancel, so the invalidation callback has to know who ended the session.
45
+ @property (atomic, assign) BOOL sessionEndedByApp;
43
46
 
44
47
  @end
45
48
 
@@ -58,6 +61,7 @@
58
61
 
59
62
 
60
63
  - (void)endNFCSessionWithError:(BOOL)isError {
64
+ self.sessionEndedByApp = YES;
61
65
  self.session.alertMessage = @"";
62
66
  if (isError) {
63
67
  [self.session invalidateSessionWithErrorMessage:OKTools.isChineseLan ? @"读取失败,请重试":@"Connect fail, please try again."];
@@ -75,7 +79,66 @@
75
79
  return _completionBlocks;
76
80
  }
77
81
 
82
+ // The card operation and the session invalidation run on different threads of
83
+ // the delegate queue and can both try to finish the same request, e.g. when the
84
+ // user cancels while the card is being read. Only the first caller gets the
85
+ // completion: React Native aborts the app when a callback runs twice.
86
+ - (id)takeCompletionForKey:(NSString *)key {
87
+ id completion = nil;
88
+ @synchronized (self) {
89
+ completion = [_completionBlocks objectForKey:key];
90
+ [_completionBlocks removeObjectForKey:key];
91
+ }
92
+ if (!completion) {
93
+ [LCLogger debug:[NSString stringWithFormat:@"%@ already finished, dropping the late result", key]];
94
+ }
95
+ return completion;
96
+ }
97
+
98
+ // Finishes the pending request when the session ends before the card operation
99
+ // reports its own result: as a cancel when the user or system ended the session,
100
+ // otherwise as a connection failure.
101
+ - (void)finishPendingRequestAsCancel:(BOOL)asCancel sessionError:(NSError *)sessionError {
102
+ switch (self.sessionType) {
103
+ case OKNFCLiteSessionTypeGetInfo:
104
+ case OKNFCLiteSessionTypeUpdateInfo:{
105
+ GetLiteInfoCallback callback = [self takeCompletionForKey:kGetLiteInfoBlock];
106
+ if (callback) {
107
+ callback(nil, OKNFCLiteStatusError);
108
+ }
109
+ } break;
110
+ case OKNFCLiteSessionTypeReset: {
111
+ ResetCallback callback = [self takeCompletionForKey:kResetBlock];
112
+ if (callback) {
113
+ callback(self.lite, NO, sessionError);
114
+ }
115
+ } break;
116
+ case OKNFCLiteSessionTypeSetMnemonic:
117
+ case OKNFCLiteSessionTypeSetMnemonicForce: {
118
+ SetMnemonicCallback callback = [self takeCompletionForKey:kSetMnemonicBlock];
119
+ if (callback) {
120
+ callback(self.lite, asCancel ? OKNFCLiteSetMncStatusCancel : OKNFCLiteSetMncStatusError);
121
+ }
122
+ } break;
123
+ case OKNFCLiteSessionTypeGetMnemonic: {
124
+ GetMnemonicCallback callback = [self takeCompletionForKey:kGetMnemonicBlock];
125
+ if (callback) {
126
+ callback(self.lite, nil, asCancel ? OKNFCLiteGetMncStatusCancel : OKNFCLiteGetMncStatusError);
127
+ }
128
+ } break;
129
+ case OKNFCLiteSessionTypeChangePin: {
130
+ ChangePinCallback callback = [self takeCompletionForKey:kChangePinBlock];
131
+ if (callback) {
132
+ callback(self.lite, asCancel ? OKNFCLiteChangePinStatusCancel : OKNFCLiteChangePinStatusError);
133
+ }
134
+ } break;
135
+ default:
136
+ break;
137
+ }
138
+ }
139
+
78
140
  - (void)beginNewNFCSession {
141
+ self.sessionEndedByApp = NO;
79
142
  self.session = [[NFCTagReaderSession alloc] initWithPollingOption:NFCPollingISO14443 delegate:self queue:dispatch_get_global_queue(2, 0)];
80
143
  [self.session beginSession];
81
144
  }
@@ -94,6 +157,7 @@
94
157
  [LCLogger error:errMsg];
95
158
  // [kTools debugTipMessage:errMsg];
96
159
  [self endNFCSessionWithError:YES];
160
+ [self finishPendingRequestAsCancel:NO sessionError:nil];
97
161
  return;
98
162
  }
99
163
  [self nfcSessionComplete:session];
@@ -102,44 +166,10 @@
102
166
 
103
167
  - (void)tagReaderSession:(NFCTagReaderSession *)session didInvalidateWithError:(NSError *)error {
104
168
  [LCLogger debug:[NSString stringWithFormat:@"tagReaderSession didInvalidateWithError: %@", error.localizedDescription]];
105
- if (error.code == 200 || error.code == 6) {
106
- switch (self.sessionType) {
107
- case OKNFCLiteSessionTypeGetInfo:
108
- case OKNFCLiteSessionTypeUpdateInfo:{
109
- GetLiteInfoCallback callback = [_completionBlocks objectForKey:kGetLiteInfoBlock];
110
- if(callback) {
111
- callback(nil,OKNFCLiteStatusError);
112
- }
113
- } break;
114
- case OKNFCLiteSessionTypeReset: {
115
- ResetCallback callback = [_completionBlocks objectForKey:kResetBlock];
116
- if (callback) {
117
- callback(self.lite, NO,error);
118
- }
119
- } break;
120
- case OKNFCLiteSessionTypeSetMnemonic:
121
- case OKNFCLiteSessionTypeSetMnemonicForce: {
122
- SetMnemonicCallback callback = [_completionBlocks objectForKey:kSetMnemonicBlock];
123
- if (callback) {
124
- callback(self.lite,OKNFCLiteSetMncStatusCancel);
125
- }
126
- } break;
127
- case OKNFCLiteSessionTypeGetMnemonic: {
128
- GetMnemonicCallback callback = [_completionBlocks objectForKey:kGetMnemonicBlock];
129
- if (callback) {
130
- callback(self.lite,nil,OKNFCLiteGetMncStatusCancel);
131
- }
132
- } break;
133
- case OKNFCLiteSessionTypeChangePin: {
134
- ChangePinCallback callback = [_completionBlocks objectForKey:kChangePinBlock];
135
- if (callback) {
136
- callback(self.lite,OKNFCLiteChangePinStatusCancel);
137
- }
138
-
139
- } break;
140
- default:
141
- break;
142
- }
169
+ // When the app ended the session, the card operation that ended it reports
170
+ // the real result; treating this as a cancel would race with it.
171
+ if ((error.code == 200 || error.code == 6) && !self.sessionEndedByApp) {
172
+ [self finishPendingRequestAsCancel:YES sessionError:error];
143
173
  }
144
174
  [session invalidateSession];
145
175
  }
@@ -153,6 +183,9 @@
153
183
  - (void)nfcSessionComplete:(NFCTagReaderSession *)session {
154
184
  if (![self checkLiteVersion]) {
155
185
  [self endNFCSessionWithError:YES];
186
+ [self finishPendingRequestAsCancel:NO sessionError:nil];
187
+ self.sessionType = OKNFCLiteSessionTypeNone;
188
+ return;
156
189
  }
157
190
  self.selectNFCApp = OKNFCLiteAppNONE;
158
191
  switch (self.sessionType) {
@@ -205,8 +238,13 @@
205
238
  }
206
239
 
207
240
  - (void)_getLiteInfo {
208
- GetLiteInfoCallback callback = [_completionBlocks objectForKey:kGetLiteInfoBlock];
209
- [self.lite getLiteInfo:callback];
241
+ __weak typeof(self) weakSelf = self;
242
+ [self.lite getLiteInfo:^(OKLiteV1 *lite, OKNFCLiteStatus status) {
243
+ GetLiteInfoCallback callback = [weakSelf takeCompletionForKey:kGetLiteInfoBlock];
244
+ if (callback) {
245
+ callback(lite, status);
246
+ }
247
+ }];
210
248
  }
211
249
 
212
250
  - (BOOL)syncLiteInfo {
@@ -237,13 +275,18 @@
237
275
  }
238
276
 
239
277
  - (void)_setMnemonic:(BOOL)force {
240
- SetMnemonicCallback callback = [_completionBlocks objectForKey:kSetMnemonicBlock];
241
278
  NSString *mnemonic = self.exportMnemonic;
242
279
  NSString *pin = self.pin;
243
280
  // Clear sensitive data from properties immediately
244
281
  self.exportMnemonic = nil;
245
282
  self.pin = nil;
246
- [self.lite setMnemonic:mnemonic withPin:pin overwrite:force complete:callback];
283
+ __weak typeof(self) weakSelf = self;
284
+ [self.lite setMnemonic:mnemonic withPin:pin overwrite:force complete:^(OKLiteV1 *lite, OKNFCLiteSetMncStatus status) {
285
+ SetMnemonicCallback callback = [weakSelf takeCompletionForKey:kSetMnemonicBlock];
286
+ if (callback) {
287
+ callback(lite, status);
288
+ }
289
+ }];
247
290
  }
248
291
 
249
292
  #pragma mark - getMnemonic
@@ -259,11 +302,16 @@
259
302
  }
260
303
 
261
304
  - (void)_getMnemonic {
262
- GetMnemonicCallback callback = [_completionBlocks objectForKey:kGetMnemonicBlock];
263
305
  NSString *pin = self.pin;
264
306
  // Clear sensitive data from property immediately
265
307
  self.pin = nil;
266
- [self.lite getMnemonicWithPin:pin complete:callback];
308
+ __weak typeof(self) weakSelf = self;
309
+ [self.lite getMnemonicWithPin:pin complete:^(OKLiteV1 *lite, NSString *mnemonic, OKNFCLiteGetMncStatus status) {
310
+ GetMnemonicCallback callback = [weakSelf takeCompletionForKey:kGetMnemonicBlock];
311
+ if (callback) {
312
+ callback(lite, mnemonic, status);
313
+ }
314
+ }];
267
315
  }
268
316
 
269
317
  #pragma mark - changePin
@@ -277,13 +325,18 @@
277
325
  }
278
326
 
279
327
  - (void)_changePin {
280
- ChangePinCallback callback = [_completionBlocks objectForKey:kChangePinBlock];
281
328
  NSString *oldPin = self.pin;
282
329
  NSString *newPin = self.neoPin;
283
330
  // Clear sensitive data from properties immediately
284
331
  self.pin = nil;
285
332
  self.neoPin = nil;
286
- [self.lite changePin:oldPin to:newPin complete:callback];
333
+ __weak typeof(self) weakSelf = self;
334
+ [self.lite changePin:oldPin to:newPin complete:^(OKLiteV1 *lite, OKNFCLiteChangePinStatus status) {
335
+ ChangePinCallback callback = [weakSelf takeCompletionForKey:kChangePinBlock];
336
+ if (callback) {
337
+ callback(lite, status);
338
+ }
339
+ }];
287
340
  }
288
341
 
289
342
  #pragma mark - reset
@@ -295,8 +348,13 @@
295
348
  }
296
349
 
297
350
  - (void)_reset {
298
- ResetCallback callback = [_completionBlocks objectForKey:kResetBlock];
299
- [self.lite reset:callback];
351
+ __weak typeof(self) weakSelf = self;
352
+ [self.lite reset:^(OKLiteV1 *lite, BOOL isSuccess, NSError *error) {
353
+ ResetCallback callback = [weakSelf takeCompletionForKey:kResetBlock];
354
+ if (callback) {
355
+ callback(lite, isSuccess, error);
356
+ }
357
+ }];
300
358
  }
301
359
 
302
360
  - (BOOL)_resetSync {
@@ -5,6 +5,9 @@
5
5
  #import "OKLiteV1.h"
6
6
  #import "LCLogger.h"
7
7
 
8
+ #include <atomic>
9
+ #include <memory>
10
+
8
11
  typedef NS_ENUM(NSInteger, NFCLiteExceptions) {
9
12
  NFCLiteExceptionsInitChannel = 1000,// 初始化异常
10
13
  NFCLiteExceptionsNotExistsNFC = 1001,// 没有 NFC 设备
@@ -25,6 +28,20 @@ typedef NS_ENUM(NSInteger, NFCLiteExceptions) {
25
28
  NFCLiteExceptionsNotInitialized = 4002,// 没有备份过内容
26
29
  };
27
30
 
31
+ // React Native aborts the app when a callback runs twice, and NFC results can
32
+ // arrive from more than one CoreNFC thread, so only the first result is sent.
33
+ static RCTResponseSenderBlock OKLiteCallbackOnce(RCTResponseSenderBlock callback)
34
+ {
35
+ auto invoked = std::make_shared<std::atomic<bool>>(false);
36
+ return ^(NSArray *response) {
37
+ if (invoked->exchange(true)) {
38
+ [LCLogger warn:@"Dropped a repeated Lite card callback"];
39
+ return;
40
+ }
41
+ callback(response);
42
+ };
43
+ }
44
+
28
45
  @implementation ReactNativeLiteCard
29
46
  - (NSNumber *)multiply:(double)a b:(double)b {
30
47
  NSNumber *result = @(a * b);
@@ -57,6 +74,7 @@ typedef NS_ENUM(NSInteger, NFCLiteExceptions) {
57
74
 
58
75
  - (void)getLiteInfo:(RCTResponseSenderBlock)callBack
59
76
  {
77
+ callBack = OKLiteCallbackOnce(callBack);
60
78
  if ([ReactNativeLiteCard checkSDKVaild:callBack]) {
61
79
  __block OKNFCManager *liteManager = [[OKNFCManager alloc] init];
62
80
  [liteManager getLiteInfo:^(OKLiteV1 *lite, OKNFCLiteStatus status) {
@@ -74,6 +92,7 @@ typedef NS_ENUM(NSInteger, NFCLiteExceptions) {
74
92
 
75
93
  - (void)setMnemonic:(NSString *)mnemonic pwd:(NSString *)pwd overwrite:(BOOL)overwrite callback:(RCTResponseSenderBlock)callBack
76
94
  {
95
+ callBack = OKLiteCallbackOnce(callBack);
77
96
  if ([ReactNativeLiteCard checkSDKVaild:callBack]) {
78
97
  __block OKNFCManager *liteManager = [[OKNFCManager alloc] init];
79
98
  [liteManager setMnemonic:mnemonic withPin:pwd overwrite:overwrite complete:^(OKLiteV1 *lite, OKNFCLiteSetMncStatus status) {
@@ -111,6 +130,7 @@ typedef NS_ENUM(NSInteger, NFCLiteExceptions) {
111
130
 
112
131
  - (void)getMnemonicWithPin:(NSString *)pwd callback:(RCTResponseSenderBlock)callBack
113
132
  {
133
+ callBack = OKLiteCallbackOnce(callBack);
114
134
  if ([ReactNativeLiteCard checkSDKVaild:callBack]) {
115
135
  __block OKNFCManager *liteManager = [[OKNFCManager alloc] init];
116
136
  [liteManager getMnemonicWithPin:pwd complete:^(OKLiteV1 *lite, NSString *mnemonic, OKNFCLiteGetMncStatus status) {
@@ -150,6 +170,7 @@ typedef NS_ENUM(NSInteger, NFCLiteExceptions) {
150
170
 
151
171
  - (void)changePin:(NSString *)oldPin newPin:(NSString *)newPin callback:(RCTResponseSenderBlock)callBack
152
172
  {
173
+ callBack = OKLiteCallbackOnce(callBack);
153
174
  if ([ReactNativeLiteCard checkSDKVaild:callBack]) {
154
175
  __block OKNFCManager *liteManager = [[OKNFCManager alloc] init];
155
176
  [liteManager changePin:oldPin to:newPin complete:^(OKLiteV1 *lite, OKNFCLiteChangePinStatus status) {
@@ -183,6 +204,7 @@ typedef NS_ENUM(NSInteger, NFCLiteExceptions) {
183
204
 
184
205
  - (void)reset:(RCTResponseSenderBlock)callBack
185
206
  {
207
+ callBack = OKLiteCallbackOnce(callBack);
186
208
  if ([ReactNativeLiteCard checkSDKVaild:callBack]) {
187
209
  __block OKNFCManager *liteManager = [[OKNFCManager alloc] init];
188
210
  [liteManager reset:^(OKLiteV1 *lite, BOOL isSuccess, NSError *error) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@onekeyfe/react-native-lite-card",
3
- "version": "3.0.146",
3
+ "version": "3.0.148",
4
4
  "description": "lite card",
5
5
  "main": "./lib/module/index.js",
6
6
  "types": "./lib/typescript/src/index.d.ts",