@cleanuidev/react-native-scanner 1.0.0-beta.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.
Files changed (52) hide show
  1. package/LICENSE +20 -0
  2. package/README.md +609 -0
  3. package/Scanner.podspec +20 -0
  4. package/android/build.gradle +90 -0
  5. package/android/gradle.properties +5 -0
  6. package/android/src/main/AndroidManifest.xml +8 -0
  7. package/android/src/main/java/com/scanner/CameraInfoModule.kt +253 -0
  8. package/android/src/main/java/com/scanner/ScannerPackage.kt +21 -0
  9. package/android/src/main/java/com/scanner/ScannerView.kt +783 -0
  10. package/android/src/main/java/com/scanner/ScannerViewManager.kt +181 -0
  11. package/android/src/main/java/com/scanner/utils/BarcodeFrameManager.kt +170 -0
  12. package/android/src/main/java/com/scanner/views/BarcodeFrameOverlayView.kt +43 -0
  13. package/android/src/main/java/com/scanner/views/FocusAreaView.kt +124 -0
  14. package/ios/BarcodeDetectionManager.swift +229 -0
  15. package/ios/BarcodeFrameManager.swift +175 -0
  16. package/ios/BarcodeFrameOverlayView.swift +102 -0
  17. package/ios/CameraManager.swift +396 -0
  18. package/ios/CoordinateTransformer.swift +140 -0
  19. package/ios/FocusAreaOverlayView.swift +161 -0
  20. package/ios/Models.swift +341 -0
  21. package/ios/Protocols.swift +194 -0
  22. package/ios/ScannerView.h +14 -0
  23. package/ios/ScannerView.mm +358 -0
  24. package/ios/ScannerViewImpl.swift +580 -0
  25. package/ios/react-native-scanner-Bridging-Header.h +26 -0
  26. package/lib/module/CameraInfoModule.js +8 -0
  27. package/lib/module/CameraInfoModule.js.map +1 -0
  28. package/lib/module/ScannerViewNativeComponent.ts +121 -0
  29. package/lib/module/hooks/useCameraInfo.js +106 -0
  30. package/lib/module/hooks/useCameraInfo.js.map +1 -0
  31. package/lib/module/index.js +13 -0
  32. package/lib/module/index.js.map +1 -0
  33. package/lib/module/package.json +1 -0
  34. package/lib/module/types.js +47 -0
  35. package/lib/module/types.js.map +1 -0
  36. package/lib/typescript/package.json +1 -0
  37. package/lib/typescript/src/CameraInfoModule.d.ts +8 -0
  38. package/lib/typescript/src/CameraInfoModule.d.ts.map +1 -0
  39. package/lib/typescript/src/ScannerViewNativeComponent.d.ts +91 -0
  40. package/lib/typescript/src/ScannerViewNativeComponent.d.ts.map +1 -0
  41. package/lib/typescript/src/hooks/useCameraInfo.d.ts +25 -0
  42. package/lib/typescript/src/hooks/useCameraInfo.d.ts.map +1 -0
  43. package/lib/typescript/src/index.d.ts +8 -0
  44. package/lib/typescript/src/index.d.ts.map +1 -0
  45. package/lib/typescript/src/types.d.ts +145 -0
  46. package/lib/typescript/src/types.d.ts.map +1 -0
  47. package/package.json +178 -0
  48. package/src/CameraInfoModule.ts +11 -0
  49. package/src/ScannerViewNativeComponent.ts +121 -0
  50. package/src/hooks/useCameraInfo.ts +190 -0
  51. package/src/index.tsx +30 -0
  52. package/src/types.ts +177 -0
