Files
scan-code-jssdk/src/services/provider/scan.js
2026-04-30 17:31:08 +08:00

393 lines
8.5 KiB
JavaScript

import { inRuntime, bridgeAsync } from "../bridge";
import { isSupportWebScan, startScanForWeb, stopScanForWeb, isSupportImageScan, startScanForImage, unlockScanBeep } from "../web";
import { isSupportWxScan, startScanForWx } from "../wx";
import { startScanner, stopScanner } from "../scanner";
import { getConfig } from "../config";
import { toAny } from "../../utils/toany";
let _scan_status = "ready";
let _scan_status_listener = null;
let _scan_listener_list = [];
let _scan_resolve = null;
let _scan_closing = false;
let _scan_next_start_time = 0;
const SCAN_RESTART_DELAY = 500;
function getScanRestartDelay() {
return toAny(getConfig("scanRestartDelay"), SCAN_RESTART_DELAY);
}
function __checkScanner() {
if (_scan_listener_list.length > 0) {
startScanner((result) => {
__scannerResult(result);
});
} else {
stopScanner();
}
}
function __match(result, match) {
let reg = null;
if (!!match && typeof match === "string") {
reg = new RegExp(match);
}
if (!!reg) {
return reg.test(result);
}
return true;
}
function __result(result) {
let matched = false;
for (let i = 0; i < _scan_listener_list.length; i++) {
const item = _scan_listener_list[i];
if (item.listener && __match(result, item.match)) {
matched = true;
item.listener({ result, key: item.key });
break;
}
}
if (matched) {
_scan_next_start_time = Date.now() + getScanRestartDelay();
}
return matched;
}
function __hasMatchedListener(result) {
for (let i = 0; i < _scan_listener_list.length; i++) {
const item = _scan_listener_list[i];
if (item.listener && __match(result, item.match)) {
return true;
}
}
return false;
}
function __scanning() {
if (_scan_status !== "scanning") {
_scan_status = "scanning";
if (_scan_status_listener) {
_scan_status_listener({ status: "scanning" });
}
}
}
function __closed() {
if (_scan_status !== "ready") {
_scan_status = "ready";
if (_scan_status_listener) {
_scan_status_listener({ status: "ready" });
}
}
}
function __finishScan() {
const resolve = _scan_resolve;
_scan_resolve = null;
__closed();
return resolve;
}
function __stopCurrentScan() {
if (inRuntime()) {
return bridgeAsync("stopScan").catch(() => {
// no thing
});
} else if (isSupportWebScan()) {
return stopScanForWeb().catch(() => {
// no thing
});
}
return Promise.resolve();
}
function __scannerResult(result) {
if (!__hasMatchedListener(result)) {
return;
}
if (isScanning()) {
const resolve = __finishScan();
_scan_closing = true;
__stopCurrentScan().then(() => {
setTimeout(() => {
_scan_closing = false;
}, 0);
});
__result(result);
resolve && resolve({
result
});
return;
}
__result(result);
}
function __startBridgeScan() {
return bridgeAsync("startScan", {
closeable: true
}).then(resp => {
if (!isScanning()) {
return resp;
}
if (!resp || !resp.result) {
return resp;
}
if (__result(resp.result)) {
return resp;
}
if (isScanning()) {
return __startBridgeScan();
}
return resp;
}).catch(err => {
if (!isScanning()) {
return err;
}
if (!err || !err.result) {
return err;
}
if (__result(err.result)) {
return err;
}
if (isScanning()) {
return __startBridgeScan();
}
return err;
});
}
function __startWxScan() {
return startScanForWx({
needResult: 1,
scanType: ["qrCode", "barCode"]
}).then(resp => {
if (!isScanning()) {
return resp;
}
if (!resp || !resp.result) {
return resp;
}
if (__result(resp.result)) {
return resp;
}
if (isScanning()) {
return __startWxScan();
}
return resp;
}).catch(err => {
if (!isScanning()) {
return err;
}
if (!err || !err.result) {
return err;
}
if (__result(err.result)) {
return err;
}
if (isScanning()) {
return __startWxScan();
}
return err;
});
}
function __startImageScan() {
return startScanForImage().then(resp => {
if (!isScanning()) {
return resp;
}
if (!resp || !resp.result) {
return resp;
}
if (__result(resp.result)) {
return resp;
}
if (isScanning()) {
return __startImageScan();
}
return resp;
}).catch(err => {
if (!isScanning()) {
return err;
}
if (!err || !err.result) {
return err;
}
if (__result(err.result)) {
return err;
}
if (isScanning()) {
return __startImageScan();
}
return err;
});
}
export function isScanning() {
return _scan_status === "scanning";
}
export function clear() {
for (let i = 0; i < _scan_listener_list.length; i++) {
const item = _scan_listener_list[i];
item.cancel();
}
_scan_listener_list.length = 0;
__checkScanner();
}
export function onScanListener(listener, key, match, level) {
if (!key || typeof key !== 'string') {
return;
}
if (typeof listener !== 'function') {
return;
}
let item = null;
for (let i = 0; i < _scan_listener_list.length; i++) {
const _i = _scan_listener_list[i];
if (_i.key === key) {
item = _i;
break;
}
}
if (item) {
item.level = level;
item.match = match;
item.listener = listener;
} else {
item = {
key,
match: match || "",
level: level || 0,
listener: listener,
cancel: () => {
const index = _scan_listener_list.indexOf(item);
if (index !== -1) {
const items = _scan_listener_list.splice(index, 1);
for (let i = 0; i < items.length; i++) {
const item = items[i];
item.listener && item.listener({ cancel: 1 });
}
}
}
};
_scan_listener_list.push(item);
}
// 根据level排序
_scan_listener_list.sort((a, b) => b.level - a.level);
__checkScanner();
return item;
}
export function offScanListener(listener) {
for (let i = 0; i < _scan_listener_list.length; i++) {
const _i = _scan_listener_list[i];
if (typeof listener === 'string') {
if (_i.key === listener) {
_i.cancel();
break;
}
} else if (_i.listener === listener) {
_i.cancel();
break;
}
}
__checkScanner();
}
export function setStatusListener(listener) {
if (typeof listener !== 'function') {
return;
}
_scan_status_listener = listener;
}
export function getStatus() {
return _scan_status;
}
export function stopScan() {
if (!isScanning()) {
return;
}
__stopCurrentScan().then(() => {
__closed();
});
}
export function startScan() {
if (isScanning() || _scan_closing || Date.now() < _scan_next_start_time) {
return;
}
Promise.resolve().then(() => {
__scanning();
let scannerPromise = new Promise(resolve => {
_scan_resolve = resolve;
});
let scanPromise = Promise.resolve();
if (inRuntime()) {
console.log("startScanForBridge");
scanPromise = __startBridgeScan();
} else if (isSupportWxScan()) {
console.log("startScanForWx");
scanPromise = __startWxScan();
} else if (isSupportWebScan()) {
console.log("startScanForWeb");
unlockScanBeep();
scanPromise = startScanForWeb(getConfig("webScanCanvasStyle"), __result);
} else if (isSupportImageScan()) {
console.log("startScanForImage");
scanPromise = __startImageScan();
} else {
console.log("Not support scanner");
}
return Promise.race([scanPromise, scannerPromise]);
}).finally(() => {
_scan_resolve = null;
__closed();
});
}
export function scanVideo() {
if (!isSupportWebScan()) {
console.log("Not support video scanner");
return;
}
if (isScanning() || _scan_closing || Date.now() < _scan_next_start_time) {
return;
}
unlockScanBeep();
Promise.resolve().then(() => {
__scanning();
return startScanForWeb(getConfig("webScanCanvasStyle"), __result).then(resp => {
if (resp && resp.result) {
__result(resp.result);
}
throw resp.error;
}).catch(err => { });
}).finally(() => {
__closed();
});
}
export function scanImage() {
if (!isSupportImageScan()) {
console.log("Not support image scanner");
return;
}
Promise.resolve().then(() => {
__scanning();
return startScanForImage().then(resp => {
if (resp && resp.result) {
__result(resp.result);
}
throw resp.error;
}).catch(err => { });
}).finally(() => {
__closed();
});
}