Files
pda-overseas-uniapp/src/utils/scan-broadcast.js
T
2026-09-20 23:06:27 +08:00

116 lines
4.0 KiB
JavaScript

export const SCAN_BROADCAST_ACTION = 'android.intent.action.SCANRESULT'
export const SCAN_BROADCAST_EXTRA = 'value'
export const SCAN_BROADCAST_ACTIONS = Object.freeze([
SCAN_BROADCAST_ACTION,
'com.android.server.scannerservice.broadcast',
'com.sunmi.scanner.ACTION_DATA_CODE_RECEIVED'
])
const SCAN_BROADCAST_EXTRAS = Object.freeze(['value', 'data', 'barcode', 'SCAN_BARCODE1'])
const DUPLICATE_WINDOW_MS = 80
let receiver = null
let activity = null
let lastScan = { value: '', receivedAt: 0 }
export function normalizeScanValue(value) {
if (value === null || value === undefined) return ''
return String(value).trim()
}
export function isDuplicateScan(value, receivedAt = Date.now()) {
const duplicate = value === lastScan.value && receivedAt - lastScan.receivedAt < DUPLICATE_WINDOW_MS
if (!duplicate) lastScan = { value, receivedAt }
return duplicate
}
export function resetScanDeduplication() {
lastScan = { value: '', receivedAt: 0 }
}
export function startScanBroadcast({ onScan, onError } = {}) {
if (typeof onScan !== 'function') return () => {}
// #ifdef APP-PLUS
try {
if (receiver) stopScanBroadcast()
const registeredActivity = plus.android.runtimeMainActivity()
const IntentFilter = plus.android.importClass('android.content.IntentFilter')
const filter = new IntentFilter()
SCAN_BROADCAST_ACTIONS.forEach((action) => filter.addAction(action))
const registeredReceiver = plus.android.implements('io.dcloud.feature.internal.reflect.BroadcastReceiver', {
onReceive(context, intent) {
try {
plus.android.importClass(intent)
let rawValue = ''
for (const extra of SCAN_BROADCAST_EXTRAS) {
try {
const candidate = intent.getStringExtra(extra)
if (candidate !== null && candidate !== undefined && String(candidate).trim()) { rawValue = candidate; break }
} catch (_) {}
}
const value = normalizeScanValue(rawValue)
console.info('[Overseas PDA broadcast] received', { action: intent.getAction(), extras: SCAN_BROADCAST_EXTRAS, rawValue, value })
if (!value) { console.warn('[Overseas PDA broadcast] ignored empty value'); return }
if (isDuplicateScan(value)) { console.info('[Overseas PDA broadcast] ignored duplicate', { value }); return }
onScan(value)
} catch (error) {
console.error('[Overseas PDA broadcast] receive failed', { message: error.message })
if (typeof onError === 'function') onError(error)
}
}
})
const Build = plus.android.importClass('android.os.Build')
const sdkInt = Number(Build.VERSION.SDK_INT)
if (Build.VERSION.SDK_INT >= 33) {
const Context = plus.android.importClass('android.content.Context')
registeredActivity.registerReceiver(registeredReceiver, filter, Context.RECEIVER_EXPORTED)
} else {
registeredActivity.registerReceiver(registeredReceiver, filter)
}
activity = registeredActivity
receiver = registeredReceiver
let packageName = ''
try { packageName = String(registeredActivity.getPackageName()) } catch (_) {}
console.info('[Overseas PDA broadcast] receiver registered', {
actions: SCAN_BROADCAST_ACTIONS,
extras: SCAN_BROADCAST_EXTRAS,
packageName,
sdkInt,
exported: sdkInt >= 33
})
return () => stopRegisteredBroadcast(registeredActivity, registeredReceiver)
} catch (error) {
console.error('[Overseas PDA broadcast] registration failed', {
actions: SCAN_BROADCAST_ACTIONS,
extras: SCAN_BROADCAST_EXTRAS,
message: error?.message || String(error)
})
receiver = null
activity = null
if (typeof onError === 'function') onError(error)
}
// #endif
return stopScanBroadcast
}
function stopRegisteredBroadcast(registeredActivity, registeredReceiver) {
// #ifdef APP-PLUS
if (registeredActivity && registeredReceiver) {
try {
registeredActivity.unregisterReceiver(registeredReceiver)
} catch (_) {}
}
// #endif
if (activity !== registeredActivity || receiver !== registeredReceiver) return
receiver = null
activity = null
resetScanDeduplication()
}
export function stopScanBroadcast() {
stopRegisteredBroadcast(activity, receiver)
}