@digitalshieldfe/react-native-backup-card-sdk 0.1.4 → 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 (115) hide show
  1. package/android/build.gradle +33 -49
  2. package/android/libs/backupcardsdk.aar +0 -0
  3. package/android/src/main/AndroidManifest.xml +1 -4
  4. package/android/src/main/java/com/ziancube/reactnativebackupcardsdk/BackupCardSdkModule.kt +244 -74
  5. package/android/src/main/java/com/ziancube/reactnativebackupcardsdk/BackupCardSdkPackage.kt +1 -1
  6. package/android/src/main/java/com/ziancube/reactnativebackupcardsdk/nfc/NfcExceptions.kt +11 -0
  7. package/android/src/main/java/com/ziancube/reactnativebackupcardsdk/nfc/NfcUtils.kt +30 -0
  8. package/android/src/main/java/com/ziancube/reactnativebackupcardsdk/utils/MiUtil.kt +74 -0
  9. package/android/src/main/java/com/ziancube/reactnativebackupcardsdk/utils/NfcPermissionUtils.kt +23 -0
  10. package/lib/module/NativeBackupCardSdk.js +3 -0
  11. package/lib/module/NativeBackupCardSdk.js.map +1 -1
  12. package/lib/module/cardOperations.js +27 -0
  13. package/lib/module/cardOperations.js.map +1 -0
  14. package/lib/module/index.js +2 -0
  15. package/lib/module/index.js.map +1 -1
  16. package/lib/module/nfc.js +75 -0
  17. package/lib/module/nfc.js.map +1 -0
  18. package/lib/typescript/src/NativeBackupCardSdk.d.ts +50 -4
  19. package/lib/typescript/src/NativeBackupCardSdk.d.ts.map +1 -1
  20. package/lib/typescript/src/cardOperations.d.ts +7 -0
  21. package/lib/typescript/src/cardOperations.d.ts.map +1 -0
  22. package/lib/typescript/src/index.d.ts +5 -2
  23. package/lib/typescript/src/index.d.ts.map +1 -1
  24. package/lib/typescript/src/nfc.d.ts +28 -0
  25. package/lib/typescript/src/nfc.d.ts.map +1 -0
  26. package/package.json +7 -5
  27. package/src/NativeBackupCardSdk.ts +62 -4
  28. package/src/cardOperations.ts +61 -0
  29. package/src/index.tsx +22 -2
  30. package/src/nfc.ts +74 -0
  31. package/android/consumer-rules.pro +0 -0
  32. package/android/proguard-rules.pro +0 -21
  33. package/android/src/main/java/com/ziancube/backupcardsdk/BackupCardSdk.kt +0 -478
  34. package/android/src/main/java/com/ziancube/backupcardsdk/GPChannelNatives.java +0 -41
  35. package/android/src/main/java/com/ziancube/backupcardsdk/listener/ApiAsyncListener.java +0 -13
  36. package/android/src/main/java/com/ziancube/backupcardsdk/nfc/ApiNfc.java +0 -173
  37. package/android/src/main/java/com/ziancube/backupcardsdk/nfc/ImplNfc.java +0 -39
  38. package/android/src/main/java/com/ziancube/backupcardsdk/nfc/NfcComm.java +0 -115
  39. package/android/src/main/java/com/ziancube/backupcardsdk/utils/ApduParam.java +0 -67
  40. package/android/src/main/java/com/ziancube/backupcardsdk/utils/CommList.java +0 -41
  41. package/android/src/main/java/com/ziancube/backupcardsdk/utils/Utils.java +0 -109
  42. package/android/src/main/jni/CMakeLists.txt +0 -60
  43. package/android/src/main/jni/GPChannel/include/GPChannelSDK.h +0 -306
  44. package/android/src/main/jni/GPChannel/include/context/BaseContext.h +0 -56
  45. package/android/src/main/jni/GPChannel/include/device/ApduBuilder.hpp +0 -72
  46. package/android/src/main/jni/GPChannel/include/utility/Apdu.hpp +0 -166
  47. package/android/src/main/jni/GPChannel/include/utility/Debug.hpp +0 -59
  48. package/android/src/main/jni/GPChannel/include/utility/Singleton.h +0 -34
  49. package/android/src/main/jni/GPChannel/include/utility/mutex.h +0 -24
  50. package/android/src/main/jni/GPChannel/include/utility/trim.hpp +0 -155
  51. package/android/src/main/jni/GPChannel/include/utility/util.h +0 -104
  52. package/android/src/main/jni/GPChannel/include/utility/xFactory.hpp +0 -26
  53. package/android/src/main/jni/GPChannel/include/utility/xManager.hpp +0 -84
  54. package/android/src/main/jni/GPChannel/src/arm64-v8a/libJUB_GPC_APDU_SDK.a +0 -0
  55. package/android/src/main/jni/GPChannel/src/arm64-v8a/libTrezorCrypto.a +0 -0
  56. package/android/src/main/jni/GPChannel/src/armeabi-v7a/libJUB_GPC_APDU_SDK.a +0 -0
  57. package/android/src/main/jni/GPChannel/src/armeabi-v7a/libTrezorCrypto.a +0 -0
  58. package/android/src/main/jni/GPChannel/src/x86/libJUB_GPC_APDU_SDK.a +0 -0
  59. package/android/src/main/jni/GPChannel/src/x86/libTrezorCrypto.a +0 -0
  60. package/android/src/main/jni/src/implJni.cpp +0 -313
  61. package/android/src/main/jni/src/implJni.h +0 -9
  62. package/android/src/main/jni/utils/jsoncpp/AUTHORS +0 -111
  63. package/android/src/main/jni/utils/jsoncpp/CMakeLists.txt +0 -159
  64. package/android/src/main/jni/utils/jsoncpp/LICENSE +0 -55
  65. package/android/src/main/jni/utils/jsoncpp/README.md +0 -135
  66. package/android/src/main/jni/utils/jsoncpp/amalgamate.py +0 -155
  67. package/android/src/main/jni/utils/jsoncpp/appveyor.yml +0 -22
  68. package/android/src/main/jni/utils/jsoncpp/dev.makefile +0 -35
  69. package/android/src/main/jni/utils/jsoncpp/devtools/__init__.py +0 -6
  70. package/android/src/main/jni/utils/jsoncpp/devtools/agent_vmw7.json +0 -33
  71. package/android/src/main/jni/utils/jsoncpp/devtools/agent_vmxp.json +0 -26
  72. package/android/src/main/jni/utils/jsoncpp/devtools/antglob.py +0 -205
  73. package/android/src/main/jni/utils/jsoncpp/devtools/batchbuild.py +0 -278
  74. package/android/src/main/jni/utils/jsoncpp/devtools/fixeol.py +0 -70
  75. package/android/src/main/jni/utils/jsoncpp/devtools/licenseupdater.py +0 -94
  76. package/android/src/main/jni/utils/jsoncpp/devtools/tarball.py +0 -52
  77. package/android/src/main/jni/utils/jsoncpp/doxybuild.py +0 -189
  78. package/android/src/main/jni/utils/jsoncpp/include/CMakeLists.txt +0 -2
  79. package/android/src/main/jni/utils/jsoncpp/include/json/allocator.h +0 -98
  80. package/android/src/main/jni/utils/jsoncpp/include/json/assertions.h +0 -54
  81. package/android/src/main/jni/utils/jsoncpp/include/json/autolink.h +0 -25
  82. package/android/src/main/jni/utils/jsoncpp/include/json/config.h +0 -187
  83. package/android/src/main/jni/utils/jsoncpp/include/json/features.h +0 -61
  84. package/android/src/main/jni/utils/jsoncpp/include/json/forwards.h +0 -37
  85. package/android/src/main/jni/utils/jsoncpp/include/json/json.h +0 -15
  86. package/android/src/main/jni/utils/jsoncpp/include/json/reader.h +0 -411
  87. package/android/src/main/jni/utils/jsoncpp/include/json/value.h +0 -888
  88. package/android/src/main/jni/utils/jsoncpp/include/json/version.h +0 -20
  89. package/android/src/main/jni/utils/jsoncpp/include/json/writer.h +0 -357
  90. package/android/src/main/jni/utils/jsoncpp/makefiles/vs71/jsontest.vcproj +0 -119
  91. package/android/src/main/jni/utils/jsoncpp/makefiles/vs71/lib_json.vcproj +0 -205
  92. package/android/src/main/jni/utils/jsoncpp/makefiles/vs71/test_lib_json.vcproj +0 -130
  93. package/android/src/main/jni/utils/jsoncpp/makerelease.py +0 -390
  94. package/android/src/main/jni/utils/jsoncpp/meson.build +0 -103
  95. package/android/src/main/jni/utils/jsoncpp/pkg-config/jsoncpp.pc.in +0 -9
  96. package/android/src/main/jni/utils/jsoncpp/src/CMakeLists.txt +0 -5
  97. package/android/src/main/jni/utils/jsoncpp/src/jsontestrunner/CMakeLists.txt +0 -25
  98. package/android/src/main/jni/utils/jsoncpp/src/jsontestrunner/main.cpp +0 -333
  99. package/android/src/main/jni/utils/jsoncpp/src/lib_json/CMakeLists.txt +0 -117
  100. package/android/src/main/jni/utils/jsoncpp/src/lib_json/json_reader.cpp +0 -2060
  101. package/android/src/main/jni/utils/jsoncpp/src/lib_json/json_tool.h +0 -114
  102. package/android/src/main/jni/utils/jsoncpp/src/lib_json/json_value.cpp +0 -1661
  103. package/android/src/main/jni/utils/jsoncpp/src/lib_json/json_valueiterator.inl +0 -167
  104. package/android/src/main/jni/utils/jsoncpp/src/lib_json/json_writer.cpp +0 -1233
  105. package/android/src/main/jni/utils/jsoncpp/src/lib_json/version.h.in +0 -20
  106. package/android/src/main/jni/utils/jsoncpp/src/test_lib_json/CMakeLists.txt +0 -38
  107. package/android/src/main/jni/utils/jsoncpp/src/test_lib_json/jsontest.cpp +0 -457
  108. package/android/src/main/jni/utils/jsoncpp/src/test_lib_json/jsontest.h +0 -286
  109. package/android/src/main/jni/utils/jsoncpp/src/test_lib_json/main.cpp +0 -2606
  110. package/android/src/main/jni/utils/jsoncpp/travis.sh +0 -23
  111. package/android/src/main/jni/utils/jsoncpp/version +0 -1
  112. package/android/src/main/jni/utils/jsoncpp/version.in +0 -1
  113. package/android/src/main/jni/utils/logUtils.cpp +0 -108
  114. package/android/src/main/jni/utils/logUtils.h +0 -87
  115. package/android/src/main/jni/utils/mSIGNA/stdutils/uchar_vector.h +0 -614
