@digitalshieldfe/react-native-backup-card-sdk 0.1.5 → 0.1.6

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.
Files changed (29) hide show
  1. package/android/build.gradle +27 -0
  2. package/android/libs/backupcardsdk.aar +0 -0
  3. package/android/src/main/java/com/ziancube/reactnativebackupcardsdk/BackupCardSdkModule.kt +244 -74
  4. package/android/src/main/java/com/ziancube/reactnativebackupcardsdk/BackupCardSdkPackage.kt +1 -1
  5. package/android/src/main/java/com/ziancube/reactnativebackupcardsdk/nfc/NfcExceptions.kt +11 -0
  6. package/android/src/main/java/com/ziancube/reactnativebackupcardsdk/nfc/NfcUtils.kt +30 -0
  7. package/android/src/main/java/com/ziancube/reactnativebackupcardsdk/utils/MiUtil.kt +74 -0
  8. package/android/src/main/java/com/ziancube/reactnativebackupcardsdk/utils/NfcPermissionUtils.kt +23 -0
  9. package/lib/module/NativeBackupCardSdk.js +3 -0
  10. package/lib/module/NativeBackupCardSdk.js.map +1 -1
  11. package/lib/module/cardOperations.js +27 -0
  12. package/lib/module/cardOperations.js.map +1 -0
  13. package/lib/module/index.js +2 -0
  14. package/lib/module/index.js.map +1 -1
  15. package/lib/module/nfc.js +75 -0
  16. package/lib/module/nfc.js.map +1 -0
  17. package/lib/typescript/src/NativeBackupCardSdk.d.ts +50 -4
  18. package/lib/typescript/src/NativeBackupCardSdk.d.ts.map +1 -1
  19. package/lib/typescript/src/cardOperations.d.ts +7 -0
  20. package/lib/typescript/src/cardOperations.d.ts.map +1 -0
  21. package/lib/typescript/src/index.d.ts +5 -2
  22. package/lib/typescript/src/index.d.ts.map +1 -1
  23. package/lib/typescript/src/nfc.d.ts +28 -0
  24. package/lib/typescript/src/nfc.d.ts.map +1 -0
  25. package/package.json +2 -2
  26. package/src/NativeBackupCardSdk.ts +62 -4
  27. package/src/cardOperations.ts +61 -0
  28. package/src/index.tsx +22 -2
  29. package/src/nfc.ts +74 -0
@@ -32,6 +32,33 @@ apply plugin: "kotlin-android"
32
32
 
33
33
  apply plugin: "com.facebook.react"
34
34
 
