Files
uni-pda/utils/scan-android.js
2026-06-02 15:28:25 +08:00

172 lines
4.7 KiB
JavaScript

/**
* Android 系统扫码 API 实现
* 使用 android.device.ScanDevice + 广播监听
*/
// UTF8 字节数组解码为 Unicode 字符串
function utf8ByteToUnicodeStr(utf8Bytes) {
var unicodeStr = ''
for (var pos = 0; pos < utf8Bytes.length;) {
var flag = utf8Bytes[pos]
var unicode = 0
if ((flag >>> 7) === 0) {
unicodeStr += String.fromCharCode(utf8Bytes[pos])
pos += 1
} else if ((flag & 0xFC) === 0xFC) {
unicode = (utf8Bytes[pos] & 0x3) << 30
unicode |= (utf8Bytes[pos + 1] & 0x3F) << 24
unicode |= (utf8Bytes[pos + 2] & 0x3F) << 18
unicode |= (utf8Bytes[pos + 3] & 0x3F) << 12
unicode |= (utf8Bytes[pos + 4] & 0x3F) << 6
unicode |= (utf8Bytes[pos + 5] & 0x3F)
unicodeStr += String.fromCodePoint(unicode)
pos += 6
} else if ((flag & 0xF8) === 0xF8) {
unicode = (utf8Bytes[pos] & 0x7) << 24
unicode |= (utf8Bytes[pos + 1] & 0x3F) << 18
unicode |= (utf8Bytes[pos + 2] & 0x3F) << 12
unicode |= (utf8Bytes[pos + 3] & 0x3F) << 6
unicode |= (utf8Bytes[pos + 4] & 0x3F)
unicodeStr += String.fromCodePoint(unicode)
pos += 5
} else if ((flag & 0xF0) === 0xF0) {
unicode = (utf8Bytes[pos] & 0xF) << 18
unicode |= (utf8Bytes[pos + 1] & 0x3F) << 12
unicode |= (utf8Bytes[pos + 2] & 0x3F) << 6
unicode |= (utf8Bytes[pos + 3] & 0x3F)
unicodeStr += String.fromCodePoint(unicode)
pos += 4
} else if ((flag & 0xE0) === 0xE0) {
unicode = (utf8Bytes[pos] & 0x1F) << 12
unicode |= (utf8Bytes[pos + 1] & 0x3F) << 6
unicode |= (utf8Bytes[pos + 2] & 0x3F)
unicodeStr += String.fromCharCode(unicode)
pos += 3
} else if ((flag & 0xC0) === 0xC0) {
unicode = (utf8Bytes[pos] & 0x3F) << 6
unicode |= (utf8Bytes[pos + 1] & 0x3F)
unicodeStr += String.fromCharCode(unicode)
pos += 2
} else {
unicodeStr += String.fromCharCode(utf8Bytes[pos])
pos += 1
}
}
return unicodeStr
}
class ScanAndroidImpl {
constructor() {
this.scanDevice = null
this._receiver = null
this._filter = null
this._main = null
this._callback = null
this._isScanning = false
}
/**
* 初始化:打开扫描设备,设置广播模式
*/
init() {
// var ScanDeviceClass = plus.android.importClass('android.device.ScanDevice')
// this.scanDevice = new ScanDeviceClass()
// 使用 plus.android.newObject 创建实例(更兼容)
try {
this.scanDevice = plus.android.newObject('android.device.ScanDevice')
} catch (e) {
throw new Error('[Scan-Android] 当前设备不支持 android.device.ScanDevice,请切换到 iData 模式或使用其他扫码方式: ' + e.message)
}
this.scanDevice.openScan()
this.scanDevice.setOutScanMode(0) // 0 = 广播模式
this._main = plus.android.runtimeMainActivity()
var IntentFilter = plus.android.importClass('android.content.IntentFilter')
this._filter = new IntentFilter()
this._filter.addAction('scan.rcv.message')
}
/**
* 注册扫码结果回调
* @param {Function} callback - (codeStr: string) => void
*/
register(callback) {
this._callback = callback
var self = this
this._receiver = plus.android.implements('io.dcloud.feature.internal.reflect.BroadcastReceiver', {
onReceive: function (context, intent) {
plus.android.importClass(intent)
var code = intent.getByteArrayExtra('barocode')
if (code) {
var codeStr = utf8ByteToUnicodeStr(code)
console.log('[Scan-Android] 扫码结果:', codeStr)
self.scanDevice.stopScan()
self._isScanning = false
if (self._callback) {
self._callback(codeStr)
}
}
}
})
this._main.registerReceiver(this._receiver, this._filter)
}
/**
* 注销监听(页面卸载时调用)
*/
unregister() {
if (this._receiver && this._main) {
this._main.unregisterReceiver(this._receiver)
this._receiver = null
}
this._callback = null
}
/**
* 开始扫描
*/
startScan() {
if (this.scanDevice) {
this.scanDevice.stopScan()
this.scanDevice.startScan()
this._isScanning = true
}
}
/**
* 停止扫描
*/
stopScan() {
if (this.scanDevice) {
this.scanDevice.stopScan()
this._isScanning = false
}
}
/**
* 是否正在扫描
*/
isScanning() {
return this._isScanning
}
/**
* 完全销毁(应用退出时调用)
*/
destroy() {
this.unregister()
if (this.scanDevice) {
this.scanDevice.closeScan()
this.scanDevice = null
}
this._main = null
this._filter = null
}
}
export default ScanAndroidImpl