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(); }); }