@icedevml/react-native-host-card-emulation 0.2.0 → 0.2.1

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.
@@ -1,125 +1,125 @@
1
- #import "RTNHCEModuleIOS.h"
2
- #import "RCTDefaultReactNativeFactoryDelegate.h"
3
- #import "RTNHCEModuleIOS-Swift.h"
4
-
5
- @implementation RTNHCEModuleIOS {
6
- API_AVAILABLE(ios(17.4))
7
- RTNHCEModuleIOSImpl *hcemoduleios;
8
- }
9
-
10
- -(id) init {
11
- self = [super init];
12
-
13
- if (@available(iOS 17.4, *)) {
14
- __weak RTNHCEModuleIOS *weakSelf = self;
15
-
16
- hcemoduleios = [RTNHCEModuleIOSImpl new];
17
- [hcemoduleios setEmitOnEventWithEmitOnEvent:^(NSString *type, NSString *arg){
18
- [weakSelf emitOnEvent:@{@"type": type, @"arg": arg}];
19
- }];
20
- } else {
21
- // ignore
22
- }
23
-
24
- return(self);
25
- }
26
-
27
- - (void)dealloc {
28
- [hcemoduleios setEmitOnEventWithEmitOnEvent:^(NSString *type, NSString *arg){
29
- // no-op
30
- }];
31
- }
32
-
33
- - (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:(const facebook::react::ObjCTurboModule::InitParams &)params {
34
- return std::make_shared<facebook::react::NativeHCEModuleSpecJSI>(params);
35
- }
36
-
37
- - (nonnull NSNumber *)isPlatformSupported {
38
- if (@available(iOS 17.4, *)) {
39
- return @1;
40
- }
41
-
42
- return @0;
43
- }
44
-
45
- - (void)acquireExclusiveNFC:(nonnull RCTPromiseResolveBlock)resolve reject:(nonnull RCTPromiseRejectBlock)reject {
46
- if (@available(iOS 17.4, *)) {
47
- return [hcemoduleios acquireExclusiveNFCWithResolve:resolve reject:reject];
48
- } else {
49
- reject(@"err_platform_unsupported", @"This iOS version does not support HCE.", nil);
50
- }
51
- }
52
-
53
- - (nonnull NSNumber *)isExclusiveNFC {
54
- if (@available(iOS 17.4, *)) {
55
- return [hcemoduleios isExclusiveNFC] ? @1 : @0;
56
- }
57
-
58
- return @0;
59
- }
60
-
61
- - (void)beginSession:(nonnull RCTPromiseResolveBlock)resolve reject:(nonnull RCTPromiseRejectBlock)reject {
62
- if (@available(iOS 17.4, *)) {
63
- return [hcemoduleios beginSessionWithResolve:resolve reject:reject];
64
- } else {
65
- reject(@"err_platform_unsupported", @"This iOS version does not support HCE.", nil);
66
- }
67
- }
68
-
69
- - (void)setSessionAlertMessage:(nonnull NSString *)message {
70
- if (@available(iOS 17.4, *)) {
71
- return [hcemoduleios setSessionAlertMessageWithMessage:message];
72
- }
73
- }
74
-
75
- - (void)invalidateSession {
76
- if (@available(iOS 17.4, *)) {
77
- [hcemoduleios invalidateSession];
78
- }
79
- }
80
-
81
- - (nonnull NSNumber *)isSessionRunning {
82
- if (@available(iOS 17.4, *)) {
83
- return [hcemoduleios isSessionRunning] ? @1 : @0;
84
- } else {
85
- return @0;
86
- }
87
- }
88
-
89
- - (void)startHCE:(nonnull RCTPromiseResolveBlock)resolve reject:(nonnull RCTPromiseRejectBlock)reject {
90
- if (@available(iOS 17.4, *)) {
91
- return [hcemoduleios startHCEWithResolve:resolve reject:reject];
92
- } else {
93
- reject(@"err_platform_unsupported", @"This iOS version does not support HCE.", nil);
94
- }
95
- }
96
-
97
- - (void)stopHCE:(nonnull NSString *)status resolve:(nonnull RCTPromiseResolveBlock)resolve reject:(nonnull RCTPromiseRejectBlock)reject {
98
- if (@available(iOS 17.4, *)) {
99
- return [hcemoduleios stopHCEWithStatus:status resolve:resolve reject:reject];
100
- } else {
101
- reject(@"err_platform_unsupported", @"This iOS version does not support HCE.", nil);
102
- }
103
- }
104
-
105
- - (void)respondAPDU:(nonnull NSString *)rapdu resolve:(nonnull RCTPromiseResolveBlock)resolve reject:(nonnull RCTPromiseRejectBlock)reject {
106
- if (@available(iOS 17.4, *)) {
107
- return [hcemoduleios respondAPDUWithRapdu:rapdu resolve:resolve reject:reject];
108
- } else {
109
- reject(@"err_platform_unsupported", @"This iOS version does not support HCE.", nil);
110
- }
111
- }
112
-
113
- - (void)isHCERunning:(nonnull RCTPromiseResolveBlock)resolve reject:(nonnull RCTPromiseRejectBlock)reject {
114
- if (@available(iOS 17.4, *)) {
115
- [hcemoduleios isHCERunningWithResolve:resolve reject:reject];
116
- } else {
117
- reject(@"err_platform_unsupported", @"This iOS version does not support HCE.", nil);
118
- }
119
- }
120
-
121
- + (NSString *)moduleName {
122
- return @"NativeHCEModule";
123
- }
124
-
125
- @end
1
+ #import "RTNHCEModuleIOS.h"
2
+ #import "RCTDefaultReactNativeFactoryDelegate.h"
3
+ #import "RTNHCEModuleIOS-Swift.h"
4
+
5
+ @implementation RTNHCEModuleIOS {
6
+ API_AVAILABLE(ios(17.4))
7
+ RTNHCEModuleIOSImpl *hcemoduleios;
8
+ }
9
+
10
+ -(id) init {
11
+ self = [super init];
12
+
13
+ if (@available(iOS 17.4, *)) {
14
+ __weak RTNHCEModuleIOS *weakSelf = self;
15
+
16
+ hcemoduleios = [RTNHCEModuleIOSImpl new];
17
+ [hcemoduleios setEmitOnEventWithEmitOnEvent:^(NSString *type, NSString *arg){
18
+ [weakSelf emitOnEvent:@{@"type": type, @"arg": arg}];
19
+ }];
20
+ } else {
21
+ // ignore
22
+ }
23
+
24
+ return(self);
25
+ }
26
+
27
+ - (void)dealloc {
28
+ [hcemoduleios setEmitOnEventWithEmitOnEvent:^(NSString *type, NSString *arg){
29
+ // no-op
30
+ }];
31
+ }
32
+
33
+ - (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:(const facebook::react::ObjCTurboModule::InitParams &)params {
34
+ return std::make_shared<facebook::react::NativeHCEModuleSpecJSI>(params);
35
+ }
36
+
37
+ - (nonnull NSNumber *)isPlatformSupported {
38
+ if (@available(iOS 17.4, *)) {
39
+ return @1;
40
+ }
41
+
42
+ return @0;
43
+ }
44
+
45
+ - (void)acquireExclusiveNFC:(nonnull RCTPromiseResolveBlock)resolve reject:(nonnull RCTPromiseRejectBlock)reject {
46
+ if (@available(iOS 17.4, *)) {
47
+ return [hcemoduleios acquireExclusiveNFCWithResolve:resolve reject:reject];
48
+ } else {
49
+ reject(@"err_platform_unsupported", @"This iOS version does not support HCE.", nil);
50
+ }
51
+ }
52
+
53
+ - (nonnull NSNumber *)isExclusiveNFC {
54
+ if (@available(iOS 17.4, *)) {
55
+ return [hcemoduleios isExclusiveNFC] ? @1 : @0;
56
+ }
57
+
58
+ return @0;
59
+ }
60
+
61
+ - (void)beginSession:(nonnull RCTPromiseResolveBlock)resolve reject:(nonnull RCTPromiseRejectBlock)reject {
62
+ if (@available(iOS 17.4, *)) {
63
+ return [hcemoduleios beginSessionWithResolve:resolve reject:reject];
64
+ } else {
65
+ reject(@"err_platform_unsupported", @"This iOS version does not support HCE.", nil);
66
+ }
67
+ }
68
+
69
+ - (void)setSessionAlertMessage:(nonnull NSString *)message {
70
+ if (@available(iOS 17.4, *)) {
71
+ return [hcemoduleios setSessionAlertMessageWithMessage:message];
72
+ }
73
+ }
74
+
75
+ - (void)invalidateSession {
76
+ if (@available(iOS 17.4, *)) {
77
+ [hcemoduleios invalidateSession];
78
+ }
79
+ }
80
+
81
+ - (nonnull NSNumber *)isSessionRunning {
82
+ if (@available(iOS 17.4, *)) {
83
+ return [hcemoduleios isSessionRunning] ? @1 : @0;
84
+ } else {
85
+ return @0;
86
+ }
87
+ }
88
+
89
+ - (void)startHCE:(nonnull RCTPromiseResolveBlock)resolve reject:(nonnull RCTPromiseRejectBlock)reject {
90
+ if (@available(iOS 17.4, *)) {
91
+ return [hcemoduleios startHCEWithResolve:resolve reject:reject];
92
+ } else {
93
+ reject(@"err_platform_unsupported", @"This iOS version does not support HCE.", nil);
94
+ }
95
+ }
96
+
97
+ - (void)stopHCE:(nonnull NSString *)status resolve:(nonnull RCTPromiseResolveBlock)resolve reject:(nonnull RCTPromiseRejectBlock)reject {
98
+ if (@available(iOS 17.4, *)) {
99
+ return [hcemoduleios stopHCEWithStatus:status resolve:resolve reject:reject];
100
+ } else {
101
+ reject(@"err_platform_unsupported", @"This iOS version does not support HCE.", nil);
102
+ }
103
+ }
104
+
105
+ - (void)respondAPDU:(nonnull NSString *)rapdu resolve:(nonnull RCTPromiseResolveBlock)resolve reject:(nonnull RCTPromiseRejectBlock)reject {
106
+ if (@available(iOS 17.4, *)) {
107
+ return [hcemoduleios respondAPDUWithRapdu:rapdu resolve:resolve reject:reject];
108
+ } else {
109
+ reject(@"err_platform_unsupported", @"This iOS version does not support HCE.", nil);
110
+ }
111
+ }
112
+
113
+ - (void)isHCERunning:(nonnull RCTPromiseResolveBlock)resolve reject:(nonnull RCTPromiseRejectBlock)reject {
114
+ if (@available(iOS 17.4, *)) {
115
+ [hcemoduleios isHCERunningWithResolve:resolve reject:reject];
116
+ } else {
117
+ reject(@"err_platform_unsupported", @"This iOS version does not support HCE.", nil);
118
+ }
119
+ }
120
+
121
+ + (NSString *)moduleName {
122
+ return @"NativeHCEModule";
123
+ }
124
+
125
+ @end
@@ -1,190 +1,190 @@
1
- import Foundation
2
- import CoreNFC
3
-
4
- extension StringProtocol {
5
- func asHexArray() -> [UInt8] {
6
- var startIndex = self.startIndex
7
- return stride(from: 0, to: count, by: 2).compactMap { _ in
8
- let endIndex = index(startIndex, offsetBy: 2, limitedBy: self.endIndex) ?? self.endIndex
9
- defer { startIndex = endIndex }
10
- return UInt8(self[startIndex..<endIndex], radix: 16)
11
- }
12
- }
13
- }
14
-
15
- extension Data {
16
- struct HexEncodingOptions: OptionSet {
17
- let rawValue: Int
18
- static let upperCase = HexEncodingOptions(rawValue: 1 << 0)
19
- }
20
-
21
- func hexEncodedString(options: HexEncodingOptions = []) -> String {
22
- let format = options.contains(.upperCase) ? "%02hhX" : "%02hhx"
23
- return map { String(format: format, $0) }.joined()
24
- }
25
- }
26
-
27
- @available(iOS 17.4, *)
28
- @objc public class RTNHCEModuleIOSImpl: NSObject {
29
- var cardSession: CardSession? = nil
30
- var cardSessionInvalidated: Bool = true
31
- var presentmentIntent: NFCPresentmentIntentAssertion? = nil
32
- var receivedCardAPDU: CardSession.APDU? = nil
33
-
34
- var emitOnEvent: ((NSString, NSString?) -> ())? = nil
35
-
36
- @objc public func setEmitOnEvent(emitOnEvent: @escaping (NSString, NSString?) -> ()) {
37
- self.emitOnEvent = emitOnEvent
38
- }
39
-
40
- @objc public func acquireExclusiveNFC(resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
41
- Task.init {
42
- if self.presentmentIntent != nil && self.presentmentIntent!.isValid {
43
- reject("err_already_exists", "NFCPresentmentIntentAssertion already exists and is valid.", nil)
44
- return
45
- }
46
-
47
- self.presentmentIntent = nil
48
-
49
- do {
50
- self.presentmentIntent = try await NFCPresentmentIntentAssertion.acquire()
51
- } catch (let error) {
52
- // TODO exact error details here and in other places as well
53
- reject("err_create_presentment", "Failed to create NFCPresentmentIntentAssertion: \(error)", nil)
54
- return
55
- }
56
-
57
- resolve(nil)
58
- }
59
- }
60
-
61
- @objc public func isExclusiveNFC() -> Bool {
62
- return self.presentmentIntent != nil && self.presentmentIntent!.isValid
63
- }
64
-
65
- @objc public func beginSession(resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
66
- Task.init {
67
- guard NFCReaderSession.readingAvailable else {
68
- reject("err_nfc_reader_not_available", "Preflight check failed: NFCReaderSession.readingAvailable is false", nil)
69
- return
70
- }
71
-
72
- guard CardSession.isSupported else {
73
- reject("err_card_session_unsupported", "Preflight check failed: CardSession.isSupported is false", nil)
74
- return
75
- }
76
-
77
- guard await CardSession.isEligible else {
78
- reject("err_card_session_not_eligible", "Preflight check failed: CardSession.isEligible is false", nil)
79
- return
80
- }
81
-
82
- guard self.cardSessionInvalidated else {
83
- reject("err_card_session_exists", "CardSession already exists.", nil)
84
- return
85
- }
86
-
87
- do {
88
- self.cardSession = try await CardSession()
89
- } catch (let error) {
90
- reject("err_create_card_session", "Failed to create CardSession(): \(error)", nil)
91
- return
92
- }
93
-
94
- resolve(nil)
95
-
96
- do {
97
- for try await event in cardSession!.eventStream {
98
- switch event {
99
- case .sessionStarted:
100
- cardSession!.alertMessage = String(localized: "Communicating with card reader.")
101
- self.emitOnEvent!("sessionStarted", "")
102
-
103
- case .readerDetected:
104
- self.emitOnEvent!("readerDetected", "")
105
-
106
- case .readerDeselected:
107
- self.emitOnEvent!("readerDeselected", "")
108
-
109
- case .received(let cardAPDU):
110
- self.receivedCardAPDU = cardAPDU
111
- self.emitOnEvent!("received", NSString(string:cardAPDU.payload.hexEncodedString()))
112
-
113
- case .sessionInvalidated(let reason):
114
- self.cardSessionInvalidated = true
115
- self.emitOnEvent!("sessionInvalidated", "\(reason)" as NSString)
116
- self.cardSession = nil
117
-
118
- @unknown default:
119
- fatalError("Received unknown CardSession event.")
120
- }
121
- }
122
- } catch (let err) {
123
- self.emitOnEvent!("internalError", "\(err)" as NSString)
124
- }
125
- }
126
- }
127
-
128
- @objc public func setSessionAlertMessage(message: NSString) {
129
- self.cardSession?.alertMessage = String(message)
130
- }
131
-
132
- @objc public func invalidateSession() {
133
- self.cardSession?.invalidate()
134
- self.cardSession = nil
135
- self.cardSessionInvalidated = true
136
- }
137
-
138
- @objc public func isSessionRunning() -> Bool {
139
- return self.cardSession != nil && !self.cardSessionInvalidated
140
- }
141
-
142
- @objc public func isHCERunning(resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
143
- Task.init {
144
- guard self.cardSession != nil else {
145
- return resolve(false)
146
- }
147
-
148
- let isRunning = await self.cardSession!.isEmulationInProgress
149
- resolve(isRunning)
150
- }
151
- }
152
-
153
- @objc public func respondAPDU(rapdu: NSString, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
154
- Task.init {
155
- guard let capdu = self.receivedCardAPDU else {
156
- reject("err_no_apdu_received", "There is no received APDU to respond to.", nil)
157
- return
158
- }
159
-
160
- do {
161
- try await capdu.respond(response: Data.init(String(rapdu).asHexArray()))
162
- } catch (let error) {
163
- reject("err_apdu_respond", "Error trying to respond to APDU. \(error)", nil)
164
- return
165
- }
166
-
167
- resolve(nil)
168
- }
169
- }
170
-
171
- @objc public func startHCE(resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
172
- Task.init {
173
- try await self.cardSession?.startEmulation()
174
- }
175
- }
176
-
177
- @objc public func stopHCE(status: NSString, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
178
- Task.init {
179
- let sStatus = String(status)
180
-
181
- if (sStatus == "success") {
182
- await self.cardSession?.stopEmulation(status: .success)
183
- } else {
184
- await self.cardSession?.stopEmulation(status: .failure)
185
- }
186
-
187
- resolve(nil)
188
- }
189
- }
190
- }
1
+ import Foundation
2
+ import CoreNFC
3
+
4
+ extension StringProtocol {
5
+ func asHexArray() -> [UInt8] {
6
+ var startIndex = self.startIndex
7
+ return stride(from: 0, to: count, by: 2).compactMap { _ in
8
+ let endIndex = index(startIndex, offsetBy: 2, limitedBy: self.endIndex) ?? self.endIndex
9
+ defer { startIndex = endIndex }
10
+ return UInt8(self[startIndex..<endIndex], radix: 16)
11
+ }
12
+ }
13
+ }
14
+
15
+ extension Data {
16
+ struct HexEncodingOptions: OptionSet {
17
+ let rawValue: Int
18
+ static let upperCase = HexEncodingOptions(rawValue: 1 << 0)
19
+ }
20
+
21
+ func hexEncodedString(options: HexEncodingOptions = []) -> String {
22
+ let format = options.contains(.upperCase) ? "%02hhX" : "%02hhx"
23
+ return map { String(format: format, $0) }.joined()
24
+ }
25
+ }
26
+
27
+ @available(iOS 17.4, *)
28
+ @objc public class RTNHCEModuleIOSImpl: NSObject {
29
+ var cardSession: CardSession? = nil
30
+ var cardSessionInvalidated: Bool = true
31
+ var presentmentIntent: NFCPresentmentIntentAssertion? = nil
32
+ var receivedCardAPDU: CardSession.APDU? = nil
33
+
34
+ var emitOnEvent: ((NSString, NSString?) -> ())? = nil
35
+
36
+ @objc public func setEmitOnEvent(emitOnEvent: @escaping (NSString, NSString?) -> ()) {
37
+ self.emitOnEvent = emitOnEvent
38
+ }
39
+
40
+ @objc public func acquireExclusiveNFC(resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
41
+ Task.init {
42
+ if self.presentmentIntent != nil && self.presentmentIntent!.isValid {
43
+ reject("err_already_exists", "NFCPresentmentIntentAssertion already exists and is valid.", nil)
44
+ return
45
+ }
46
+
47
+ self.presentmentIntent = nil
48
+
49
+ do {
50
+ self.presentmentIntent = try await NFCPresentmentIntentAssertion.acquire()
51
+ } catch (let error) {
52
+ // TODO exact error details here and in other places as well
53
+ reject("err_create_presentment", "Failed to create NFCPresentmentIntentAssertion: \(error)", nil)
54
+ return
55
+ }
56
+
57
+ resolve(nil)
58
+ }
59
+ }
60
+
61
+ @objc public func isExclusiveNFC() -> Bool {
62
+ return self.presentmentIntent != nil && self.presentmentIntent!.isValid
63
+ }
64
+
65
+ @objc public func beginSession(resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
66
+ Task.init {
67
+ guard NFCReaderSession.readingAvailable else {
68
+ reject("err_nfc_reader_not_available", "Preflight check failed: NFCReaderSession.readingAvailable is false", nil)
69
+ return
70
+ }
71
+
72
+ guard CardSession.isSupported else {
73
+ reject("err_card_session_unsupported", "Preflight check failed: CardSession.isSupported is false", nil)
74
+ return
75
+ }
76
+
77
+ guard await CardSession.isEligible else {
78
+ reject("err_card_session_not_eligible", "Preflight check failed: CardSession.isEligible is false", nil)
79
+ return
80
+ }
81
+
82
+ guard self.cardSessionInvalidated else {
83
+ reject("err_card_session_exists", "CardSession already exists.", nil)
84
+ return
85
+ }
86
+
87
+ do {
88
+ self.cardSession = try await CardSession()
89
+ } catch (let error) {
90
+ reject("err_create_card_session", "Failed to create CardSession(): \(error)", nil)
91
+ return
92
+ }
93
+
94
+ resolve(nil)
95
+
96
+ do {
97
+ for try await event in cardSession!.eventStream {
98
+ switch event {
99
+ case .sessionStarted:
100
+ cardSession!.alertMessage = String(localized: "Communicating with card reader.")
101
+ self.emitOnEvent!("sessionStarted", "")
102
+
103
+ case .readerDetected:
104
+ self.emitOnEvent!("readerDetected", "")
105
+
106
+ case .readerDeselected:
107
+ self.emitOnEvent!("readerDeselected", "")
108
+
109
+ case .received(let cardAPDU):
110
+ self.receivedCardAPDU = cardAPDU
111
+ self.emitOnEvent!("received", NSString(string:cardAPDU.payload.hexEncodedString()))
112
+
113
+ case .sessionInvalidated(let reason):
114
+ self.cardSessionInvalidated = true
115
+ self.emitOnEvent!("sessionInvalidated", "\(reason)" as NSString)
116
+ self.cardSession = nil
117
+
118
+ @unknown default:
119
+ fatalError("Received unknown CardSession event.")
120
+ }
121
+ }
122
+ } catch (let err) {
123
+ self.emitOnEvent!("internalError", "\(err)" as NSString)
124
+ }
125
+ }
126
+ }
127
+
128
+ @objc public func setSessionAlertMessage(message: NSString) {
129
+ self.cardSession?.alertMessage = String(message)
130
+ }
131
+
132
+ @objc public func invalidateSession() {
133
+ self.cardSession?.invalidate()
134
+ self.cardSession = nil
135
+ self.cardSessionInvalidated = true
136
+ }
137
+
138
+ @objc public func isSessionRunning() -> Bool {
139
+ return self.cardSession != nil && !self.cardSessionInvalidated
140
+ }
141
+
142
+ @objc public func isHCERunning(resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
143
+ Task.init {
144
+ guard self.cardSession != nil else {
145
+ return resolve(false)
146
+ }
147
+
148
+ let isRunning = await self.cardSession!.isEmulationInProgress
149
+ resolve(isRunning)
150
+ }
151
+ }
152
+
153
+ @objc public func respondAPDU(rapdu: NSString, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
154
+ Task.init {
155
+ guard let capdu = self.receivedCardAPDU else {
156
+ reject("err_no_apdu_received", "There is no received APDU to respond to.", nil)
157
+ return
158
+ }
159
+
160
+ do {
161
+ try await capdu.respond(response: Data.init(String(rapdu).asHexArray()))
162
+ } catch (let error) {
163
+ reject("err_apdu_respond", "Error trying to respond to APDU. \(error)", nil)
164
+ return
165
+ }
166
+
167
+ resolve(nil)
168
+ }
169
+ }
170
+
171
+ @objc public func startHCE(resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
172
+ Task.init {
173
+ try await self.cardSession?.startEmulation()
174
+ }
175
+ }
176
+
177
+ @objc public func stopHCE(status: NSString, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
178
+ Task.init {
179
+ let sStatus = String(status)
180
+
181
+ if (sStatus == "success") {
182
+ await self.cardSession?.stopEmulation(status: .success)
183
+ } else {
184
+ await self.cardSession?.stopEmulation(status: .failure)
185
+ }
186
+
187
+ resolve(nil)
188
+ }
189
+ }
190
+ }