@@ -0,0 +1,90 @@
1
+ buildscript {
2
+ ext.getExtOrDefault = {name ->
3
+ return rootProject.ext.has(name) ? rootProject.ext.get(name) : project.properties['Scanner_' + name]
4
+ }
5
+
6
+ repositories {
7
+ google()
8
+ mavenCentral()
9
+ }
10
+
11
+ dependencies {
12
+ classpath "com.android.tools.build:gradle:8.7.2"
13
+ // noinspection DifferentKotlinGradleVersion
14
+ classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${getExtOrDefault('kotlinVersion')}"
15
+ }
16
+ }
17
+
18
+
19
+ apply plugin: "com.android.library"
20
+ apply plugin: "kotlin-android"
21
+
22
+ apply plugin: "com.facebook.react"
23
+
24
+ def getExtOrIntegerDefault(name) {
25
+ return rootProject.ext.has(name) ? rootProject.ext.get(name) : (project.properties["Scanner_" + name]).toInteger()
26
+ }
27
+
28
+ android {
29
+ namespace "com.scanner"
30
+
31
+ compileSdkVersion getExtOrIntegerDefault("compileSdkVersion")
32
+
33
+ defaultConfig {
34
+ minSdkVersion getExtOrIntegerDefault("minSdkVersion")
35
+ targetSdkVersion getExtOrIntegerDefault("targetSdkVersion")
36
+ }
37
+
38
+ buildFeatures {
39
+ buildConfig true
40
+ }
41
+
42
+ buildTypes {
43
+ release {
44
+ minifyEnabled false
45
+ }
46
+ }
47
+
48
+ lintOptions {
49
+ disable "GradleCompatible"
50
+ }
51
+
52
+ compileOptions {
53
+ sourceCompatibility JavaVersion.VERSION_1_8
54
+ targetCompatibility JavaVersion.VERSION_1_8
55
+ }
56
+
57
+ sourceSets {
58
+ main {
59
+ java.srcDirs += [
60
+ "generated/java",
61
+ "generated/jni"
62
+ ]
63
+ }
64
+ }
65
+ }
66
+
67
+ repositories {
68
+ mavenCentral()
69
+ google()
70
+ }
71
+
72
+ def kotlin_version = getExtOrDefault("kotlinVersion")
73
+
74
+ dependencies {
75
+ implementation "com.facebook.react:react-android"
76
+ implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
77
+
78
+ // Camera dependencies
79
+ implementation "androidx.camera:camera-core:1.3.1"
80
+ implementation "androidx.camera:camera-camera2:1.3.1"
81
+ implementation "androidx.camera:camera-lifecycle:1.3.1"
82
+ implementation "androidx.camera:camera-view:1.3.1"
83
+
84
+ // ML Kit for barcode scanning
85
+ implementation "com.google.mlkit:barcode-scanning:17.2.0"
86
+
87
+ // Lifecycle dependencies
88
+ implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.7.0"
89
+ implementation "androidx.lifecycle:lifecycle-common-java8:2.7.0"
90
+ }
@@ -0,0 +1,5 @@
1
+ Scanner_kotlinVersion=2.0.21
2
+ Scanner_minSdkVersion=24
3
+ Scanner_targetSdkVersion=34
4
+ Scanner_compileSdkVersion=35
5
+ Scanner_ndkVersion=27.1.12297006
@@ -0,0 +1,8 @@
1
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android">
2
+ <!-- Camera permissions -->
3
+ <uses-permission android:name="android.permission.CAMERA" />
4
+ <uses-permission android:name="android.permission.WAKE_LOCK" />
5
+ <uses-feature android:name="android.hardware.camera" android:required="true" />
6
+ <uses-feature android:name="android.hardware.camera.autofocus" android:required="false" />
7
+ <uses-feature android:name="android.hardware.camera.flash" android:required="false" />
8
+ </manifest>
@@ -0,0 +1,253 @@
1
+ package com.scanner
2
+
3
+ import android.content.Context
4
+ import android.content.pm.PackageManager
5
+ import android.hardware.camera2.CameraCharacteristics
6
+ import android.hardware.camera2.CameraManager
7
+ import android.Manifest
8
+ import android.util.Log
9
+ import androidx.camera.core.CameraSelector
10
+ import androidx.camera.lifecycle.ProcessCameraProvider
11
+ import androidx.core.content.ContextCompat
12
+ import com.facebook.react.bridge.*
13
+ import com.facebook.react.modules.core.DeviceEventManagerModule
14
+ import java.util.concurrent.ExecutorService
15
+ import java.util.concurrent.Executors
16
+
17
+ // Removed @ReactModule annotation for compatibility
18
+ class CameraInfoModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaModule(reactContext) {
19
+
20
+ private val cameraExecutor: ExecutorService = Executors.newSingleThreadExecutor()
21
+ private var cameraProvider: ProcessCameraProvider? = null
22
+
23
+ override fun getName(): String = NAME
24
+
25
+ @ReactMethod
26
+ fun getCameraInfo(promise: Promise) {
27
+ try {
28
+ // Check camera permission first
29
+ if (!hasCameraPermission()) {
30
+ promise.reject("PERMISSION_ERROR", "Camera permission not granted")
31
+ return
32
+ }
33
+
34
+ val cameraManager = reactApplicationContext.getSystemService(Context.CAMERA_SERVICE) as CameraManager
35
+ val cameraArray = Arguments.createArray()
36
+
37
+ // Check if camera list is available
38
+ if (cameraManager.cameraIdList.isEmpty()) {
39
+ promise.reject("NO_CAMERAS_ERROR", "No cameras found on device")
40
+ return
41
+ }
42
+
43
+ // Collect all camera info first, then deduplicate
44
+ val allCameras = mutableListOf<Pair<String, CameraCharacteristics>>()
45
+
46
+ for (cameraId in cameraManager.cameraIdList) {
47
+ try {
48
+ val characteristics = cameraManager.getCameraCharacteristics(cameraId)
49
+ allCameras.add(cameraId to characteristics)
50
+ } catch (e: Exception) {
51
+ Log.w("CameraInfoModule", "Failed to get characteristics for camera $cameraId", e)
52
+ continue
53
+ }
54
+ }
55
+
56
+ // Deduplicate cameras based on characteristics
57
+ val uniqueCameras = deduplicateCameras(allCameras)
58
+
59
+ // Create camera info maps for unique cameras
60
+ for ((cameraId, characteristics) in uniqueCameras) {
61
+ val cameraInfo = createCameraInfoMap(cameraId, characteristics)
62
+ cameraArray.pushMap(cameraInfo)
63
+ }
64
+
65
+ // If no cameras were successfully processed, return error
66
+ if (cameraArray.size() == 0) {
67
+ promise.reject("CAMERA_ACCESS_ERROR", "Failed to access any camera characteristics")
68
+ return
69
+ }
70
+
71
+ val result = Arguments.createMap().apply {
72
+ putArray("cameras", cameraArray)
73
+ putString("defaultBackCamera", getDefaultBackCameraId(cameraManager))
74
+ putString("defaultFrontCamera", getDefaultFrontCameraId(cameraManager))
75
+ }
76
+
77
+ promise.resolve(result)
78
+ } catch (e: Exception) {
79
+ Log.e("CameraInfoModule", "Error getting camera info", e)
80
+ promise.reject("CAMERA_INFO_ERROR", "Failed to get camera information: ${e.message}", e)
81
+ }
82
+ }
83
+
84
+ @ReactMethod
85
+ fun getCurrentCameraInfo(promise: Promise) {
86
+ try {
87
+ val cameraProviderFuture = ProcessCameraProvider.getInstance(reactApplicationContext)
88
+ cameraProviderFuture.addListener({
89
+ try {
90
+ cameraProvider = cameraProviderFuture.get()
91
+ val cameraInfo = getCurrentCameraCapabilities()
92
+ promise.resolve(cameraInfo)
93
+ } catch (e: Exception) {
94
+ Log.e("CameraInfoModule", "Error getting current camera info", e)
95
+ promise.reject("CURRENT_CAMERA_ERROR", "Failed to get current camera info", e)
96
+ }
97
+ }, ContextCompat.getMainExecutor(reactApplicationContext))
98
+ } catch (e: Exception) {
99
+ Log.e("CameraInfoModule", "Error initializing camera provider", e)
100
+ promise.reject("CAMERA_PROVIDER_ERROR", "Failed to initialize camera provider", e)
101
+ }
102
+ }
103
+
104
+ private fun hasCameraPermission(): Boolean {
105
+ return reactApplicationContext.checkSelfPermission(Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED
106
+ }
107
+
108
+ private fun createCameraInfoMap(cameraId: String, characteristics: CameraCharacteristics): WritableMap {
109
+ val lensFacing = characteristics.get(CameraCharacteristics.LENS_FACING)
110
+ val sensorOrientation = characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION) ?: 0
111
+ val minFocusDistance = characteristics.get(CameraCharacteristics.LENS_INFO_MINIMUM_FOCUS_DISTANCE)
112
+ val availableFocalLengths = characteristics.get(CameraCharacteristics.LENS_INFO_AVAILABLE_FOCAL_LENGTHS)
113
+ val availableAeModes = characteristics.get(CameraCharacteristics.CONTROL_AE_AVAILABLE_MODES)
114
+ val availableAfModes = characteristics.get(CameraCharacteristics.CONTROL_AF_AVAILABLE_MODES)
115
+ val flashAvailable = characteristics.get(CameraCharacteristics.FLASH_INFO_AVAILABLE) ?: false
116
+
117
+ // Determine if this is a macro camera
118
+ val isMacroCamera = isMacroCamera(characteristics)
119
+
120
+ // Get zoom range
121
+ val maxZoom = characteristics.get(CameraCharacteristics.SCALER_AVAILABLE_MAX_DIGITAL_ZOOM) ?: 1.0f
122
+ val minZoom = 1.0f // Digital zoom typically starts at 1.0
123
+
124
+ return Arguments.createMap().apply {
125
+ putString("id", cameraId)
126
+ putString("facing", when (lensFacing) {
127
+ CameraCharacteristics.LENS_FACING_FRONT -> "front"
128
+ CameraCharacteristics.LENS_FACING_BACK -> "back"
129
+ else -> "unknown"
130
+ })
131
+ putInt("sensorOrientation", sensorOrientation)
132
+ putDouble("minFocusDistance", minFocusDistance?.toDouble() ?: -1.0)
133
+ putBoolean("hasFlash", flashAvailable)
134
+ putBoolean("isMacroCamera", isMacroCamera)
135
+
136
+ // Add zoom range as separate properties
137
+ putDouble("zoomMin", minZoom.toDouble())
138
+ putDouble("zoomMax", maxZoom.toDouble())
139
+
140
+ // Convert arrays to supported types for React Native
141
+ putArray("focalLengths", availableFocalLengths?.let { lengths ->
142
+ val stringArray = lengths.map { it.toString() }.toTypedArray()
143
+ Arguments.fromArray(stringArray)
144
+ } ?: Arguments.createArray())
145
+
146
+ putArray("aeModes", availableAeModes?.let { modes ->
147
+ val stringArray = modes.map { it.toString() }.toTypedArray()
148
+ Arguments.fromArray(stringArray)
149
+ } ?: Arguments.createArray())
150
+
151
+ putArray("afModes", availableAfModes?.let { modes ->
152
+ val stringArray = modes.map { it.toString() }.toTypedArray()
153
+ Arguments.fromArray(stringArray)
154
+ } ?: Arguments.createArray())
155
+ }
156
+ }
157
+
158
+ private fun isMacroCamera(characteristics: CameraCharacteristics): Boolean {
159
+ val minFocusDistance = characteristics.get(CameraCharacteristics.LENS_INFO_MINIMUM_FOCUS_DISTANCE)
160
+ val availableFocalLengths = characteristics.get(CameraCharacteristics.LENS_INFO_AVAILABLE_FOCAL_LENGTHS)
161
+
162
+ // Macro cameras typically have very small minimum focus distance
163
+ val hasCloseFocus = minFocusDistance != null && minFocusDistance < 0.5f
164
+
165
+ // Macro cameras often have specific focal lengths
166
+ val hasMacroFocalLength = availableFocalLengths?.any { it < 3.0f } == true
167
+
168
+ return hasCloseFocus || hasMacroFocalLength
169
+ }
170
+
171
+ private fun deduplicateCameras(cameras: List<Pair<String, CameraCharacteristics>>): List<Pair<String, CameraCharacteristics>> {
172
+ val uniqueCameras = mutableListOf<Pair<String, CameraCharacteristics>>()
173
+ val seenCharacteristics = mutableSetOf<String>()
174
+
175
+ for ((cameraId, characteristics) in cameras) {
176
+ // Create a unique key based on camera characteristics
177
+ val key = createCameraKey(characteristics)
178
+
179
+ if (!seenCharacteristics.contains(key)) {
180
+ seenCharacteristics.add(key)
181
+ uniqueCameras.add(cameraId to characteristics)
182
+ } else {
183
+ Log.d("CameraInfoModule", "Skipping duplicate camera: $cameraId")
184
+ }
185
+ }
186
+
187
+ return uniqueCameras
188
+ }
189
+
190
+ private fun createCameraKey(characteristics: CameraCharacteristics): String {
191
+ val lensFacing = characteristics.get(CameraCharacteristics.LENS_FACING) ?: -1
192
+ val sensorOrientation = characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION) ?: 0
193
+ val minFocusDistance = characteristics.get(CameraCharacteristics.LENS_INFO_MINIMUM_FOCUS_DISTANCE)
194
+ val availableFocalLengths = characteristics.get(CameraCharacteristics.LENS_INFO_AVAILABLE_FOCAL_LENGTHS)
195
+ val flashAvailable = characteristics.get(CameraCharacteristics.FLASH_INFO_AVAILABLE) ?: false
196
+
197
+ // Create a unique key based on physical characteristics
198
+ val focalLengthsStr = availableFocalLengths?.joinToString(",") ?: ""
199
+ val minFocusStr = minFocusDistance?.toString() ?: "null"
200
+
201
+ return "$lensFacing-$sensorOrientation-$minFocusStr-$focalLengthsStr-$flashAvailable"
202
+ }
203
+
204
+ private fun getDefaultBackCameraId(cameraManager: CameraManager): String {
205
+ for (cameraId in cameraManager.cameraIdList) {
206
+ try {
207
+ val characteristics = cameraManager.getCameraCharacteristics(cameraId)
208
+ val lensFacing = characteristics.get(CameraCharacteristics.LENS_FACING)
209
+ if (lensFacing == CameraCharacteristics.LENS_FACING_BACK) {
210
+ return cameraId
211
+ }
212
+ } catch (e: Exception) {
213
+ Log.w("CameraInfoModule", "Failed to get characteristics for camera $cameraId", e)
214
+ continue
215
+ }
216
+ }
217
+ return cameraManager.cameraIdList.firstOrNull() ?: ""
218
+ }
219
+
220
+ private fun getDefaultFrontCameraId(cameraManager: CameraManager): String {
221
+ for (cameraId in cameraManager.cameraIdList) {
222
+ try {
223
+ val characteristics = cameraManager.getCameraCharacteristics(cameraId)
224
+ val lensFacing = characteristics.get(CameraCharacteristics.LENS_FACING)
225
+ if (lensFacing == CameraCharacteristics.LENS_FACING_FRONT) {
226
+ return cameraId
227
+ }
228
+ } catch (e: Exception) {
229
+ Log.w("CameraInfoModule", "Failed to get characteristics for camera $cameraId", e)
230
+ continue
231
+ }
232
+ }
233
+ return ""
234
+ }
235
+
236
+ private fun getCurrentCameraCapabilities(): WritableMap {
237
+ // This would be called when a camera is already bound
238
+ // For now, return basic info
239
+ return Arguments.createMap().apply {
240
+ putString("status", "camera_bound")
241
+ putString("message", "Camera capabilities available when camera is bound")
242
+ }
243
+ }
244
+
245
+ override fun onCatalystInstanceDestroy() {
246
+ super.onCatalystInstanceDestroy()
247
+ cameraExecutor.shutdown()
248
+ }
249
+
250
+ companion object {
251
+ const val NAME = "CameraInfoModule"
252
+ }
253
+ }
@@ -0,0 +1,21 @@
1
+ package com.scanner
2
+
3
+ import com.facebook.react.ReactPackage
4
+ import com.facebook.react.bridge.NativeModule
5
+ import com.facebook.react.bridge.ReactApplicationContext
6
+ import com.facebook.react.uimanager.ViewManager
7
+ import java.util.ArrayList
8
+
9
+ class ScannerViewPackage : ReactPackage {
10
+ override fun createViewManagers(reactContext: ReactApplicationContext): List<ViewManager<*, *>> {
11
+ val viewManagers: MutableList<ViewManager<*, *>> = ArrayList()
12
+ viewManagers.add(ScannerViewManager())
13
+ return viewManagers
14
+ }
15
+
16
+ override fun createNativeModules(reactContext: ReactApplicationContext): List<NativeModule> {
17
+ val modules: MutableList<NativeModule> = ArrayList()
18
+ modules.add(CameraInfoModule(reactContext))
19
+ return modules
20
+ }
21
+ }