@@ -15,7 +15,6 @@ buildscript {
15
15
  }
16
16
 
17
17
  repositories {
18
- mavenLocal()
19
18
  google()
20
19
  mavenCentral()
21
20
  }
@@ -33,6 +32,33 @@ apply plugin: "kotlin-android"
33
32
 
34
33
  apply plugin: "com.facebook.react"
35
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
+
36
62
  android {
37
63
  namespace "com.ziancube.reactnativebackupcardsdk"
38
64
 
@@ -41,31 +67,6 @@ android {
41
67
  defaultConfig {
42
68
  minSdkVersion getExtOrDefault("minSdkVersion")
43
69
  targetSdkVersion getExtOrDefault("targetSdkVersion")
44
- testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
45
- consumerProguardFiles "consumer-rules.pro"
46
-
47
- externalNativeBuild {
48
- cmake {
49
- cppFlags(
50
- "",
51
- "-std=c++11",
52
- "-frtti",
53
- "-fexceptions",
54
- "-DHAVE_ENDIAN_H"
55
- )
56
-
57
- arguments(
58
- "-DANDROID_TOOLCHAIN=clang",
59
- "-DANDROID_STL=c++_static",
60
- "-DANDROID_ARM_MODE=arm",
61
- "-DANDROID_PLATFORM=android-19"
62
- )
63
- }
64
- }
65
-
66
- ndk {
67
- abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86'
68
- }
69
70
  }
70
71
 
71
72
  buildFeatures {
@@ -75,10 +76,6 @@ android {
75
76
  buildTypes {
76
77
  release {
77
78
  minifyEnabled false
78
- proguardFiles(
79
- getDefaultProguardFile("proguard-android-optimize.txt"),
80
- "proguard-rules.pro"
81
- )
82
79
  }
83
80
  }
84
81
 
@@ -87,28 +84,15 @@ android {
87
84
  }
88
85
 
89
86
  compileOptions {
90
- sourceCompatibility JavaVersion.VERSION_11
91
- targetCompatibility JavaVersion.VERSION_11
92
- }
93
-
94
- externalNativeBuild {
95
- cmake {
96
- path = file("src/main/jni/CMakeLists.txt")
97
- }
98
- }
99
-
100
- publishing {
101
- singleVariant("release") {
102
- withSourcesJar()
103
- }
87
+ sourceCompatibility JavaVersion.VERSION_1_8
88
+ targetCompatibility JavaVersion.VERSION_1_8
104
89
  }
105
90
  }
106
91
 
107
92
  dependencies {
108
- implementation("androidx.appcompat:appcompat:1.6.1")
109
- implementation("com.google.android.material:material:1.12.0")
93
+ implementation(files("libs/backupcardsdk.aar"))
94
+ // Transitive deps of backupcardsdk (not bundled inside the AAR)
95
+ implementation("androidx.appcompat:appcompat:1.7.1")
96
+ implementation("com.google.android.material:material:1.13.0")
110
97
  implementation("com.facebook.react:react-android")
111
- testImplementation("junit:junit:4.13.2")
112
- androidTestImplementation("androidx.test.ext:junit:1.1.5")
113
- androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1")
114
98
  }
Binary file
@@ -1,5 +1,2 @@
1
- <?xml version="1.0" encoding="utf-8"?>
2
1
  <manifest xmlns:android="http://schemas.android.com/apk/res/android">
3
- <uses-permission android:name="android.permission.NFC" />
4
- <uses-feature android:name="android.hardware.nfc" android:required="false" />
5
- </manifest>
2
+ </manifest>
@@ -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
+ }