344 lines
7.3 KiB
JavaScript
344 lines
7.3 KiB
JavaScript
import { inRuntime, bridgeAsync } from "../bridge/appbridge";
|
|
import { isSupportWebScan, startScanForWeb, stopScanForWeb, isSupportImageScan, startScanForImage } from "../web";
|
|
import { isSupportWxScan, startScanForWx } from "../wx";
|
|
import { startScanner, stopScanner } from "../scanner";
|
|
import { getConfig } from "../config";
|
|
|
|
let _scan_status = "closed";
|
|
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 = 2000;
|
|
|
|
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() + SCAN_RESTART_DELAY;
|
|
}
|
|
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 !== "closed") {
|
|
_scan_status = "closed";
|
|
if (_scan_status_listener) {
|
|
_scan_status_listener({ status: "closed" });
|
|
}
|
|
}
|
|
}
|
|
|
|
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 (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.listener === listener) {
|
|
item = _i;
|
|
break;
|
|
}
|
|
}
|
|
if (item) {
|
|
item.key = key;
|
|
item.level = level;
|
|
item.match = match;
|
|
} else {
|
|
item = {
|
|
key,
|
|
match,
|
|
level,
|
|
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");
|
|
scanPromise = startScanForWeb(getConfig("webCanvasStyle"), __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();
|
|
});
|
|
} |