35
+ react {
36
+ jsRootDir = file("../src/")
37
+ libraryName = "BackupCardSdkSpec"
38
+ codegenJavaPackageName = "com.ziancube.reactnativebackupcardsdk"
39
+ }
40
+
41
+ // Kotlin/Java TurboModule uses BackupCardSdkSpec-generated.cpp (JavaTurboModule).
42
+ // BackupCardSdkSpecJSI-generated.cpp targets a C++ module class that is not implemented
43
+ // and conflicts with BackupCardSdkSpecJSI.h from the same codegen run.
44
+ def patchBackupCardCodegen = tasks.register("patchBackupCardCodegen") {
45
+ doLast {
46
+ def jsiCpp =
47
+ file(
48
+ "${layout.buildDirectory.get()}/generated/source/codegen/jni/react/renderer/components/BackupCardSdkSpec/BackupCardSdkSpecJSI-generated.cpp"
49
+ )
50
+ if (jsiCpp.exists()) {
51
+ jsiCpp.delete()
52
+ }
53
+ }
54
+ }
55
+
56
+ tasks.configureEach { task ->
57
+ if (task.name == "generateCodegenArtifactsFromSchema") {
58
+ task.finalizedBy(patchBackupCardCodegen)
59
+ }
60
+ }
61
+
35
62
  android {
36
63
  namespace "com.ziancube.reactnativebackupcardsdk"
37
64
 
Binary file
@@ -1,6 +1,8 @@
1
1
  package com.ziancube.reactnativebackupcardsdk
2
2
 
3
+ import android.app.Activity
3
4
  import android.content.Intent
5
+ import android.util.Log
4
6
  import com.facebook.react.bridge.Arguments
5
7
  import com.facebook.react.bridge.BaseActivityEventListener
6
8
  import com.facebook.react.bridge.Promise
@@ -12,7 +14,12 @@ import com.facebook.react.bridge.LifecycleEventListener
12
14
  import com.ziancube.backupcardsdk.ApduLogger
13
15
  import com.ziancube.backupcardsdk.BackupCardSdk
14
16
  import com.ziancube.backupcardsdk.NfcTouchListener
17
+ import com.ziancube.backupcardsdk.CardOperationResult
15
18
  import com.ziancube.backupcardsdk.CardInfo
19
+ import com.ziancube.backupcardsdk.NfcWaitTimeoutException
20
+ import com.ziancube.reactnativebackupcardsdk.nfc.NfcExceptions
21
+ import com.ziancube.reactnativebackupcardsdk.nfc.NfcUtils
22
+ import com.ziancube.reactnativebackupcardsdk.utils.NfcPermissionUtils
16
23
  import kotlinx.coroutines.CoroutineDispatcher
17
24
  import kotlinx.coroutines.CoroutineScope
18
25
  import kotlinx.coroutines.Dispatchers
@@ -21,47 +28,73 @@ import kotlinx.coroutines.cancel
21
28
  import kotlinx.coroutines.launch
22
29
  import kotlinx.coroutines.withContext
23
30
 
24
- fun CardInfo.toWritableMap(): WritableMap {
25
- val map = Arguments.createMap()
26
- map.putString("serialNumber", serialNumber)
27
- map.putInt("pinRetryCount", pinRetryCount ?: -1)
28
- map.putBoolean("isNewCard", isNewCard ?: false)
29
- return map
30
- }
31
-
32
- fun ReadableArray.toByteArray(): ByteArray {
33
- val bytes = ByteArray(size())
34
- for (i in 0 until size()) {
35
- bytes[i] = getInt(i).toByte()
36
- }
37
- return bytes
38
- }
39
-
40
- fun ByteArray?.toWritableArrayOrNull(): WritableArray? {
41
- if (this == null) return null
42
- val array = Arguments.createArray()
43
- for (b in this) {
44
- array.pushInt(b.toInt() and 0xFF)
45
- }
46
- return array
47
- }
48
-
49
-
50
31
  class BackupCardSdkModule(val reactContext: ReactApplicationContext) :
51
32
  NativeBackupCardSdkSpec(reactContext) ,LifecycleEventListener
52
33
  {
53
- private lateinit var backupCardSdk: BackupCardSdk
34
+ private var backupCardSdk: BackupCardSdk? = null
35
+ private var boundActivity: Activity? = null
54
36
  private val tag = "BackupCardSdkModule"
55
37
  private val scope = CoroutineScope(SupervisorJob() + Dispatchers.Main.immediate)
38
+
39
+ private val apduLogger =
40
+ object : ApduLogger {
41
+ override fun log(message: String, isSent: Boolean, isSuccess: Boolean) {
42
+ val params =
43
+ Arguments.createMap()
44
+ .apply {
45
+ putString("message", message)
46
+ putBoolean("isSent", isSent)
47
+ putBoolean("isSuccess", isSuccess)
48
+ }
49
+ .copy()
50
+ runCatching { emitOnApduLog(params) }
51
+ .onFailure { Log.w(tag, "Dropped apduLog event: JS callback is not ready", it) }
52
+ }
53
+ }
54
+
55
+ private val nfcTouchListener =
56
+ object : NfcTouchListener {
57
+ override fun onTouch(isBackupCard: Boolean) {
58
+ val params =
59
+ Arguments.createMap()
60
+ .apply { putBoolean("isBackupCard", isBackupCard) }
61
+ .copy()
62
+ runCatching { emitOnNfcTouch(params) }
63
+ .onFailure { Log.w(tag, "Dropped nfcTouch event: JS callback is not ready", it) }
64
+ }
65
+ }
66
+
67
+ private fun ensureBackupCardSdk(activity: Activity?): BackupCardSdk? {
68
+ if (activity == null) return null
69
+ if (backupCardSdk != null && boundActivity === activity) return backupCardSdk
70
+
71
+ runCatching { backupCardSdk?.release() }
72
+ .onFailure { Log.e(tag, "Failed to release previous BackupCardSdk", it) }
73
+
74
+ boundActivity = activity
75
+ backupCardSdk = runCatching { BackupCardSdk(activity, apduLogger, nfcTouchListener) }
76
+ .onFailure { Log.e(tag, "Failed to initialize BackupCardSdk", it) }
77
+ .getOrNull()
78
+ return backupCardSdk
79
+ }
80
+
56
81
  override fun invalidate() {
57
82
  super.invalidate()
83
+ backupCardSdk?.cancelWaitForCardTag()
84
+ backupCardSdk?.release()
85
+ backupCardSdk = null
86
+ boundActivity = null
58
87
  scope.cancel()
59
88
  }
60
89
  private val mActivityEventListener =
61
90
  object : BaseActivityEventListener() {
62
91
  override fun onNewIntent(intent: Intent) {
63
92
  super.onNewIntent(intent)
64
- backupCardSdk.handleIntent(intent)
93
+ runCatching {
94
+ backupCardSdk?.handleIntent(intent)
95
+ }.onFailure {
96
+ Log.e(tag, "Crash while handling NFC intent", it)
97
+ }
65
98
  }
66
99
  }
67
100
 
@@ -69,37 +102,76 @@ class BackupCardSdkModule(val reactContext: ReactApplicationContext) :
69
102
  super.initialize()
70
103
  Utils.init(reactContext)
71
104
  Utils.getActivityLifecycle()
72
- val activity = Utils.getTopActivity()
73
- if (activity == null) {
74
- return
75
- }
76
- val apduLogger =
77
- object : ApduLogger {
78
- override fun log(message: String, isSent: Boolean, isSuccess: Boolean) {
79
- val params =
80
- Arguments.createMap()
81
- .apply {
82
- putString("message", message)
83
- putBoolean("isSent", isSent)
84
- putBoolean("isSuccess", isSuccess)
85
- }
86
- .copy()
87
- emitOnApduLog(params)
88
- }
89
- }
90
- val nfcTouchListener =
91
- object : NfcTouchListener {
92
- override fun onTouch(isBackupCard: Boolean) {
93
- val params =
94
- Arguments.createMap()
95
- .apply { putBoolean("isBackupCard", isBackupCard) }
96
- .copy()
97
- emitOnNfcTouch(params)
98
- }
99
- }
100
- backupCardSdk = BackupCardSdk(activity, apduLogger, nfcTouchListener)
101
105
  reactContext.addActivityEventListener(mActivityEventListener)
102
106
  reactContext.addLifecycleEventListener(this)
107
+ ensureBackupCardSdk(Utils.getTopActivity())
108
+ }
109
+
110
+ private fun CardInfo.toCardInfoMap(): WritableMap {
111
+ val map = Arguments.createMap()
112
+ map.putString("serialNumber", serialNumber)
113
+ map.putInt("pinRetryCount", pinRetryCount ?: -1)
114
+ map.putBoolean("isNewCard", isNewCard ?: false)
115
+ val backup = isBackup
116
+ if (backup != null) {
117
+ map.putBoolean("isBackup", backup)
118
+ } else {
119
+ map.putNull("isBackup")
120
+ }
121
+ return map
122
+ }
123
+
124
+ private fun putOperationData(map: WritableMap, data: Any?) {
125
+ when (data) {
126
+ null -> map.putNull("data")
127
+ is Boolean -> map.putBoolean("data", data)
128
+ is Int -> map.putInt("data", data)
129
+ is Long -> map.putDouble("data", data.toDouble())
130
+ is Double -> map.putDouble("data", data)
131
+ is Float -> map.putDouble("data", data.toDouble())
132
+ is String -> map.putString("data", data)
133
+ is ByteArray -> map.putArray("data", data.asWritableArrayOrNull())
134
+ else -> map.putNull("data")
135
+ }
136
+ }
137
+
138
+ private fun CardOperationResult<*>.toCardOperationResultMap(): WritableMap {
139
+ val map = Arguments.createMap()
140
+ val cardError = error
141
+ val info = cardInfo
142
+ if (cardError != null) {
143
+ val errorMap = Arguments.createMap()
144
+ errorMap.putInt("code", cardError.code)
145
+ errorMap.putString("message", cardError.message)
146
+ map.putMap("error", errorMap)
147
+ } else {
148
+ map.putNull("error")
149
+ }
150
+ if (info != null) {
151
+ map.putMap("cardInfo", info.toCardInfoMap())
152
+ } else {
153
+ map.putNull("cardInfo")
154
+ }
155
+ map.putInt("resultCode", resultCode)
156
+ putOperationData(map, data)
157
+ return map
158
+ }
159
+
160
+ private fun ReadableArray.asByteArray(): ByteArray {
161
+ val bytes = ByteArray(size())
162
+ for (i in 0 until size()) {
163
+ bytes[i] = getInt(i).toByte()
164
+ }
165
+ return bytes
166
+ }
167
+
168
+ private fun ByteArray?.asWritableArrayOrNull(): WritableArray? {
169
+ if (this == null) return null
170
+ val array = Arguments.createArray()
171
+ for (b in this) {
172
+ array.pushInt(b.toInt() and 0xFF)
173
+ }
174
+ return array
103
175
  }
104
176
 
105
177
  companion object {
@@ -108,44 +180,125 @@ class BackupCardSdkModule(val reactContext: ReactApplicationContext) :
108
180
 
109
181
  override fun getCardInfo(promise: Promise) =
110
182
  promise.launchSuspend(
111
- block = { backupCardSdk.getCardInfo() },
112
- transform = { info -> info?.toWritableMap() }
183
+ block = {
184
+ val sdk = ensureBackupCardSdk(Utils.getTopActivity())
185
+ ?: throw IllegalStateException("No foreground activity available")
186
+ sdk.getCardInfo()
187
+ },
188
+ transform = { info -> info?.toCardInfoMap() }
113
189
  )
114
190
 
191
+ override fun cancelNfcWait() {
192
+ backupCardSdk?.cancelWaitForCardTag()
193
+ }
194
+
195
+ override fun checkNFCPermission(promise: Promise) {
196
+ val activity = Utils.getTopActivity()
197
+ if (activity == null) {
198
+ promise.rejectNfc(NfcExceptions.InitializedException("No foreground activity"))
199
+ return
200
+ }
201
+ if (!NfcUtils.isNfcExits(activity)) {
202
+ promise.rejectNfc(NfcExceptions.NotExistsNFC())
203
+ return
204
+ }
205
+ if (!NfcUtils.isNfcEnable(activity)) {
206
+ promise.rejectNfc(NfcExceptions.NotEnableNFC())
207
+ return
208
+ }
209
+ var granted = false
210
+ NfcPermissionUtils.checkPermission(activity) { granted = true }
211
+ if (granted) {
212
+ promise.resolve(true)
213
+ } else {
214
+ promise.rejectNfc(NfcExceptions.NotNFCPermission())
215
+ }
216
+ }
217
+
218
+ override fun intoSetting() {
219
+ val activity = Utils.getTopActivity() ?: return
220
+ NfcUtils.intentToNfcSetting(activity)
221
+ }
222
+
223
+ private fun Promise.rejectNfc(exception: NfcExceptions) {
224
+ val userInfo =
225
+ Arguments.createMap()
226
+ .apply {
227
+ putInt("code", exception.code)
228
+ putString("message", exception.message ?: "")
229
+ }
230
+ .copy()
231
+ reject("NFC_ERROR", exception.message, null, userInfo)
232
+ }
233
+
115
234
  override fun resetCard(promise: Promise) =
116
235
  promise.launchSuspend(
117
- block = { backupCardSdk.resetCard() },
236
+ block = {
237
+ val sdk = ensureBackupCardSdk(Utils.getTopActivity())
238
+ ?: throw IllegalStateException("No foreground activity available")
239
+ sdk.resetCard()
240
+ },
118
241
  transform = { result -> result }
119
242
  )
120
243
 
121
- override fun activateCard(pwd: String, promise: Promise) =
244
+ override fun activateCard(pwd: String, serialNumber: String, promise: Promise) =
122
245
  promise.launchSuspend(
123
- block = { backupCardSdk.activateCard(pwd) },
124
- transform = { result -> result }
246
+ block = {
247
+ val sdk = ensureBackupCardSdk(Utils.getTopActivity())
248
+ ?: throw IllegalStateException("No foreground activity available")
249
+ sdk.activateCard(pwd, serialNumber)
250
+ },
251
+ transform = { result -> result.toCardOperationResultMap() }
125
252
  )
126
253
 
127
254
  override fun changePin(oldPin: String, newPin: String, promise: Promise) =
128
255
  promise.launchSuspend(
129
- block = { backupCardSdk.changePin(oldPin, newPin) },
256
+ block = {
257
+ val sdk = ensureBackupCardSdk(Utils.getTopActivity())
258
+ ?: throw IllegalStateException("No foreground activity available")
259
+ sdk.changePin(oldPin, newPin)
260
+ },
130
261
  transform = { result -> result }
131
262
  )
132
263
 
133
264
  override fun checkSlotEmpty(slotId: Double, pwd: String, promise: Promise) =
134
265
  promise.launchSuspend(
135
- block = { backupCardSdk.checkSlotEmpty(slotId.toInt(), pwd) },
136
- transform = { result -> result }
266
+ block = {
267
+ val sdk = ensureBackupCardSdk(Utils.getTopActivity())
268
+ ?: throw IllegalStateException("No foreground activity available")
269
+ sdk.checkSlotEmpty(slotId.toInt(), pwd)
270
+ },
271
+ transform = { result -> result.toCardOperationResultMap() }
137
272
  )
138
273
 
139
274
  override fun writeSlot(slotIndex: Double, data: ReadableArray, pwd: String, promise: Promise) =
140
275
  promise.launchSuspend(
141
- block = { backupCardSdk.writeSlot(slotIndex.toInt(), data.toByteArray(), pwd) },
142
- transform = { result -> result }
276
+ block = {
277
+ val sdk = ensureBackupCardSdk(Utils.getTopActivity())
278
+ ?: throw IllegalStateException("No foreground activity available")
279
+ sdk.writeSlot(slotIndex.toInt(), data.asByteArray(), pwd)
280
+ },
281
+ transform = { result -> result.toCardOperationResultMap() }
143
282
  )
144
283
 
145
284
  override fun readSlot(slotIndex: Double, pwd: String, promise: Promise) =
146
285
  promise.launchSuspend(
147
- block = { backupCardSdk.readSlot(slotIndex.toInt(), pwd) },
148
- transform = { result -> result.toWritableArrayOrNull() }
286
+ block = {
287
+ val sdk = ensureBackupCardSdk(Utils.getTopActivity())
288
+ ?: throw IllegalStateException("No foreground activity available")
289
+ sdk.readSlot(slotIndex.toInt(), pwd)
290
+ },
291
+ transform = { result -> result.toCardOperationResultMap() }
292
+ )
293
+
294
+ override fun deleteSlot(slotIndex: Double, pwd: String, promise: Promise) =
295
+ promise.launchSuspend(
296
+ block = {
297
+ val sdk = ensureBackupCardSdk(Utils.getTopActivity())
298
+ ?: throw IllegalStateException("No foreground activity available")
299
+ sdk.deleteSlot(slotIndex.toInt(), pwd)
300
+ },
301
+ transform = { result -> result.toCardOperationResultMap() }
149
302
  )
150
303
 
151
304
 
@@ -154,7 +307,12 @@ class BackupCardSdkModule(val reactContext: ReactApplicationContext) :
154
307
  dispatcher: CoroutineDispatcher = Dispatchers.IO,
155
308
  block: suspend () -> T,
156
309
  transform: (T) -> R,
157
- errorCode: (Throwable) -> String = { "E_UNEXPECTED" }
310
+ errorCode: (Throwable) -> String = { throwable ->
311
+ when (throwable) {
312
+ is NfcWaitTimeoutException -> "NFC_WAIT_TIMEOUT"
313
+ else -> "E_UNEXPECTED"
314
+ }
315
+ }
158
316
  ) {
159
317
  scope.launch {
160
318
  try {
@@ -170,14 +328,26 @@ class BackupCardSdkModule(val reactContext: ReactApplicationContext) :
170
328
  }
171
329
 
172
330
  override fun onHostResume() {
173
- backupCardSdk.onActivityResumed()
331
+ runCatching {
332
+ val sdk = ensureBackupCardSdk(Utils.getTopActivity())
333
+ sdk?.onActivityResumed()
334
+ if (sdk != null) {
335
+ Log.i(tag, "NFC foreground dispatch enabled automatically on app resume.")
336
+ } else {
337
+ Log.w(tag, "Skipped NFC foreground dispatch: no foreground activity.")
338
+ }
339
+ }.onFailure {
340
+ Log.e(tag, "Failed to enable NFC foreground dispatch on resume", it)
341
+ }
174
342
  }
175
343
 
176
344
  override fun onHostPause() {
177
- backupCardSdk.onActivityPaused()
345
+ runCatching { backupCardSdk?.onActivityPaused() }
346
+ .onFailure { Log.e(tag, "Failed to disable NFC foreground dispatch on pause", it) }
178
347
  }
179
348
 
180
349
  override fun onHostDestroy() {
181
- backupCardSdk.onActivityDestroyed()
350
+ runCatching { backupCardSdk?.onActivityDestroyed() }
351
+ .onFailure { Log.e(tag, "Failed to cleanup NFC on destroy", it) }
182
352
  }
183
353
  }
@@ -22,7 +22,7 @@ class BackupCardSdkPackage : BaseReactPackage() {
22
22
  name = BackupCardSdkModule.NAME,
23
23
  className = BackupCardSdkModule.NAME,
24
24
  canOverrideExistingModule = false,
25
- needsEagerInit = false,
25
+ needsEagerInit = true,
26
26
  isCxxModule = false,
27
27
  isTurboModule = true
28
28
  )
@@ -0,0 +1,11 @@
1
+ package com.ziancube.reactnativebackupcardsdk.nfc
2
+
3
+ sealed class NfcExceptions(val code: Int, override val message: String? = null) : Exception(message) {
4
+ class InitializedException(message: String? = null) : NfcExceptions(4001, message)
5
+
6
+ class NotExistsNFC(message: String? = null) : NfcExceptions(1001, message)
7
+
8
+ class NotEnableNFC(message: String? = null) : NfcExceptions(1002, message)
9
+
10
+ class NotNFCPermission(message: String? = null) : NfcExceptions(1003, message)
11
+ }
@@ -0,0 +1,30 @@
1
+ package com.ziancube.reactnativebackupcardsdk.nfc
2
+
3
+ import android.content.Context
4
+ import android.content.Intent
5
+ import android.nfc.NfcAdapter
6
+ import android.provider.Settings
7
+
8
+ object NfcUtils {
9
+ fun isNfcExits(context: Context): Boolean {
10
+ return NfcAdapter.getDefaultAdapter(context) != null
11
+ }
12
+
13
+ fun isNfcEnable(context: Context): Boolean {
14
+ val nfcAdapter = NfcAdapter.getDefaultAdapter(context)
15
+ return nfcAdapter != null && nfcAdapter.isEnabled
16
+ }
17
+
18
+ fun intentToNfcSetting(context: Context): Boolean {
19
+ if (!isNfcExits(context)) {
20
+ return false
21
+ }
22
+ return try {
23
+ context.startActivity(Intent(Settings.ACTION_NFC_SETTINGS))
24
+ true
25
+ } catch (ex: Exception) {
26
+ ex.printStackTrace()
27
+ false
28
+ }
29
+ }
30
+ }
@@ -0,0 +1,74 @@
1
+ package com.ziancube.reactnativebackupcardsdk.utils
2
+
3
+ import android.app.AppOpsManager
4
+ import android.content.Context
5
+ import android.content.Intent
6
+ import android.net.Uri
7
+ import android.os.Build
8
+ import android.provider.Settings
9
+ import android.util.Log
10
+ import androidx.annotation.IntDef
11
+ import androidx.annotation.RequiresApi
12
+
13
+ object MiUtil {
14
+ private const val TAG = "BackupCardSdkMiUtil"
15
+
16
+ @IntDef(
17
+ value =
18
+ [
19
+ PermissionResult.PERMISSION_GRANTED,
20
+ PermissionResult.PERMISSION_DENIED,
21
+ PermissionResult.PERMISSION_ASK,
22
+ PermissionResult.PERMISSION_UNKNOWN,
23
+ ]
24
+ )
25
+ @Retention(AnnotationRetention.SOURCE)
26
+ annotation class PermissionResult {
27
+ companion object {
28
+ const val PERMISSION_GRANTED = 0
29
+ const val PERMISSION_DENIED = -1
30
+ const val PERMISSION_ASK = 1
31
+ const val PERMISSION_UNKNOWN = 2
32
+ }
33
+ }
34
+
35
+ @PermissionResult
36
+ @RequiresApi(Build.VERSION_CODES.KITKAT)
37
+ fun checkNfcPermission(context: Context): Int {
38
+ try {
39
+ val appOps = context.getSystemService(Context.APP_OPS_SERVICE) as AppOpsManager
40
+ val pkg = context.applicationContext.packageName
41
+ val uid = context.applicationInfo.uid
42
+ val appOpsClass = Class.forName(AppOpsManager::class.java.name)
43
+ val checkOpNoThrowMethod =
44
+ appOpsClass.getDeclaredMethod(
45
+ "checkOpNoThrow",
46
+ Integer.TYPE,
47
+ Integer.TYPE,
48
+ String::class.java,
49
+ )
50
+ val invoke = checkOpNoThrowMethod.invoke(appOps, 10016, uid, pkg) ?: return PermissionResult.PERMISSION_UNKNOWN
51
+ return when (invoke.toString()) {
52
+ "0" -> PermissionResult.PERMISSION_GRANTED
53
+ "1" -> PermissionResult.PERMISSION_DENIED
54
+ "5" -> PermissionResult.PERMISSION_ASK
55
+ else -> PermissionResult.PERMISSION_UNKNOWN
56
+ }
57
+ } catch (e: Exception) {
58
+ Log.d(TAG, "check nfc permission fail: ${e.message}")
59
+ }
60
+ return PermissionResult.PERMISSION_UNKNOWN
61
+ }
62
+
63
+ fun intentToAppSetting(context: Context): Boolean {
64
+ val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
65
+ intent.data = Uri.fromParts("package", context.packageName, null)
66
+ return try {
67
+ context.startActivity(intent)
68
+ true
69
+ } catch (e: Exception) {
70
+ Log.d(TAG, "open app setting fail: ${e.message}")
71
+ false
72
+ }
73
+ }
74
+ }
@@ -0,0 +1,23 @@
1
+ package com.ziancube.reactnativebackupcardsdk.utils
2
+
3
+ import android.app.Activity
4
+ import android.os.Build
5
+
6
+ object NfcPermissionUtils {
7
+ inline fun checkPermission(activity: Activity, doNext: () -> Unit): Int {
8
+ return if ("xiaomi".equals(Build.MANUFACTURER, ignoreCase = true)) {
9
+ checkMiuiPermission(activity, doNext)
10
+ } else {
11
+ doNext.invoke()
12
+ 0
13
+ }
14
+ }
15
+
16
+ inline fun checkMiuiPermission(activity: Activity, doNext: () -> Unit): Int {
17
+ when (MiUtil.checkNfcPermission(activity)) {
18
+ MiUtil.PermissionResult.PERMISSION_GRANTED -> doNext.invoke()
19
+ else -> {}
20
+ }
21
+ return MiUtil.checkNfcPermission(activity)
22
+ }
23
+ }
@@ -1,5 +1,8 @@
1
1
  "use strict";
2
2
 
3
3
  import { TurboModuleRegistry } from 'react-native';
4
+
5
+ /** App-layer result type (same pattern as react-native-lite-card PromiseResult). */
6
+
4
7
  export default TurboModuleRegistry.getEnforcing('BackupCardSdk');
5
8
  //# sourceMappingURL=NativeBackupCardSdk.js.map
@@ -1 +1 @@
1
- {"version":3,"names":["TurboModuleRegistry","getEnforcing"],"sourceRoot":"../../src","sources":["NativeBackupCardSdk.ts"],"mappings":";;AAAA,SACEA,mBAAmB,QAGd,cAAc;AAgCrB,eAAeA,mBAAmB,CAACC,YAAY,CAAO,eAAe,CAAC","ignoreList":[]}
1
+ {"version":3,"names":["TurboModuleRegistry","getEnforcing"],"sourceRoot":"../../src","sources":["NativeBackupCardSdk.ts"],"mappings":";;AAAA,SACEA,mBAAmB,QAGd,cAAc;;AAWrB;;AA+EA,eAAeA,mBAAmB,CAACC,YAAY,CAAO,eAAe,CAAC","ignoreList":[]}
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+
3
+ import BackupCardSdk from "./NativeBackupCardSdk.js";
4
+ function withoutData(result) {
5
+ return {
6
+ error: result.error,
7
+ cardInfo: result.cardInfo,
8
+ resultCode: result.resultCode,
9
+ data: null
10
+ };
11
+ }
12
+ export async function activateCard(pwd, serialNumber) {
13
+ return withoutData(await BackupCardSdk.activateCard(pwd, serialNumber));
14
+ }
15
+ export async function checkSlotEmpty(slotId, pwd) {
16
+ return withoutData(await BackupCardSdk.checkSlotEmpty(slotId, pwd));
17
+ }
18
+ export async function writeSlot(slotIndex, data, pwd) {
19
+ return withoutData(await BackupCardSdk.writeSlot(slotIndex, data, pwd));
20
+ }
21
+ export async function readSlot(slotIndex, pwd) {
22
+ return BackupCardSdk.readSlot(slotIndex, pwd);
23
+ }
24
+ export async function deleteSlot(slotIndex, pwd) {
25
+ return withoutData(await BackupCardSdk.deleteSlot(slotIndex, pwd));
26
+ }
27
+ //# sourceMappingURL=cardOperations.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["BackupCardSdk","withoutData","result","error","cardInfo","resultCode","data","activateCard","pwd","serialNumber","checkSlotEmpty","slotId","writeSlot","slotIndex","readSlot","deleteSlot"],"sourceRoot":"../../src","sources":["cardOperations.ts"],"mappings":";;AAAA,OAAOA,aAAa,MAAM,0BAAuB;AAejD,SAASC,WAAWA,CAClBC,MAAiC,EACN;EAC3B,OAAO;IACLC,KAAK,EAAED,MAAM,CAACC,KAAK;IACnBC,QAAQ,EAAEF,MAAM,CAACE,QAAQ;IACzBC,UAAU,EAAEH,MAAM,CAACG,UAAU;IAC7BC,IAAI,EAAE;EACR,CAAC;AACH;AAEA,OAAO,eAAeC,YAAYA,CAChCC,GAAW,EACXC,YAAoB,EACgB;EACpC,OAAOR,WAAW,CAAC,MAAMD,aAAa,CAACO,YAAY,CAACC,GAAG,EAAEC,YAAY,CAAC,CAAC;AACzE;AAEA,OAAO,eAAeC,cAAcA,CAClCC,MAAc,EACdH,GAAW,EACyB;EACpC,OAAOP,WAAW,CAAC,MAAMD,aAAa,CAACU,cAAc,CAACC,MAAM,EAAEH,GAAG,CAAC,CAAC;AACrE;AAEA,OAAO,eAAeI,SAASA,CAC7BC,SAAiB,EACjBP,IAAmB,EACnBE,GAAW,EACyB;EACpC,OAAOP,WAAW,CAAC,MAAMD,aAAa,CAACY,SAAS,CAACC,SAAS,EAAEP,IAAI,EAAEE,GAAG,CAAC,CAAC;AACzE;AAEA,OAAO,eAAeM,QAAQA,CAC5BD,SAAiB,EACjBL,GAAW,EAC2B;EACtC,OAAOR,aAAa,CAACc,QAAQ,CAACD,SAAS,EAAEL,GAAG,CAAC;AAC/C;AAEA,OAAO,eAAeO,UAAUA,CAC9BF,SAAiB,EACjBL,GAAW,EACyB;EACpC,OAAOP,WAAW,CAAC,MAAMD,aAAa,CAACe,UAAU,CAACF,SAAS,EAAEL,GAAG,CAAC,CAAC;AACpE","ignoreList":[]}
@@ -1,5 +1,7 @@
1
1
  "use strict";
2
2
 
3
3
  import BackupCardSdk from "./NativeBackupCardSdk.js";
4
+ export { CardErrors, cancelNfcWait, checkNFCPermission, intoSetting } from "./nfc.js";
5
+ export { activateCard, checkSlotEmpty, deleteSlot, readSlot, writeSlot } from "./cardOperations.js";
4
6
  export default BackupCardSdk;
5
7
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"names":["BackupCardSdk"],"sourceRoot":"../../src","sources":["index.tsx"],"mappings":";;AAAA,OAAOA,aAAa,MAAM,0BAAuB;AAGjD,eAAeA,aAAa","ignoreList":[]}
1
+ {"version":3,"names":["BackupCardSdk","CardErrors","cancelNfcWait","checkNFCPermission","intoSetting","activateCard","checkSlotEmpty","deleteSlot","readSlot","writeSlot"],"sourceRoot":"../../src","sources":["index.tsx"],"mappings":";;AAAA,OAAOA,aAAa,MAAM,0BAAuB;AASjD,SACEC,UAAU,EACVC,aAAa,EACbC,kBAAkB,EAClBC,WAAW,QACN,UAAO;AACd,SACEC,YAAY,EACZC,cAAc,EACdC,UAAU,EACVC,QAAQ,EACRC,SAAS,QACJ,qBAAkB;AAEzB,eAAeT,aAAa","ignoreList":[]}
@@ -0,0 +1,75 @@
1
+ "use strict";
2
+
3
+ import { Platform } from 'react-native';
4
+ import BackupCardSdk from "./NativeBackupCardSdk.js";
5
+ /** Same error codes as @digitalshieldfe/react-native-lite-card for NFC checks. */
6
+ export let CardErrors = /*#__PURE__*/function (CardErrors) {
7
+ CardErrors[CardErrors["InitChannel"] = 1000] = "InitChannel";
8
+ CardErrors[CardErrors["NotExistsNFC"] = 1001] = "NotExistsNFC";
9
+ CardErrors[CardErrors["NotEnableNFC"] = 1002] = "NotEnableNFC";
10
+ CardErrors[CardErrors["NotNFCPermission"] = 1003] = "NotNFCPermission";
11
+ CardErrors[CardErrors["ConnectionFail"] = 2001] = "ConnectionFail";
12
+ CardErrors[CardErrors["NotSameNFCLite"] = 2002] = "NotSameNFCLite";
13
+ CardErrors[CardErrors["ActivateCardFailed"] = 2003] = "ActivateCardFailed";
14
+ CardErrors[CardErrors["NotSupportedCard"] = 2004] = "NotSupportedCard";
15
+ CardErrors[CardErrors["PasswordWrong"] = 2005] = "PasswordWrong";
16
+ CardErrors[CardErrors["NotSetPassword"] = 2006] = "NotSetPassword";
17
+ CardErrors[CardErrors["CardLock"] = 2007] = "CardLock";
18
+ CardErrors[CardErrors["NotInitializedError"] = 2008] = "NotInitializedError";
19
+ CardErrors[CardErrors["InitializedError"] = 4001] = "InitializedError";
20
+ return CardErrors;
21
+ }({});
22
+ function parseTurboModuleError(error) {
23
+ const err = error;
24
+ const code = err?.userInfo?.code;
25
+ if (typeof code === 'number') {
26
+ return {
27
+ code,
28
+ message: err.userInfo?.message ?? err.message ?? null
29
+ };
30
+ }
31
+ return {
32
+ code: CardErrors.InitChannel,
33
+ message: err?.message ?? null
34
+ };
35
+ }
36
+
37
+ /** Android only for now; iOS will be added later. */
38
+ export function checkNFCPermission() {
39
+ if (Platform.OS !== 'android') {
40
+ return Promise.resolve({
41
+ error: {
42
+ code: CardErrors.InitChannel,
43
+ message: 'checkNFCPermission is not implemented on iOS yet'
44
+ },
45
+ data: null,
46
+ cardInfo: null,
47
+ resultCode: -1
48
+ });
49
+ }
50
+ return BackupCardSdk.checkNFCPermission().then(() => ({
51
+ error: null,
52
+ data: true,
53
+ cardInfo: null,
54
+ resultCode: 0
55
+ })).catch(error => ({
56
+ error: parseTurboModuleError(error),
57
+ data: null,
58
+ cardInfo: null,
59
+ resultCode: -1
60
+ }));
61
+ }
62
+
63
+ /** Android only for now; iOS will be added later. */
64
+ export function intoSetting() {
65
+ if (Platform.OS !== 'android') {
66
+ return;
67
+ }
68
+ BackupCardSdk.intoSetting();
69
+ }
70
+
71
+ /** Call when user dismisses the "tap card" UI to stop waiting. Android only. */
72
+ export function cancelNfcWait() {
73
+ BackupCardSdk.cancelNfcWait();
74
+ }
75
+ //# sourceMappingURL=nfc.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["Platform","BackupCardSdk","CardErrors","parseTurboModuleError","error","err","code","userInfo","message","InitChannel","checkNFCPermission","OS","Promise","resolve","data","cardInfo","resultCode","then","catch","intoSetting","cancelNfcWait"],"sourceRoot":"../../src","sources":["nfc.ts"],"mappings":";;AAAA,SAASA,QAAQ,QAAQ,cAAc;AAEvC,OAAOC,aAAa,MAAM,0BAAuB;AAMjD;AACA,WAAYC,UAAU,0BAAVA,UAAU;EAAVA,UAAU,CAAVA,UAAU;EAAVA,UAAU,CAAVA,UAAU;EAAVA,UAAU,CAAVA,UAAU;EAAVA,UAAU,CAAVA,UAAU;EAAVA,UAAU,CAAVA,UAAU;EAAVA,UAAU,CAAVA,UAAU;EAAVA,UAAU,CAAVA,UAAU;EAAVA,UAAU,CAAVA,UAAU;EAAVA,UAAU,CAAVA,UAAU;EAAVA,UAAU,CAAVA,UAAU;EAAVA,UAAU,CAAVA,UAAU;EAAVA,UAAU,CAAVA,UAAU;EAAVA,UAAU,CAAVA,UAAU;EAAA,OAAVA,UAAU;AAAA;AAkBtB,SAASC,qBAAqBA,CAACC,KAAc,EAAiB;EAC5D,MAAMC,GAAG,GAAGD,KAGX;EACD,MAAME,IAAI,GAAGD,GAAG,EAAEE,QAAQ,EAAED,IAAI;EAChC,IAAI,OAAOA,IAAI,KAAK,QAAQ,EAAE;IAC5B,OAAO;MAAEA,IAAI;MAAEE,OAAO,EAAEH,GAAG,CAACE,QAAQ,EAAEC,OAAO,IAAIH,GAAG,CAACG,OAAO,IAAI;IAAK,CAAC;EACxE;EACA,OAAO;IAAEF,IAAI,EAAEJ,UAAU,CAACO,WAAW;IAAED,OAAO,EAAEH,GAAG,EAAEG,OAAO,IAAI;EAAK,CAAC;AACxE;;AAEA;AACA,OAAO,SAASE,kBAAkBA,CAAA,EAAoC;EACpE,IAAIV,QAAQ,CAACW,EAAE,KAAK,SAAS,EAAE;IAC7B,OAAOC,OAAO,CAACC,OAAO,CAAC;MACrBT,KAAK,EAAE;QACLE,IAAI,EAAEJ,UAAU,CAACO,WAAW;QAC5BD,OAAO,EAAE;MACX,CAAC;MACDM,IAAI,EAAE,IAAI;MACVC,QAAQ,EAAE,IAAI;MACdC,UAAU,EAAE,CAAC;IACf,CAAC,CAAC;EACJ;EACA,OAAOf,aAAa,CAACS,kBAAkB,CAAC,CAAC,CACtCO,IAAI,CAAC,OAAO;IAAEb,KAAK,EAAE,IAAI;IAAEU,IAAI,EAAE,IAAI;IAAEC,QAAQ,EAAE,IAAI;IAAEC,UAAU,EAAE;EAAE,CAAC,CAAC,CAAC,CACxEE,KAAK,CAAEd,KAAc,KAAM;IAC1BA,KAAK,EAAED,qBAAqB,CAACC,KAAK,CAAC;IACnCU,IAAI,EAAE,IAAI;IACVC,QAAQ,EAAE,IAAI;IACdC,UAAU,EAAE,CAAC;EACf,CAAC,CAAC,CAAC;AACP;;AAEA;AACA,OAAO,SAASG,WAAWA,CAAA,EAAS;EAClC,IAAInB,QAAQ,CAACW,EAAE,KAAK,SAAS,EAAE;IAC7B;EACF;EACAV,aAAa,CAACkB,WAAW,CAAC,CAAC;AAC7B;;AAEA;AACA,OAAO,SAASC,aAAaA,CAAA,EAAS;EACpCnB,aAAa,CAACmB,aAAa,CAAC,CAAC;AAC/B","ignoreList":[]}
@@ -3,15 +3,61 @@ export type CardInfo = {
3
3
  serialNumber: string | null;
4
4
  pinRetryCount: number | null;
5
5
  isNewCard: boolean | null;
6
+ isBackup: boolean | null;
6
7
  };
8
+ export type CallbackError = {
9
+ code: number;
10
+ message: string | null;
11
+ };
12
+ /** App-layer result type (same pattern as react-native-lite-card PromiseResult). */
13
+ export type PromiseResult<T> = {
14
+ error: CallbackError | null;
15
+ data: T | null;
16
+ cardInfo: CardInfo | null;
17
+ resultCode: number;
18
+ };
19
+ export type CardOperationResult<T> = PromiseResult<T>;
7
20
  export interface Spec extends TurboModule {
21
+ /** Waits for user to tap the backup card (Android), then reads card info. */
8
22
  getCardInfo(): Promise<CardInfo | null>;
23
+ /** Cancels an in-flight wait for NFC tap (Android). */
24
+ cancelNfcWait(): void;
25
+ /** Android: hardware NFC, system switch, MIUI permission. iOS: not implemented yet. */
26
+ checkNFCPermission(): Promise<boolean>;
27
+ /** Android: opens system NFC settings. iOS: not implemented yet. */
28
+ intoSetting(): void;
9
29
  resetCard(): Promise<Boolean>;
10
- activateCard(pwd: string): Promise<Boolean>;
30
+ activateCard(pwd: string, serialNumber: string): Promise<{
31
+ error: CallbackError | null;
32
+ cardInfo: CardInfo | null;
33
+ resultCode: number;
34
+ data: string | null;
35
+ }>;
11
36
  changePin(oldPin: string, newPin: string): Promise<Boolean>;
12
- checkSlotEmpty(slotId: number, pwd: string): Promise<Boolean>;
13
- writeSlot(slotIndex: number, data: Array<number>, pwd: string): Promise<Boolean>;
14
- readSlot(slotIndex: number, pwd: string): Promise<Array<number> | null>;
37
+ checkSlotEmpty(slotId: number, pwd: string): Promise<{
38
+ error: CallbackError | null;
39
+ cardInfo: CardInfo | null;
40
+ resultCode: number;
41
+ data: string | null;
42
+ }>;
43
+ writeSlot(slotIndex: number, data: Array<number>, pwd: string): Promise<{
44
+ error: CallbackError | null;
45
+ cardInfo: CardInfo | null;
46
+ resultCode: number;
47
+ data: string | null;
48
+ }>;
49
+ readSlot(slotIndex: number, pwd: string): Promise<{
50
+ error: CallbackError | null;
51
+ cardInfo: CardInfo | null;
52
+ resultCode: number;
53
+ data: string | null;
54
+ }>;
55
+ deleteSlot(slotIndex: number, pwd: string): Promise<{
56
+ error: CallbackError | null;
57
+ cardInfo: CardInfo | null;
58
+ resultCode: number;
59
+ data: string | null;
60
+ }>;
15
61
  readonly onApduLog: CodegenTypes.EventEmitter<{
16
62
  message: string;
17
63
  isSent: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"NativeBackupCardSdk.d.ts","sourceRoot":"","sources":["../../../src/NativeBackupCardSdk.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,WAAW,EAChB,KAAK,YAAY,EAClB,MAAM,cAAc,CAAC;AAEtB,MAAM,MAAM,QAAQ,GAAG;IACrB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,SAAS,EAAE,OAAO,GAAG,IAAI,CAAC;CAC3B,CAAC;AAEF,MAAM,WAAW,IAAK,SAAQ,WAAW;IACvC,WAAW,IAAI,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,CAAC;IACxC,SAAS,IAAI,OAAO,CAAC,OAAO,CAAC,CAAC;IAC9B,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAC5C,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAC5D,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAC9D,SAAS,CACP,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,KAAK,CAAC,MAAM,CAAC,EACnB,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,OAAO,CAAC,CAAC;IACpB,QAAQ,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC;IAExE,QAAQ,CAAC,SAAS,EAAE,YAAY,CAAC,YAAY,CAAC;QAC5C,OAAO,EAAE,MAAM,CAAC;QAChB,MAAM,EAAE,OAAO,CAAC;QAChB,SAAS,EAAE,OAAO,CAAC;KACpB,CAAC,CAAC;IAEH,QAAQ,CAAC,UAAU,EAAE,YAAY,CAAC,YAAY,CAAC;QAC7C,YAAY,EAAE,OAAO,CAAC;KACvB,CAAC,CAAC;CACJ;;AAED,wBAAuE"}
1
+ {"version":3,"file":"NativeBackupCardSdk.d.ts","sourceRoot":"","sources":["../../../src/NativeBackupCardSdk.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ import type { CardOperationResult } from './NativeBackupCardSdk';
2
+ export declare function activateCard(pwd: string, serialNumber: string): Promise<CardOperationResult<null>>;
3
+ export declare function checkSlotEmpty(slotId: number, pwd: string): Promise<CardOperationResult<null>>;
4
+ export declare function writeSlot(slotIndex: number, data: Array<number>, pwd: string): Promise<CardOperationResult<null>>;
5
+ export declare function readSlot(slotIndex: number, pwd: string): Promise<CardOperationResult<string>>;
6
+ export declare function deleteSlot(slotIndex: number, pwd: string): Promise<CardOperationResult<null>>;
7
+ //# sourceMappingURL=cardOperations.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cardOperations.d.ts","sourceRoot":"","sources":["../../../src/cardOperations.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAGV,mBAAmB,EACpB,MAAM,uBAAuB,CAAC;AAoB/B,wBAAsB,YAAY,CAChC,GAAG,EAAE,MAAM,EACX,YAAY,EAAE,MAAM,GACnB,OAAO,CAAC,mBAAmB,CAAC,IAAI,CAAC,CAAC,CAEpC;AAED,wBAAsB,cAAc,CAClC,MAAM,EAAE,MAAM,EACd,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,mBAAmB,CAAC,IAAI,CAAC,CAAC,CAEpC;AAED,wBAAsB,SAAS,CAC7B,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,KAAK,CAAC,MAAM,CAAC,EACnB,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,mBAAmB,CAAC,IAAI,CAAC,CAAC,CAEpC;AAED,wBAAsB,QAAQ,CAC5B,SAAS,EAAE,MAAM,EACjB,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,mBAAmB,CAAC,MAAM,CAAC,CAAC,CAEtC;AAED,wBAAsB,UAAU,CAC9B,SAAS,EAAE,MAAM,EACjB,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,mBAAmB,CAAC,IAAI,CAAC,CAAC,CAEpC"}
@@ -1,5 +1,8 @@
1
1
  import BackupCardSdk from './NativeBackupCardSdk';
2
- import type { CardInfo } from './NativeBackupCardSdk';
3
- export type { CardInfo };
2
+ import type { CardInfo, CardOperationResult, PromiseResult } from './NativeBackupCardSdk';
3
+ export type { CardInfo, CardOperationResult, PromiseResult };
4
+ export type { CallbackError } from './nfc';
5
+ export { CardErrors, cancelNfcWait, checkNFCPermission, intoSetting, } from './nfc';
6
+ export { activateCard, checkSlotEmpty, deleteSlot, readSlot, writeSlot, } from './cardOperations';
4
7
  export default BackupCardSdk;
5
8
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.tsx"],"names":[],"mappings":"AAAA,OAAO,aAAa,MAAM,uBAAuB,CAAC;AAClD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AACtD,YAAY,EAAE,QAAQ,EAAE,CAAC;AACzB,eAAe,aAAa,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.tsx"],"names":[],"mappings":"AAAA,OAAO,aAAa,MAAM,uBAAuB,CAAC;AAClD,OAAO,KAAK,EACV,QAAQ,EACR,mBAAmB,EACnB,aAAa,EACd,MAAM,uBAAuB,CAAC;AAE/B,YAAY,EAAE,QAAQ,EAAE,mBAAmB,EAAE,aAAa,EAAE,CAAC;AAC7D,YAAY,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AAC3C,OAAO,EACL,UAAU,EACV,aAAa,EACb,kBAAkB,EAClB,WAAW,GACZ,MAAM,OAAO,CAAC;AACf,OAAO,EACL,YAAY,EACZ,cAAc,EACd,UAAU,EACV,QAAQ,EACR,SAAS,GACV,MAAM,kBAAkB,CAAC;AAE1B,eAAe,aAAa,CAAC"}
@@ -0,0 +1,28 @@
1
+ import type { PromiseResult } from './NativeBackupCardSdk';
2
+ export type CallbackError = {
3
+ code: number;
4
+ message: string | null;
5
+ } | null;
6
+ /** Same error codes as @digitalshieldfe/react-native-lite-card for NFC checks. */
7
+ export declare enum CardErrors {
8
+ InitChannel = 1000,
9
+ NotExistsNFC = 1001,
10
+ NotEnableNFC = 1002,
11
+ NotNFCPermission = 1003,
12
+ ConnectionFail = 2001,
13
+ NotSameNFCLite = 2002,
14
+ ActivateCardFailed = 2003,
15
+ NotSupportedCard = 2004,
16
+ PasswordWrong = 2005,
17
+ NotSetPassword = 2006,
18
+ CardLock = 2007,
19
+ NotInitializedError = 2008,
20
+ InitializedError = 4001
21
+ }
22
+ /** Android only for now; iOS will be added later. */
23
+ export declare function checkNFCPermission(): Promise<PromiseResult<boolean>>;
24
+ /** Android only for now; iOS will be added later. */
25
+ export declare function intoSetting(): void;
26
+ /** Call when user dismisses the "tap card" UI to stop waiting. Android only. */
27
+ export declare function cancelNfcWait(): void;
28
+ //# sourceMappingURL=nfc.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"nfc.d.ts","sourceRoot":"","sources":["../../../src/nfc.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAE3D,MAAM,MAAM,aAAa,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,GAAG,IAAI,CAAC;AAE5E,kFAAkF;AAClF,oBAAY,UAAU;IACpB,WAAW,OAAO;IAClB,YAAY,OAAO;IACnB,YAAY,OAAO;IACnB,gBAAgB,OAAO;IAEvB,cAAc,OAAO;IACrB,cAAc,OAAO;IACrB,kBAAkB,OAAO;IACzB,gBAAgB,OAAO;IACvB,aAAa,OAAO;IACpB,cAAc,OAAO;IACrB,QAAQ,OAAO;IACf,mBAAmB,OAAO;IAE1B,gBAAgB,OAAO;CACxB;AAcD,qDAAqD;AACrD,wBAAgB,kBAAkB,IAAI,OAAO,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,CAoBpE;AAED,qDAAqD;AACrD,wBAAgB,WAAW,IAAI,IAAI,CAKlC;AAED,gFAAgF;AAChF,wBAAgB,aAAa,IAAI,IAAI,CAEpC"}
package/package.json CHANGED
@@ -1,13 +1,13 @@
1
1
  {
2
2
  "name": "@digitalshieldfe/react-native-backup-card-sdk",
3
- "version": "0.1.5",
3
+ "version": "0.1.6",
4
4
  "description": "ds react-native backup-card sdk",
5
5
  "main": "./lib/module/index.js",
6
6
  "types": "./lib/typescript/src/index.d.ts",
7
7
  "exports": {
8
8
  ".": {
9
- "source": "./src/index.tsx",
10
9
  "types": "./lib/typescript/src/index.d.ts",
10
+ "react-native": "./src/index.tsx",
11
11
  "default": "./lib/module/index.js"
12
12
  },
13
13
  "./package.json": "./package.json"
@@ -8,20 +8,78 @@ export type CardInfo = {
8
8
  serialNumber: string | null;
9
9
  pinRetryCount: number | null;
10
10
  isNewCard: boolean | null;
11
+ isBackup: boolean | null;
11
12
  };
12
13
 
14
+ export type CallbackError = { code: number; message: string | null };
15
+
16
+ /** App-layer result type (same pattern as react-native-lite-card PromiseResult). */
17
+ export type PromiseResult<T> = {
18
+ error: CallbackError | null;
19
+ data: T | null;
20
+ cardInfo: CardInfo | null;
21
+ resultCode: number;
22
+ };
23
+
24
+ export type CardOperationResult<T> = PromiseResult<T>;
25
+
13
26
  export interface Spec extends TurboModule {
27
+ /** Waits for user to tap the backup card (Android), then reads card info. */
14
28
  getCardInfo(): Promise<CardInfo | null>;
29
+ /** Cancels an in-flight wait for NFC tap (Android). */
30
+ cancelNfcWait(): void;
31
+ /** Android: hardware NFC, system switch, MIUI permission. iOS: not implemented yet. */
32
+ checkNFCPermission(): Promise<boolean>;
33
+ /** Android: opens system NFC settings. iOS: not implemented yet. */
34
+ intoSetting(): void;
15
35
  resetCard(): Promise<Boolean>;
16
- activateCard(pwd: string): Promise<Boolean>;
36
+ activateCard(
37
+ pwd: string,
38
+ serialNumber: string
39
+ ): Promise<{
40
+ error: CallbackError | null;
41
+ cardInfo: CardInfo | null;
42
+ resultCode: number;
43
+ data: string | null;
44
+ }>;
17
45
  changePin(oldPin: string, newPin: string): Promise<Boolean>;
18
- checkSlotEmpty(slotId: number, pwd: string): Promise<Boolean>;
46
+ checkSlotEmpty(
47
+ slotId: number,
48
+ pwd: string
49
+ ): Promise<{
50
+ error: CallbackError | null;
51
+ cardInfo: CardInfo | null;
52
+ resultCode: number;
53
+ data: string | null;
54
+ }>;
19
55
  writeSlot(
20
56
  slotIndex: number,
21
57
  data: Array<number>,
22
58
  pwd: string
23
- ): Promise<Boolean>;
24
- readSlot(slotIndex: number, pwd: string): Promise<Array<number> | null>;
59
+ ): Promise<{
60
+ error: CallbackError | null;
61
+ cardInfo: CardInfo | null;
62
+ resultCode: number;
63
+ data: string | null;
64
+ }>;
65
+ readSlot(
66
+ slotIndex: number,
67
+ pwd: string
68
+ ): Promise<{
69
+ error: CallbackError | null;
70
+ cardInfo: CardInfo | null;
71
+ resultCode: number;
72
+ data: string | null;
73
+ }>;
74
+ deleteSlot(
75
+ slotIndex: number,
76
+ pwd: string
77
+ ): Promise<{
78
+ error: CallbackError | null;
79
+ cardInfo: CardInfo | null;
80
+ resultCode: number;
81
+ data: string | null;
82
+ }>;
25
83
 
26
84
  readonly onApduLog: CodegenTypes.EventEmitter<{
27
85
  message: string;
@@ -0,0 +1,61 @@
1
+ import BackupCardSdk from './NativeBackupCardSdk';
2
+
3
+ import type {
4
+ CallbackError,
5
+ CardInfo,
6
+ CardOperationResult,
7
+ } from './NativeBackupCardSdk';
8
+
9
+ type NativeCardOperationResult = {
10
+ error: CallbackError | null;
11
+ cardInfo: CardInfo | null;
12
+ resultCode: number;
13
+ data: string | null;
14
+ };
15
+
16
+ function withoutData(
17
+ result: NativeCardOperationResult
18
+ ): CardOperationResult<null> {
19
+ return {
20
+ error: result.error,
21
+ cardInfo: result.cardInfo,
22
+ resultCode: result.resultCode,
23
+ data: null,
24
+ };
25
+ }
26
+
27
+ export async function activateCard(
28
+ pwd: string,
29
+ serialNumber: string
30
+ ): Promise<CardOperationResult<null>> {
31
+ return withoutData(await BackupCardSdk.activateCard(pwd, serialNumber));
32
+ }
33
+
34
+ export async function checkSlotEmpty(
35
+ slotId: number,
36
+ pwd: string
37
+ ): Promise<CardOperationResult<null>> {
38
+ return withoutData(await BackupCardSdk.checkSlotEmpty(slotId, pwd));
39
+ }
40
+
41
+ export async function writeSlot(
42
+ slotIndex: number,
43
+ data: Array<number>,
44
+ pwd: string
45
+ ): Promise<CardOperationResult<null>> {
46
+ return withoutData(await BackupCardSdk.writeSlot(slotIndex, data, pwd));
47
+ }
48
+
49
+ export async function readSlot(
50
+ slotIndex: number,
51
+ pwd: string
52
+ ): Promise<CardOperationResult<string>> {
53
+ return BackupCardSdk.readSlot(slotIndex, pwd);
54
+ }
55
+
56
+ export async function deleteSlot(
57
+ slotIndex: number,
58
+ pwd: string
59
+ ): Promise<CardOperationResult<null>> {
60
+ return withoutData(await BackupCardSdk.deleteSlot(slotIndex, pwd));
61
+ }
package/src/index.tsx CHANGED
@@ -1,4 +1,24 @@
1
1
  import BackupCardSdk from './NativeBackupCardSdk';
2
- import type { CardInfo } from './NativeBackupCardSdk';
3
- export type { CardInfo };
2
+ import type {
3
+ CardInfo,
4
+ CardOperationResult,
5
+ PromiseResult,
6
+ } from './NativeBackupCardSdk';
7
+
8
+ export type { CardInfo, CardOperationResult, PromiseResult };
9
+ export type { CallbackError } from './nfc';
10
+ export {
11
+ CardErrors,
12
+ cancelNfcWait,
13
+ checkNFCPermission,
14
+ intoSetting,
15
+ } from './nfc';
16
+ export {
17
+ activateCard,
18
+ checkSlotEmpty,
19
+ deleteSlot,
20
+ readSlot,
21
+ writeSlot,
22
+ } from './cardOperations';
23
+
4
24
  export default BackupCardSdk;
package/src/nfc.ts ADDED
@@ -0,0 +1,74 @@
1
+ import { Platform } from 'react-native';
2
+
3
+ import BackupCardSdk from './NativeBackupCardSdk';
4
+
5
+ import type { PromiseResult } from './NativeBackupCardSdk';
6
+
7
+ export type CallbackError = { code: number; message: string | null } | null;
8
+
9
+ /** Same error codes as @digitalshieldfe/react-native-lite-card for NFC checks. */
10
+ export enum CardErrors {
11
+ InitChannel = 1000,
12
+ NotExistsNFC = 1001,
13
+ NotEnableNFC = 1002,
14
+ NotNFCPermission = 1003,
15
+
16
+ ConnectionFail = 2001,
17
+ NotSameNFCLite = 2002,
18
+ ActivateCardFailed = 2003,
19
+ NotSupportedCard = 2004,
20
+ PasswordWrong = 2005,
21
+ NotSetPassword = 2006,
22
+ CardLock = 2007,
23
+ NotInitializedError = 2008,
24
+
25
+ InitializedError = 4001,
26
+ }
27
+
28
+ function parseTurboModuleError(error: unknown): CallbackError {
29
+ const err = error as {
30
+ message?: string;
31
+ userInfo?: { code?: number; message?: string };
32
+ };
33
+ const code = err?.userInfo?.code;
34
+ if (typeof code === 'number') {
35
+ return { code, message: err.userInfo?.message ?? err.message ?? null };
36
+ }
37
+ return { code: CardErrors.InitChannel, message: err?.message ?? null };
38
+ }
39
+
40
+ /** Android only for now; iOS will be added later. */
41
+ export function checkNFCPermission(): Promise<PromiseResult<boolean>> {
42
+ if (Platform.OS !== 'android') {
43
+ return Promise.resolve({
44
+ error: {
45
+ code: CardErrors.InitChannel,
46
+ message: 'checkNFCPermission is not implemented on iOS yet',
47
+ },
48
+ data: null,
49
+ cardInfo: null,
50
+ resultCode: -1,
51
+ });
52
+ }
53
+ return BackupCardSdk.checkNFCPermission()
54
+ .then(() => ({ error: null, data: true, cardInfo: null, resultCode: 0 }))
55
+ .catch((error: unknown) => ({
56
+ error: parseTurboModuleError(error),
57
+ data: null,
58
+ cardInfo: null,
59
+ resultCode: -1,
60
+ }));
61
+ }
62
+
63
+ /** Android only for now; iOS will be added later. */
64
+ export function intoSetting(): void {
65
+ if (Platform.OS !== 'android') {
66
+ return;
67
+ }
68
+ BackupCardSdk.intoSetting();
69
+ }
70
+
71
+ /** Call when user dismisses the "tap card" UI to stop waiting. Android only. */
72
+ export function cancelNfcWait(): void {
73
+ BackupCardSdk.cancelNfcWait();
74
+ }