raxon-barcode-scanner 0.1.0
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.
- package/LICENSE +21 -0
- package/README.md +105 -0
- package/android/build.gradle +18 -0
- package/android/src/main/AndroidManifest.xml +2 -0
- package/android/src/main/java/expo/modules/raxonbarcodescanner/RaxonBarcodeScannerModule.kt +330 -0
- package/build/RaxonBarcodeScanner.types.d.ts +36 -0
- package/build/RaxonBarcodeScanner.types.d.ts.map +1 -0
- package/build/RaxonBarcodeScanner.types.js +2 -0
- package/build/RaxonBarcodeScanner.types.js.map +1 -0
- package/build/RaxonBarcodeScannerModule.d.ts +9 -0
- package/build/RaxonBarcodeScannerModule.d.ts.map +1 -0
- package/build/RaxonBarcodeScannerModule.js +3 -0
- package/build/RaxonBarcodeScannerModule.js.map +1 -0
- package/build/RaxonBarcodeScannerModule.web.d.ts +9 -0
- package/build/RaxonBarcodeScannerModule.web.d.ts.map +1 -0
- package/build/RaxonBarcodeScannerModule.web.js +11 -0
- package/build/RaxonBarcodeScannerModule.web.js.map +1 -0
- package/build/index.d.ts +4 -0
- package/build/index.d.ts.map +1 -0
- package/build/index.js +4 -0
- package/build/index.js.map +1 -0
- package/build/useBarcodeScanner.d.ts +3 -0
- package/build/useBarcodeScanner.d.ts.map +1 -0
- package/build/useBarcodeScanner.js +29 -0
- package/build/useBarcodeScanner.js.map +1 -0
- package/expo-module.config.json +6 -0
- package/package.json +70 -0
- package/src/RaxonBarcodeScanner.types.ts +38 -0
- package/src/RaxonBarcodeScannerModule.ts +13 -0
- package/src/RaxonBarcodeScannerModule.web.ts +18 -0
- package/src/index.ts +3 -0
- package/src/useBarcodeScanner.ts +45 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2015-present 650 Industries, Inc. (aka Expo)
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
# raxon-barcode-scanner
|
|
2
|
+
|
|
3
|
+
Zebra ve benzeri kurumsal Android cihazlarda fiziksel barkod okuyucudan gelen veriyi React Native / Expo uygulamanıza aktaran hook tabanlı paket.
|
|
4
|
+
|
|
5
|
+
## Özellikler
|
|
6
|
+
|
|
7
|
+
- `useBarcodeScanner` hook ile basit entegrasyon
|
|
8
|
+
- Zebra DataWedge profilini otomatik oluşturma / güncelleme
|
|
9
|
+
- Klavye gibi davranan (HID / keyboard-wedge) okuyucu desteği: tuş vuruşları tamponlanır, Enter/Tab ile tek barkod olarak yayınlanır ve UI'a sızmaz
|
|
10
|
+
- Android 13+ broadcast receiver uyumluluğu
|
|
11
|
+
- Expo Modules API ile autolinking
|
|
12
|
+
|
|
13
|
+
## Kurulum
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npm install raxon-barcode-scanner
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Expo projelerinde development build veya `expo prebuild` gerekir. Expo Go içinde native modül çalışmaz.
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
npx expo prebuild
|
|
23
|
+
npx expo run:android
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Kullanım
|
|
27
|
+
|
|
28
|
+
```tsx
|
|
29
|
+
import { useCallback, useState } from 'react';
|
|
30
|
+
import { useBarcodeScanner } from 'raxon-barcode-scanner';
|
|
31
|
+
|
|
32
|
+
function ScannerScreen() {
|
|
33
|
+
const [enabled, setEnabled] = useState(true);
|
|
34
|
+
|
|
35
|
+
const onReadBarcode = useCallback((payload) => {
|
|
36
|
+
console.log(payload.code, payload.symbology);
|
|
37
|
+
}, []);
|
|
38
|
+
|
|
39
|
+
const scanner = useBarcodeScanner(enabled, onReadBarcode);
|
|
40
|
+
|
|
41
|
+
return (
|
|
42
|
+
<>
|
|
43
|
+
<Switch value={enabled} onValueChange={setEnabled} />
|
|
44
|
+
<Text>{scanner.isListening ? 'Dinleniyor' : 'Kapalı'}</Text>
|
|
45
|
+
</>
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
`Switch` ve `Text` için `react-native` importunu eklemeyi unutmayın.
|
|
51
|
+
|
|
52
|
+
`enabled` değeri `true` olduğu sürece native dinleyici açık kalır. `false` yapıldığında dinleyici kapanır.
|
|
53
|
+
|
|
54
|
+
### Gelişmiş ayarlar
|
|
55
|
+
|
|
56
|
+
```tsx
|
|
57
|
+
useBarcodeScanner(enabled, onReadBarcode, {
|
|
58
|
+
intentAction: 'com.myapp.barcode.ACTION',
|
|
59
|
+
profileName: 'MyAppScanner',
|
|
60
|
+
configureDataWedge: true,
|
|
61
|
+
captureKeyboard: true,
|
|
62
|
+
});
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
| Seçenek | Varsayılan | Açıklama |
|
|
66
|
+
| --- | --- | --- |
|
|
67
|
+
| `intentAction` | `com.raxon.barcode.ACTION` | DataWedge broadcast action |
|
|
68
|
+
| `profileName` | `RaxonBarcodeScanner` | DataWedge profil adı |
|
|
69
|
+
| `configureDataWedge` | `true` | Profili otomatik yapılandır |
|
|
70
|
+
| `captureKeyboard` | `true` | Klavye modundaki (HID) okuyucuları yakala |
|
|
71
|
+
|
|
72
|
+
`configureDataWedge: false` kullanın eğer DataWedge profilini MDM veya manuel olarak yönetiyorsanız. Bu durumda `intentAction` değerinin profildeki Intent Output action ile eşleşmesi gerekir.
|
|
73
|
+
|
|
74
|
+
## Test projesi
|
|
75
|
+
|
|
76
|
+
Depodaki `example` uygulaması modülü test etmek içindir.
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
cd example
|
|
80
|
+
npm install
|
|
81
|
+
npm run android
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Kök dizinden:
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
npm run open:android
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## Desteklenen cihazlar
|
|
91
|
+
|
|
92
|
+
- Zebra TC serisi ve DataWedge yüklü cihazlar
|
|
93
|
+
- DataWedge Intent Output ile broadcast gönderen diğer kurumsal Android cihazlar
|
|
94
|
+
- Klavye (HID / keyboard-wedge) modunda çalışan okuyucular ve el terminalleri
|
|
95
|
+
|
|
96
|
+
## npm yayını
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
npm run build
|
|
100
|
+
npm publish --access public
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## Lisans
|
|
104
|
+
|
|
105
|
+
MIT
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
plugins {
|
|
2
|
+
id 'com.android.library'
|
|
3
|
+
id 'expo-module-gradle-plugin'
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
group = 'expo.modules.raxonbarcodescanner'
|
|
7
|
+
version = '0.1.0'
|
|
8
|
+
|
|
9
|
+
android {
|
|
10
|
+
namespace "expo.modules.raxonbarcodescanner"
|
|
11
|
+
defaultConfig {
|
|
12
|
+
versionCode 1
|
|
13
|
+
versionName "0.1.0"
|
|
14
|
+
}
|
|
15
|
+
lintOptions {
|
|
16
|
+
abortOnError false
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -0,0 +1,330 @@
|
|
|
1
|
+
package expo.modules.raxonbarcodescanner
|
|
2
|
+
|
|
3
|
+
import android.app.Activity
|
|
4
|
+
import android.content.BroadcastReceiver
|
|
5
|
+
import android.content.Context
|
|
6
|
+
import android.content.Intent
|
|
7
|
+
import android.content.IntentFilter
|
|
8
|
+
import android.os.Build
|
|
9
|
+
import android.os.Bundle
|
|
10
|
+
import android.os.SystemClock
|
|
11
|
+
import android.view.KeyEvent
|
|
12
|
+
import android.view.Window
|
|
13
|
+
import expo.modules.kotlin.modules.Module
|
|
14
|
+
import expo.modules.kotlin.modules.ModuleDefinition
|
|
15
|
+
|
|
16
|
+
class RaxonBarcodeScannerModule : Module() {
|
|
17
|
+
companion object {
|
|
18
|
+
private const val DEFAULT_INTENT_ACTION = "com.raxon.barcode.ACTION"
|
|
19
|
+
private const val DEFAULT_PROFILE_NAME = "RaxonBarcodeScanner"
|
|
20
|
+
private const val DATAWEDGE_API_ACTION = "com.symbol.datawedge.api.ACTION"
|
|
21
|
+
private const val DATAWEDGE_RESULT_ACTION = "com.symbol.datawedge.api.RESULT_ACTION"
|
|
22
|
+
private const val DATAWEDGE_PACKAGE = "com.symbol.datawedge"
|
|
23
|
+
private const val SET_CONFIG_EXTRA = "com.symbol.datawedge.api.SET_CONFIG"
|
|
24
|
+
|
|
25
|
+
private val BARCODE_DATA_KEYS = listOf(
|
|
26
|
+
"com.symbol.datawedge.data_string",
|
|
27
|
+
"com.motorolasolutions.emdk.datawedge.data_string",
|
|
28
|
+
"data",
|
|
29
|
+
"barcode_string",
|
|
30
|
+
"SCAN_BARCODE1",
|
|
31
|
+
"barcode"
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
private val SYMBOLOGY_KEYS = listOf(
|
|
35
|
+
"com.symbol.datawedge.label_type",
|
|
36
|
+
"com.motorolasolutions.emdk.datawedge.label_type",
|
|
37
|
+
"label_type",
|
|
38
|
+
"aimId"
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
// Keyboard-wedge: art arda gelen tuşlar arasında bu süre aşılırsa tampon sıfırlanır.
|
|
42
|
+
private const val WEDGE_BUFFER_TIMEOUT_MS = 1000L
|
|
43
|
+
|
|
44
|
+
private val TERMINATOR_KEY_CODES = setOf(
|
|
45
|
+
KeyEvent.KEYCODE_ENTER,
|
|
46
|
+
KeyEvent.KEYCODE_NUMPAD_ENTER,
|
|
47
|
+
KeyEvent.KEYCODE_TAB
|
|
48
|
+
)
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
private var broadcastReceiver: BroadcastReceiver? = null
|
|
52
|
+
private var isListening = false
|
|
53
|
+
private var keyInterceptor: KeyInterceptorCallback? = null
|
|
54
|
+
private val wedgeBuffer = StringBuilder()
|
|
55
|
+
private var lastWedgeKeyTime = 0L
|
|
56
|
+
private val consumedKeyDowns = mutableSetOf<Int>()
|
|
57
|
+
|
|
58
|
+
private val context: Context
|
|
59
|
+
get() = requireNotNull(appContext.reactContext)
|
|
60
|
+
|
|
61
|
+
override fun definition() = ModuleDefinition {
|
|
62
|
+
Name("RaxonBarcodeScanner")
|
|
63
|
+
|
|
64
|
+
Events("onBarcodeScanned")
|
|
65
|
+
|
|
66
|
+
Function("startListening") { options: Map<String, Any?>? ->
|
|
67
|
+
startListening(options)
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
Function("stopListening") {
|
|
71
|
+
stopListening()
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
OnDestroy {
|
|
75
|
+
stopListening()
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
private fun startListening(options: Map<String, Any?>?) {
|
|
80
|
+
if (isListening) {
|
|
81
|
+
stopListening()
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
val intentAction = (options?.get("intentAction") as? String)?.takeIf { it.isNotBlank() }
|
|
85
|
+
?: DEFAULT_INTENT_ACTION
|
|
86
|
+
val profileName = (options?.get("profileName") as? String)?.takeIf { it.isNotBlank() }
|
|
87
|
+
?: DEFAULT_PROFILE_NAME
|
|
88
|
+
val configureDataWedge = options?.get("configureDataWedge") as? Boolean ?: true
|
|
89
|
+
val captureKeyboard = options?.get("captureKeyboard") as? Boolean ?: true
|
|
90
|
+
|
|
91
|
+
if (configureDataWedge) {
|
|
92
|
+
configureDataWedgeProfile(profileName, intentAction)
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
registerBarcodeReceiver(intentAction)
|
|
96
|
+
|
|
97
|
+
if (captureKeyboard) {
|
|
98
|
+
installKeyboardCapture()
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
isListening = true
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
private fun stopListening() {
|
|
105
|
+
broadcastReceiver?.let { receiver ->
|
|
106
|
+
try {
|
|
107
|
+
context.unregisterReceiver(receiver)
|
|
108
|
+
} catch (_: IllegalArgumentException) {
|
|
109
|
+
// Receiver was already unregistered.
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
broadcastReceiver = null
|
|
113
|
+
uninstallKeyboardCapture()
|
|
114
|
+
isListening = false
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// region Keyboard wedge (HID) scanners
|
|
118
|
+
|
|
119
|
+
private fun installKeyboardCapture() {
|
|
120
|
+
val activity = appContext.activityProvider?.currentActivity ?: return
|
|
121
|
+
activity.runOnUiThread {
|
|
122
|
+
val window = activity.window ?: return@runOnUiThread
|
|
123
|
+
val current = window.callback
|
|
124
|
+
if (current is KeyInterceptorCallback) {
|
|
125
|
+
current.enabled = true
|
|
126
|
+
keyInterceptor = current
|
|
127
|
+
return@runOnUiThread
|
|
128
|
+
}
|
|
129
|
+
val interceptor = KeyInterceptorCallback(current, ::handleWedgeKeyEvent)
|
|
130
|
+
window.callback = interceptor
|
|
131
|
+
keyInterceptor = interceptor
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
private fun uninstallKeyboardCapture() {
|
|
136
|
+
val interceptor = keyInterceptor ?: return
|
|
137
|
+
keyInterceptor = null
|
|
138
|
+
wedgeBuffer.setLength(0)
|
|
139
|
+
consumedKeyDowns.clear()
|
|
140
|
+
val activity = appContext.activityProvider?.currentActivity
|
|
141
|
+
if (activity == null) {
|
|
142
|
+
interceptor.enabled = false
|
|
143
|
+
return
|
|
144
|
+
}
|
|
145
|
+
activity.runOnUiThread {
|
|
146
|
+
val window = activity.window
|
|
147
|
+
if (window?.callback === interceptor) {
|
|
148
|
+
// Başka bir kütüphane callback'i sarmadıysa orijinali geri koy.
|
|
149
|
+
window.callback = interceptor.wrapped
|
|
150
|
+
} else {
|
|
151
|
+
interceptor.enabled = false
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Klavye gibi davranan (HID/keyboard-wedge) okuyucuların tuş vuruşlarını tamponlar.
|
|
158
|
+
* Enter/Tab geldiğinde tamponu barkod olarak yayınlar ve tuşu yutar; böylece
|
|
159
|
+
* Enter odaktaki bileşeni (ör. Switch) tetiklemez.
|
|
160
|
+
*/
|
|
161
|
+
private fun handleWedgeKeyEvent(event: KeyEvent): Boolean {
|
|
162
|
+
val isTerminator = event.keyCode in TERMINATOR_KEY_CODES
|
|
163
|
+
val unicode = event.unicodeChar
|
|
164
|
+
|
|
165
|
+
when (event.action) {
|
|
166
|
+
KeyEvent.ACTION_UP -> {
|
|
167
|
+
// DOWN'da yutulan tuşların UP'ı da yutulur ki view'lar click üretmesin.
|
|
168
|
+
return consumedKeyDowns.remove(event.keyCode)
|
|
169
|
+
}
|
|
170
|
+
KeyEvent.ACTION_MULTIPLE -> {
|
|
171
|
+
val characters = event.characters
|
|
172
|
+
if (!characters.isNullOrEmpty()) {
|
|
173
|
+
touchWedgeBuffer()
|
|
174
|
+
wedgeBuffer.append(characters)
|
|
175
|
+
return true
|
|
176
|
+
}
|
|
177
|
+
return false
|
|
178
|
+
}
|
|
179
|
+
KeyEvent.ACTION_DOWN -> {
|
|
180
|
+
if (isTerminator) {
|
|
181
|
+
if (!wedgeBufferActive()) {
|
|
182
|
+
// Tampon boşken Enter/Tab normal davranışına bırakılır.
|
|
183
|
+
return false
|
|
184
|
+
}
|
|
185
|
+
val code = wedgeBuffer.toString()
|
|
186
|
+
wedgeBuffer.setLength(0)
|
|
187
|
+
consumedKeyDowns.add(event.keyCode)
|
|
188
|
+
if (code.isNotEmpty()) {
|
|
189
|
+
sendEvent("onBarcodeScanned", mapOf("code" to code))
|
|
190
|
+
}
|
|
191
|
+
return true
|
|
192
|
+
}
|
|
193
|
+
if (unicode != 0) {
|
|
194
|
+
touchWedgeBuffer()
|
|
195
|
+
wedgeBuffer.append(unicode.toChar())
|
|
196
|
+
consumedKeyDowns.add(event.keyCode)
|
|
197
|
+
return true
|
|
198
|
+
}
|
|
199
|
+
return false
|
|
200
|
+
}
|
|
201
|
+
else -> return false
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
private fun wedgeBufferActive(): Boolean {
|
|
206
|
+
return wedgeBuffer.isNotEmpty() &&
|
|
207
|
+
SystemClock.elapsedRealtime() - lastWedgeKeyTime <= WEDGE_BUFFER_TIMEOUT_MS
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
private fun touchWedgeBuffer() {
|
|
211
|
+
val now = SystemClock.elapsedRealtime()
|
|
212
|
+
if (now - lastWedgeKeyTime > WEDGE_BUFFER_TIMEOUT_MS) {
|
|
213
|
+
wedgeBuffer.setLength(0)
|
|
214
|
+
}
|
|
215
|
+
lastWedgeKeyTime = now
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
private class KeyInterceptorCallback(
|
|
219
|
+
val wrapped: Window.Callback,
|
|
220
|
+
private val onKeyEvent: (KeyEvent) -> Boolean,
|
|
221
|
+
) : Window.Callback by wrapped {
|
|
222
|
+
var enabled = true
|
|
223
|
+
|
|
224
|
+
override fun dispatchKeyEvent(event: KeyEvent): Boolean {
|
|
225
|
+
if (enabled && onKeyEvent(event)) {
|
|
226
|
+
return true
|
|
227
|
+
}
|
|
228
|
+
return wrapped.dispatchKeyEvent(event)
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
// endregion
|
|
233
|
+
|
|
234
|
+
private fun registerBarcodeReceiver(intentAction: String) {
|
|
235
|
+
val filter = IntentFilter().apply {
|
|
236
|
+
addAction(intentAction)
|
|
237
|
+
addAction(DATAWEDGE_RESULT_ACTION)
|
|
238
|
+
addCategory(Intent.CATEGORY_DEFAULT)
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
val receiver = object : BroadcastReceiver() {
|
|
242
|
+
override fun onReceive(ctx: Context?, intent: Intent?) {
|
|
243
|
+
intent ?: return
|
|
244
|
+
handleIntent(intent)
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
|
249
|
+
context.registerReceiver(receiver, filter, Context.RECEIVER_EXPORTED)
|
|
250
|
+
} else {
|
|
251
|
+
@Suppress("UnspecifiedRegisterReceiverFlag")
|
|
252
|
+
context.registerReceiver(receiver, filter)
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
broadcastReceiver = receiver
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
private fun handleIntent(intent: Intent) {
|
|
259
|
+
val action = intent.action ?: return
|
|
260
|
+
|
|
261
|
+
if (action == DATAWEDGE_RESULT_ACTION) {
|
|
262
|
+
return
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
val code = BARCODE_DATA_KEYS.firstNotNullOfOrNull { key ->
|
|
266
|
+
intent.getStringExtra(key)?.takeIf { it.isNotBlank() }
|
|
267
|
+
} ?: return
|
|
268
|
+
|
|
269
|
+
val symbology = SYMBOLOGY_KEYS.firstNotNullOfOrNull { key ->
|
|
270
|
+
intent.getStringExtra(key)?.takeIf { it.isNotBlank() }
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
val payload = mutableMapOf<String, Any>("code" to code)
|
|
274
|
+
symbology?.let { payload["symbology"] = it }
|
|
275
|
+
|
|
276
|
+
sendEvent("onBarcodeScanned", payload)
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
private fun configureDataWedgeProfile(profileName: String, intentAction: String) {
|
|
280
|
+
val packageName = context.packageName
|
|
281
|
+
|
|
282
|
+
val barcodePlugin = Bundle().apply {
|
|
283
|
+
putString("PLUGIN_NAME", "BARCODE")
|
|
284
|
+
putString("RESET_CONFIG", "true")
|
|
285
|
+
putString("scanner_selection", "auto")
|
|
286
|
+
putString("scanner_input_enabled", "true")
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
val appList = Bundle().apply {
|
|
290
|
+
putString("PACKAGE_NAME", packageName)
|
|
291
|
+
putStringArray("ACTIVITY_LIST", arrayOf("*"))
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
val profileConfig = Bundle().apply {
|
|
295
|
+
putString("PROFILE_NAME", profileName)
|
|
296
|
+
putString("PROFILE_ENABLED", "true")
|
|
297
|
+
putString("CONFIG_MODE", "CREATE_IF_NOT_EXIST")
|
|
298
|
+
putParcelableArray("PLUGIN_CONFIG", arrayOf(barcodePlugin))
|
|
299
|
+
putParcelableArray("APP_LIST", arrayOf(appList))
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
sendDataWedgeIntent(profileConfig)
|
|
303
|
+
|
|
304
|
+
val intentPlugin = Bundle().apply {
|
|
305
|
+
putString("PLUGIN_NAME", "INTENT")
|
|
306
|
+
putString("RESET_CONFIG", "true")
|
|
307
|
+
putString("intent_output_enabled", "true")
|
|
308
|
+
putString("intent_action", intentAction)
|
|
309
|
+
putString("intent_delivery", "2")
|
|
310
|
+
putString("intent_category", "android.intent.category.DEFAULT")
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
val intentConfig = Bundle().apply {
|
|
314
|
+
putString("PROFILE_NAME", profileName)
|
|
315
|
+
putString("CONFIG_MODE", "UPDATE")
|
|
316
|
+
putParcelableArray("PLUGIN_CONFIG", arrayOf(intentPlugin))
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
sendDataWedgeIntent(intentConfig)
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
private fun sendDataWedgeIntent(config: Bundle) {
|
|
323
|
+
val intent = Intent().apply {
|
|
324
|
+
action = DATAWEDGE_API_ACTION
|
|
325
|
+
setPackage(DATAWEDGE_PACKAGE)
|
|
326
|
+
putExtra(SET_CONFIG_EXTRA, config)
|
|
327
|
+
}
|
|
328
|
+
context.sendBroadcast(intent)
|
|
329
|
+
}
|
|
330
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
export type BarcodeScanPayload = {
|
|
2
|
+
code: string;
|
|
3
|
+
symbology?: string;
|
|
4
|
+
};
|
|
5
|
+
export type BarcodeScannerOptions = {
|
|
6
|
+
/**
|
|
7
|
+
* DataWedge intent action used for barcode broadcasts.
|
|
8
|
+
* @default "com.raxon.barcode.ACTION"
|
|
9
|
+
*/
|
|
10
|
+
intentAction?: string;
|
|
11
|
+
/**
|
|
12
|
+
* DataWedge profile name created or updated for this app.
|
|
13
|
+
* @default "RaxonBarcodeScanner"
|
|
14
|
+
*/
|
|
15
|
+
profileName?: string;
|
|
16
|
+
/**
|
|
17
|
+
* Automatically configure a DataWedge profile on Zebra devices.
|
|
18
|
+
* Set to false if you manage DataWedge profiles manually.
|
|
19
|
+
* @default true
|
|
20
|
+
*/
|
|
21
|
+
configureDataWedge?: boolean;
|
|
22
|
+
/**
|
|
23
|
+
* Capture input from scanners that act as a keyboard (HID / keyboard-wedge).
|
|
24
|
+
* Keystrokes are buffered and emitted as a single scan when Enter/Tab is
|
|
25
|
+
* received; the keys are swallowed so they don't interact with the UI.
|
|
26
|
+
* @default true
|
|
27
|
+
*/
|
|
28
|
+
captureKeyboard?: boolean;
|
|
29
|
+
};
|
|
30
|
+
export type RaxonBarcodeScannerModuleEvents = {
|
|
31
|
+
onBarcodeScanned: (params: BarcodeScanPayload) => void;
|
|
32
|
+
};
|
|
33
|
+
export type UseBarcodeScannerResult = {
|
|
34
|
+
isListening: boolean;
|
|
35
|
+
};
|
|
36
|
+
//# sourceMappingURL=RaxonBarcodeScanner.types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RaxonBarcodeScanner.types.d.ts","sourceRoot":"","sources":["../src/RaxonBarcodeScanner.types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,kBAAkB,GAAG;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,qBAAqB,GAAG;IAClC;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;OAIG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B;;;;;OAKG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B,CAAC;AAEF,MAAM,MAAM,+BAA+B,GAAG;IAC5C,gBAAgB,EAAE,CAAC,MAAM,EAAE,kBAAkB,KAAK,IAAI,CAAC;CACxD,CAAC;AAEF,MAAM,MAAM,uBAAuB,GAAG;IACpC,WAAW,EAAE,OAAO,CAAC;CACtB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RaxonBarcodeScanner.types.js","sourceRoot":"","sources":["../src/RaxonBarcodeScanner.types.ts"],"names":[],"mappings":"","sourcesContent":["export type BarcodeScanPayload = {\n code: string;\n symbology?: string;\n};\n\nexport type BarcodeScannerOptions = {\n /**\n * DataWedge intent action used for barcode broadcasts.\n * @default \"com.raxon.barcode.ACTION\"\n */\n intentAction?: string;\n /**\n * DataWedge profile name created or updated for this app.\n * @default \"RaxonBarcodeScanner\"\n */\n profileName?: string;\n /**\n * Automatically configure a DataWedge profile on Zebra devices.\n * Set to false if you manage DataWedge profiles manually.\n * @default true\n */\n configureDataWedge?: boolean;\n /**\n * Capture input from scanners that act as a keyboard (HID / keyboard-wedge).\n * Keystrokes are buffered and emitted as a single scan when Enter/Tab is\n * received; the keys are swallowed so they don't interact with the UI.\n * @default true\n */\n captureKeyboard?: boolean;\n};\n\nexport type RaxonBarcodeScannerModuleEvents = {\n onBarcodeScanned: (params: BarcodeScanPayload) => void;\n};\n\nexport type UseBarcodeScannerResult = {\n isListening: boolean;\n};\n"]}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { NativeModule } from 'expo';
|
|
2
|
+
import { BarcodeScannerOptions, RaxonBarcodeScannerModuleEvents } from './RaxonBarcodeScanner.types';
|
|
3
|
+
declare class RaxonBarcodeScannerModule extends NativeModule<RaxonBarcodeScannerModuleEvents> {
|
|
4
|
+
startListening(options?: BarcodeScannerOptions): void;
|
|
5
|
+
stopListening(): void;
|
|
6
|
+
}
|
|
7
|
+
declare const _default: RaxonBarcodeScannerModule;
|
|
8
|
+
export default _default;
|
|
9
|
+
//# sourceMappingURL=RaxonBarcodeScannerModule.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RaxonBarcodeScannerModule.d.ts","sourceRoot":"","sources":["../src/RaxonBarcodeScannerModule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAuB,MAAM,MAAM,CAAC;AAEzD,OAAO,EACL,qBAAqB,EACrB,+BAA+B,EAChC,MAAM,6BAA6B,CAAC;AAErC,OAAO,OAAO,yBAA0B,SAAQ,YAAY,CAAC,+BAA+B,CAAC;IAC3F,cAAc,CAAC,OAAO,CAAC,EAAE,qBAAqB,GAAG,IAAI;IACrD,aAAa,IAAI,IAAI;CACtB;;AAED,wBAAqF"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RaxonBarcodeScannerModule.js","sourceRoot":"","sources":["../src/RaxonBarcodeScannerModule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,mBAAmB,EAAE,MAAM,MAAM,CAAC;AAYzD,eAAe,mBAAmB,CAA4B,qBAAqB,CAAC,CAAC","sourcesContent":["import { NativeModule, requireNativeModule } from 'expo';\n\nimport {\n BarcodeScannerOptions,\n RaxonBarcodeScannerModuleEvents,\n} from './RaxonBarcodeScanner.types';\n\ndeclare class RaxonBarcodeScannerModule extends NativeModule<RaxonBarcodeScannerModuleEvents> {\n startListening(options?: BarcodeScannerOptions): void;\n stopListening(): void;\n}\n\nexport default requireNativeModule<RaxonBarcodeScannerModule>('RaxonBarcodeScanner');\n"]}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { NativeModule } from 'expo';
|
|
2
|
+
import { BarcodeScannerOptions, RaxonBarcodeScannerModuleEvents } from './RaxonBarcodeScanner.types';
|
|
3
|
+
declare class RaxonBarcodeScannerModule extends NativeModule<RaxonBarcodeScannerModuleEvents> {
|
|
4
|
+
startListening(_options?: BarcodeScannerOptions): void;
|
|
5
|
+
stopListening(): void;
|
|
6
|
+
}
|
|
7
|
+
declare const _default: typeof RaxonBarcodeScannerModule;
|
|
8
|
+
export default _default;
|
|
9
|
+
//# sourceMappingURL=RaxonBarcodeScannerModule.web.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RaxonBarcodeScannerModule.web.d.ts","sourceRoot":"","sources":["../src/RaxonBarcodeScannerModule.web.ts"],"names":[],"mappings":"AAAA,OAAO,EAAqB,YAAY,EAAE,MAAM,MAAM,CAAC;AAEvD,OAAO,EACL,qBAAqB,EACrB,+BAA+B,EAChC,MAAM,6BAA6B,CAAC;AAErC,cAAM,yBAA0B,SAAQ,YAAY,CAAC,+BAA+B,CAAC;IACnF,cAAc,CAAC,QAAQ,CAAC,EAAE,qBAAqB,GAAG,IAAI;IAItD,aAAa,IAAI,IAAI;CAGtB;;AAED,wBAAmF"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { registerWebModule, NativeModule } from 'expo';
|
|
2
|
+
class RaxonBarcodeScannerModule extends NativeModule {
|
|
3
|
+
startListening(_options) {
|
|
4
|
+
console.warn('raxon-barcode-scanner is only supported on Android.');
|
|
5
|
+
}
|
|
6
|
+
stopListening() {
|
|
7
|
+
// no-op
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
export default registerWebModule(RaxonBarcodeScannerModule, 'RaxonBarcodeScanner');
|
|
11
|
+
//# sourceMappingURL=RaxonBarcodeScannerModule.web.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RaxonBarcodeScannerModule.web.js","sourceRoot":"","sources":["../src/RaxonBarcodeScannerModule.web.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,MAAM,CAAC;AAOvD,MAAM,yBAA0B,SAAQ,YAA6C;IACnF,cAAc,CAAC,QAAgC;QAC7C,OAAO,CAAC,IAAI,CAAC,qDAAqD,CAAC,CAAC;IACtE,CAAC;IAED,aAAa;QACX,QAAQ;IACV,CAAC;CACF;AAED,eAAe,iBAAiB,CAAC,yBAAyB,EAAE,qBAAqB,CAAC,CAAC","sourcesContent":["import { registerWebModule, NativeModule } from 'expo';\n\nimport {\n BarcodeScannerOptions,\n RaxonBarcodeScannerModuleEvents,\n} from './RaxonBarcodeScanner.types';\n\nclass RaxonBarcodeScannerModule extends NativeModule<RaxonBarcodeScannerModuleEvents> {\n startListening(_options?: BarcodeScannerOptions): void {\n console.warn('raxon-barcode-scanner is only supported on Android.');\n }\n\n stopListening(): void {\n // no-op\n }\n}\n\nexport default registerWebModule(RaxonBarcodeScannerModule, 'RaxonBarcodeScanner');\n"]}
|
package/build/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAC7E,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACxD,cAAc,6BAA6B,CAAC"}
|
package/build/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAC7E,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACxD,cAAc,6BAA6B,CAAC","sourcesContent":["export { default as RaxonBarcodeScanner } from './RaxonBarcodeScannerModule';\nexport { useBarcodeScanner } from './useBarcodeScanner';\nexport * from './RaxonBarcodeScanner.types';\n"]}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { BarcodeScanPayload, BarcodeScannerOptions, UseBarcodeScannerResult } from './RaxonBarcodeScanner.types';
|
|
2
|
+
export declare function useBarcodeScanner(enabled: boolean, onReadBarcode: (payload: BarcodeScanPayload) => void, options?: BarcodeScannerOptions): UseBarcodeScannerResult;
|
|
3
|
+
//# sourceMappingURL=useBarcodeScanner.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useBarcodeScanner.d.ts","sourceRoot":"","sources":["../src/useBarcodeScanner.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,kBAAkB,EAClB,qBAAqB,EACrB,uBAAuB,EACxB,MAAM,6BAA6B,CAAC;AAGrC,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,OAAO,EAChB,aAAa,EAAE,CAAC,OAAO,EAAE,kBAAkB,KAAK,IAAI,EACpD,OAAO,CAAC,EAAE,qBAAqB,GAC9B,uBAAuB,CA+BzB"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { useEffect, useRef } from 'react';
|
|
2
|
+
import RaxonBarcodeScanner from './RaxonBarcodeScannerModule';
|
|
3
|
+
export function useBarcodeScanner(enabled, onReadBarcode, options) {
|
|
4
|
+
const onReadBarcodeRef = useRef(onReadBarcode);
|
|
5
|
+
useEffect(() => {
|
|
6
|
+
onReadBarcodeRef.current = onReadBarcode;
|
|
7
|
+
});
|
|
8
|
+
useEffect(() => {
|
|
9
|
+
if (!enabled) {
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
12
|
+
RaxonBarcodeScanner.startListening(options);
|
|
13
|
+
const subscription = RaxonBarcodeScanner.addListener('onBarcodeScanned', (event) => {
|
|
14
|
+
onReadBarcodeRef.current(event);
|
|
15
|
+
});
|
|
16
|
+
return () => {
|
|
17
|
+
subscription.remove();
|
|
18
|
+
RaxonBarcodeScanner.stopListening();
|
|
19
|
+
};
|
|
20
|
+
}, [
|
|
21
|
+
enabled,
|
|
22
|
+
options?.intentAction,
|
|
23
|
+
options?.profileName,
|
|
24
|
+
options?.configureDataWedge,
|
|
25
|
+
options?.captureKeyboard,
|
|
26
|
+
]);
|
|
27
|
+
return { isListening: enabled };
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=useBarcodeScanner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useBarcodeScanner.js","sourceRoot":"","sources":["../src/useBarcodeScanner.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,OAAO,CAAC;AAO1C,OAAO,mBAAmB,MAAM,6BAA6B,CAAC;AAE9D,MAAM,UAAU,iBAAiB,CAC/B,OAAgB,EAChB,aAAoD,EACpD,OAA+B;IAE/B,MAAM,gBAAgB,GAAG,MAAM,CAAC,aAAa,CAAC,CAAC;IAE/C,SAAS,CAAC,GAAG,EAAE;QACb,gBAAgB,CAAC,OAAO,GAAG,aAAa,CAAC;IAC3C,CAAC,CAAC,CAAC;IAEH,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,OAAO;QACT,CAAC;QAED,mBAAmB,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC;QAE5C,MAAM,YAAY,GAAG,mBAAmB,CAAC,WAAW,CAAC,kBAAkB,EAAE,CAAC,KAAK,EAAE,EAAE;YACjF,gBAAgB,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;QAClC,CAAC,CAAC,CAAC;QAEH,OAAO,GAAG,EAAE;YACV,YAAY,CAAC,MAAM,EAAE,CAAC;YACtB,mBAAmB,CAAC,aAAa,EAAE,CAAC;QACtC,CAAC,CAAC;IACJ,CAAC,EAAE;QACD,OAAO;QACP,OAAO,EAAE,YAAY;QACrB,OAAO,EAAE,WAAW;QACpB,OAAO,EAAE,kBAAkB;QAC3B,OAAO,EAAE,eAAe;KACzB,CAAC,CAAC;IAEH,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,CAAC;AAClC,CAAC","sourcesContent":["import { useEffect, useRef } from 'react';\n\nimport {\n BarcodeScanPayload,\n BarcodeScannerOptions,\n UseBarcodeScannerResult,\n} from './RaxonBarcodeScanner.types';\nimport RaxonBarcodeScanner from './RaxonBarcodeScannerModule';\n\nexport function useBarcodeScanner(\n enabled: boolean,\n onReadBarcode: (payload: BarcodeScanPayload) => void,\n options?: BarcodeScannerOptions\n): UseBarcodeScannerResult {\n const onReadBarcodeRef = useRef(onReadBarcode);\n\n useEffect(() => {\n onReadBarcodeRef.current = onReadBarcode;\n });\n\n useEffect(() => {\n if (!enabled) {\n return;\n }\n\n RaxonBarcodeScanner.startListening(options);\n\n const subscription = RaxonBarcodeScanner.addListener('onBarcodeScanned', (event) => {\n onReadBarcodeRef.current(event);\n });\n\n return () => {\n subscription.remove();\n RaxonBarcodeScanner.stopListening();\n };\n }, [\n enabled,\n options?.intentAction,\n options?.profileName,\n options?.configureDataWedge,\n options?.captureKeyboard,\n ]);\n\n return { isListening: enabled };\n}\n"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "raxon-barcode-scanner",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Zebra and enterprise barcode scanner hook for React Native Expo apps",
|
|
5
|
+
"main": "build/index.js",
|
|
6
|
+
"types": "build/index.d.ts",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"build": "node internal/module_scripts/build.js",
|
|
9
|
+
"clean": "node internal/module_scripts/clean.js",
|
|
10
|
+
"lint": "eslint src/",
|
|
11
|
+
"test": "node internal/module_scripts/test.js",
|
|
12
|
+
"prepare": "node internal/module_scripts/prepare.js",
|
|
13
|
+
"open:ios": "node internal/module_scripts/open-ios.js",
|
|
14
|
+
"open:android": "node internal/module_scripts/open-android.js"
|
|
15
|
+
},
|
|
16
|
+
"keywords": [
|
|
17
|
+
"react-native",
|
|
18
|
+
"expo",
|
|
19
|
+
"expo-module",
|
|
20
|
+
"barcode",
|
|
21
|
+
"barcode-scanner",
|
|
22
|
+
"zebra",
|
|
23
|
+
"datawedge",
|
|
24
|
+
"enterprise-scanner",
|
|
25
|
+
"raxon-barcode-scanner"
|
|
26
|
+
],
|
|
27
|
+
"repository": {
|
|
28
|
+
"type": "git",
|
|
29
|
+
"url": "git+ssh://git@github.com/raxonltd/raxon-barcode-scanner.git"
|
|
30
|
+
},
|
|
31
|
+
"bugs": {
|
|
32
|
+
"url": "https://github.com/raxonltd/raxon-barcode-scanner/issues"
|
|
33
|
+
},
|
|
34
|
+
"author": "Raxon Ltd <furkanbahadirozdemir@nexine.com.tr>",
|
|
35
|
+
"license": "MIT",
|
|
36
|
+
"homepage": "https://github.com/raxonltd/raxon-barcode-scanner#readme",
|
|
37
|
+
"files": [
|
|
38
|
+
"android/build.gradle",
|
|
39
|
+
"android/src",
|
|
40
|
+
"build",
|
|
41
|
+
"expo-module.config.json",
|
|
42
|
+
"src"
|
|
43
|
+
],
|
|
44
|
+
"dependencies": {},
|
|
45
|
+
"devDependencies": {
|
|
46
|
+
"@babel/core": "^7.26.0",
|
|
47
|
+
"@types/jest": "^29.2.1",
|
|
48
|
+
"@types/react": "~19.1.1",
|
|
49
|
+
"babel-preset-expo": "~56.0.14",
|
|
50
|
+
"eslint": "~9.39.4",
|
|
51
|
+
"eslint-config-universe": "^15.0.3",
|
|
52
|
+
"expo": "^56.0.9",
|
|
53
|
+
"jest": "^29.7.0",
|
|
54
|
+
"jest-expo": "~56.0.4",
|
|
55
|
+
"prettier": "^3.0.0",
|
|
56
|
+
"react-native": "0.85.3",
|
|
57
|
+
"typescript": "^5.9.2"
|
|
58
|
+
},
|
|
59
|
+
"jest": {
|
|
60
|
+
"preset": "jest-expo",
|
|
61
|
+
"roots": [
|
|
62
|
+
"<rootDir>/src"
|
|
63
|
+
]
|
|
64
|
+
},
|
|
65
|
+
"peerDependencies": {
|
|
66
|
+
"expo": "*",
|
|
67
|
+
"react": "*",
|
|
68
|
+
"react-native": "*"
|
|
69
|
+
}
|
|
70
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
export type BarcodeScanPayload = {
|
|
2
|
+
code: string;
|
|
3
|
+
symbology?: string;
|
|
4
|
+
};
|
|
5
|
+
|
|
6
|
+
export type BarcodeScannerOptions = {
|
|
7
|
+
/**
|
|
8
|
+
* DataWedge intent action used for barcode broadcasts.
|
|
9
|
+
* @default "com.raxon.barcode.ACTION"
|
|
10
|
+
*/
|
|
11
|
+
intentAction?: string;
|
|
12
|
+
/**
|
|
13
|
+
* DataWedge profile name created or updated for this app.
|
|
14
|
+
* @default "RaxonBarcodeScanner"
|
|
15
|
+
*/
|
|
16
|
+
profileName?: string;
|
|
17
|
+
/**
|
|
18
|
+
* Automatically configure a DataWedge profile on Zebra devices.
|
|
19
|
+
* Set to false if you manage DataWedge profiles manually.
|
|
20
|
+
* @default true
|
|
21
|
+
*/
|
|
22
|
+
configureDataWedge?: boolean;
|
|
23
|
+
/**
|
|
24
|
+
* Capture input from scanners that act as a keyboard (HID / keyboard-wedge).
|
|
25
|
+
* Keystrokes are buffered and emitted as a single scan when Enter/Tab is
|
|
26
|
+
* received; the keys are swallowed so they don't interact with the UI.
|
|
27
|
+
* @default true
|
|
28
|
+
*/
|
|
29
|
+
captureKeyboard?: boolean;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
export type RaxonBarcodeScannerModuleEvents = {
|
|
33
|
+
onBarcodeScanned: (params: BarcodeScanPayload) => void;
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
export type UseBarcodeScannerResult = {
|
|
37
|
+
isListening: boolean;
|
|
38
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { NativeModule, requireNativeModule } from 'expo';
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
BarcodeScannerOptions,
|
|
5
|
+
RaxonBarcodeScannerModuleEvents,
|
|
6
|
+
} from './RaxonBarcodeScanner.types';
|
|
7
|
+
|
|
8
|
+
declare class RaxonBarcodeScannerModule extends NativeModule<RaxonBarcodeScannerModuleEvents> {
|
|
9
|
+
startListening(options?: BarcodeScannerOptions): void;
|
|
10
|
+
stopListening(): void;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export default requireNativeModule<RaxonBarcodeScannerModule>('RaxonBarcodeScanner');
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { registerWebModule, NativeModule } from 'expo';
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
BarcodeScannerOptions,
|
|
5
|
+
RaxonBarcodeScannerModuleEvents,
|
|
6
|
+
} from './RaxonBarcodeScanner.types';
|
|
7
|
+
|
|
8
|
+
class RaxonBarcodeScannerModule extends NativeModule<RaxonBarcodeScannerModuleEvents> {
|
|
9
|
+
startListening(_options?: BarcodeScannerOptions): void {
|
|
10
|
+
console.warn('raxon-barcode-scanner is only supported on Android.');
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
stopListening(): void {
|
|
14
|
+
// no-op
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export default registerWebModule(RaxonBarcodeScannerModule, 'RaxonBarcodeScanner');
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { useEffect, useRef } from 'react';
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
BarcodeScanPayload,
|
|
5
|
+
BarcodeScannerOptions,
|
|
6
|
+
UseBarcodeScannerResult,
|
|
7
|
+
} from './RaxonBarcodeScanner.types';
|
|
8
|
+
import RaxonBarcodeScanner from './RaxonBarcodeScannerModule';
|
|
9
|
+
|
|
10
|
+
export function useBarcodeScanner(
|
|
11
|
+
enabled: boolean,
|
|
12
|
+
onReadBarcode: (payload: BarcodeScanPayload) => void,
|
|
13
|
+
options?: BarcodeScannerOptions
|
|
14
|
+
): UseBarcodeScannerResult {
|
|
15
|
+
const onReadBarcodeRef = useRef(onReadBarcode);
|
|
16
|
+
|
|
17
|
+
useEffect(() => {
|
|
18
|
+
onReadBarcodeRef.current = onReadBarcode;
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
useEffect(() => {
|
|
22
|
+
if (!enabled) {
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
RaxonBarcodeScanner.startListening(options);
|
|
27
|
+
|
|
28
|
+
const subscription = RaxonBarcodeScanner.addListener('onBarcodeScanned', (event) => {
|
|
29
|
+
onReadBarcodeRef.current(event);
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
return () => {
|
|
33
|
+
subscription.remove();
|
|
34
|
+
RaxonBarcodeScanner.stopListening();
|
|
35
|
+
};
|
|
36
|
+
}, [
|
|
37
|
+
enabled,
|
|
38
|
+
options?.intentAction,
|
|
39
|
+
options?.profileName,
|
|
40
|
+
options?.configureDataWedge,
|
|
41
|
+
options?.captureKeyboard,
|
|
42
|
+
]);
|
|
43
|
+
|
|
44
|
+
return { isListening: enabled };
|
|
45
|
+
}
|