This commit is contained in:
iqudoo
2026-06-09 12:26:14 +08:00
parent fb3a4b4e06
commit 0b1b145b9c
6 changed files with 76 additions and 29 deletions

10
dist/index.d.ts vendored
View File

@@ -363,15 +363,17 @@ interface IScan {
*/ */
stopScan(): void; stopScan(): void;
/** /**
* 开启扫码 * 开启扫码(摄像头 / 桥接 / 微信等)
* @param key 可选,指定后结果仅分发给同 key 的 onScanListener
*/ */
startScan(): void; startScan(key?: string): void;
/** /**
* 选择图片进行识别 * 选择图片进行识别
* @param key 可选,指定后结果仅分发给同 key 的 onScanListener
*/ */
scanImage(): void; scanImage(key?: string): void;
/** 由业务/原生传入已选图片 File 识别WebView input.files 异常时使用) */ /** 由业务/原生传入已选图片 File 识别WebView input.files 异常时使用) */
scanImageFromFile(file: File | Blob): void; scanImageFromFile(file: File | Blob, key?: string): void;
/** /**
* 清除全部监听 * 清除全部监听
*/ */

2
dist/index.js vendored

File diff suppressed because one or more lines are too long

View File

@@ -120,7 +120,7 @@ function hydrateEmbedParams(params, messageSource, targetOrigin) {
return params.map(walk); return params.map(walk);
} }
function broadcastScanErrorToEmbedChildren(error) { function broadcastScanErrorToEmbedChildren(error, meta) {
if (embedChildSources.size === 0 || error == null || error === "") { if (embedChildSources.size === 0 || error == null || error === "") {
return; return;
} }
@@ -132,6 +132,7 @@ function broadcastScanErrorToEmbedChildren(error) {
v: EMBED_V, v: EMBED_V,
kind: "forwardScanError", kind: "forwardScanError",
error, error,
scanKey: meta && meta.scanKey,
}, },
"*" "*"
); );
@@ -153,6 +154,7 @@ function broadcastScanResultToEmbedChildren(result, meta) {
kind: "forwardScanResult", kind: "forwardScanResult",
result, result,
scanSource: meta && meta.source, scanSource: meta && meta.source,
scanKey: meta && meta.scanKey,
}, },
"*" "*"
); );
@@ -221,6 +223,7 @@ function embedChildOnMessage(ev) {
if (typeof data.result === "string") { if (typeof data.result === "string") {
const consumed = dispatchEmbedScanResult(data.result, { const consumed = dispatchEmbedScanResult(data.result, {
source: data.scanSource, source: data.scanSource,
scanKey: data.scanKey,
}); });
if (consumed && resolveUseParentProxy()) { if (consumed && resolveUseParentProxy()) {
window.parent.postMessage( window.parent.postMessage(
@@ -238,7 +241,9 @@ function embedChildOnMessage(ev) {
} }
if (data.kind === "forwardScanError") { if (data.kind === "forwardScanError") {
if (typeof data.error === "string") { if (typeof data.error === "string") {
dispatchEmbedScanError(data.error); dispatchEmbedScanError(data.error, {
scanKey: data.scanKey,
});
} }
return; return;
} }

View File

@@ -17,8 +17,8 @@ export function forwardEmbedScanResultIfNeeded(result, meta) {
} }
} }
export function forwardEmbedScanErrorIfNeeded(error) { export function forwardEmbedScanErrorIfNeeded(error, meta) {
if (embedScanErrorForwarder && error != null && error !== "") { if (embedScanErrorForwarder && error != null && error !== "") {
embedScanErrorForwarder(error); embedScanErrorForwarder(error, meta);
} }
} }

View File

@@ -27,6 +27,7 @@ let _scan_error_listener_list = [];
let _scan_resolve = null; let _scan_resolve = null;
let _scan_closing = false; let _scan_closing = false;
let _scan_next_start_time = 0; let _scan_next_start_time = 0;
let _scan_session_key = null;
let _embed_scan_host_enabled = false; let _embed_scan_host_enabled = false;
const SCAN_RESTART_DELAY = 500; const SCAN_RESTART_DELAY = 500;
@@ -160,6 +161,26 @@ function __match(result, match) {
return true; return true;
} }
function __resolveScanKey(meta) {
if (meta && meta.scanKey === null) {
return null;
}
if (meta && typeof meta.scanKey === "string" && meta.scanKey) {
return meta.scanKey;
}
if (meta && meta.source === "scanner") {
return null;
}
return _scan_session_key;
}
function __listenerMatches(item, result, scanKey) {
if (scanKey && item.key !== scanKey) {
return false;
}
return __match(result, item.match);
}
function __shouldSkipBeep(meta) { function __shouldSkipBeep(meta) {
if (meta && meta.skipBeep) { if (meta && meta.skipBeep) {
return true; return true;
@@ -186,11 +207,12 @@ function __isScanCancel(raw) {
function __result(result, meta) { function __result(result, meta) {
result = parseBarcodeString(result); result = parseBarcodeString(result);
forwardEmbedScanResultIfNeeded(result, meta); const scanKey = __resolveScanKey(meta);
forwardEmbedScanResultIfNeeded(result, Object.assign({}, meta, { scanKey }));
let matched = false; let matched = false;
for (let i = 0; i < _scan_listener_list.length; i++) { for (let i = 0; i < _scan_listener_list.length; i++) {
const item = _scan_listener_list[i]; const item = _scan_listener_list[i];
if (item.listener && __match(result, item.match)) { if (item.listener && __listenerMatches(item, result, scanKey)) {
matched = true; matched = true;
item.listener({ result, key: item.key }); item.listener({ result, key: item.key });
break; break;
@@ -226,11 +248,12 @@ function __scanError(raw, meta) {
if (!error) { if (!error) {
return false; return false;
} }
forwardEmbedScanErrorIfNeeded(error); const scanKey = __resolveScanKey(meta);
forwardEmbedScanErrorIfNeeded(error, Object.assign({}, meta, { scanKey }));
let matched = false; let matched = false;
for (let i = 0; i < _scan_error_listener_list.length; i++) { for (let i = 0; i < _scan_error_listener_list.length; i++) {
const item = _scan_error_listener_list[i]; const item = _scan_error_listener_list[i];
if (item.listener && __match(error, item.match)) { if (item.listener && __listenerMatches(item, error, scanKey)) {
matched = true; matched = true;
item.listener(Object.assign({ item.listener(Object.assign({
error, error,
@@ -267,16 +290,25 @@ function __notifyWebScanFailure(raw, meta) {
return notified; return notified;
} }
function __hasMatchedListener(result) { function __hasMatchedListener(result, meta) {
const scanKey = __resolveScanKey(meta);
for (let i = 0; i < _scan_listener_list.length; i++) { for (let i = 0; i < _scan_listener_list.length; i++) {
const item = _scan_listener_list[i]; const item = _scan_listener_list[i];
if (item.listener && __match(result, item.match)) { if (item.listener && __listenerMatches(item, result, scanKey)) {
return true; return true;
} }
} }
return false; return false;
} }
function __clearScanSessionKey() {
_scan_session_key = null;
}
function __beginScanSession(key) {
_scan_session_key = typeof key === "string" && key ? key : null;
}
function __scanning() { function __scanning() {
if (_scan_status !== "scanning") { if (_scan_status !== "scanning") {
_scan_status = "scanning"; _scan_status = "scanning";
@@ -329,9 +361,9 @@ export function dispatchEmbedScanResult(raw, meta) {
* 父页通过 postMessage 将识别错误投递到嵌入 iframe 时调用。 * 父页通过 postMessage 将识别错误投递到嵌入 iframe 时调用。
* @returns {boolean} 是否有监听消费了该错误 * @returns {boolean} 是否有监听消费了该错误
*/ */
export function dispatchEmbedScanError(raw) { export function dispatchEmbedScanError(raw, meta) {
const error = normalizeScanError(raw); const error = normalizeScanError(raw);
return __scanError(error, { source: "image" }); return __scanError(error, Object.assign({ source: "image" }, meta || {}));
} }
/** /**
@@ -355,7 +387,7 @@ export function acknowledgeEmbedScanConsumed(raw) {
} }
function __scannerResult(result, meta) { function __scannerResult(result, meta) {
if (!__hasMatchedListener(result)) { if (!__hasMatchedListener(result, meta)) {
return __result(result, meta); return __result(result, meta);
} }
if (isScanning()) { if (isScanning()) {
@@ -458,7 +490,7 @@ function __startWebScan(useImageScan = false) {
} }
return resp; return resp;
} }
__result(resp.result); __result(resp.result, { source: "web" });
return resp; return resp;
}).catch(err => { }).catch(err => {
if (!isScanning()) { if (!isScanning()) {
@@ -495,7 +527,7 @@ function __startImageScan() {
__notifyImageScanFailure(resp); __notifyImageScanFailure(resp);
return resp; return resp;
} }
__result(resp.result); __result(resp.result, { source: "image" });
return resp; return resp;
}).catch(err => { }).catch(err => {
if (!isScanning()) { if (!isScanning()) {
@@ -505,7 +537,7 @@ function __startImageScan() {
return err; return err;
} }
if (err && err.result) { if (err && err.result) {
__result(err.result); __result(err.result, { source: "image" });
return err; return err;
} }
__notifyImageScanFailure(err); __notifyImageScanFailure(err);
@@ -686,12 +718,13 @@ export function stopScan() {
}); });
} }
export function startScan() { export function startScan(key) {
if (isScanning() || _scan_closing || Date.now() < _scan_next_start_time) { if (isScanning() || _scan_closing || Date.now() < _scan_next_start_time) {
return; return;
} }
unlockScanBeep(); unlockScanBeep();
Promise.resolve().then(() => { Promise.resolve().then(() => {
__beginScanSession(key);
__scanning(); __scanning();
let scannerPromise = new Promise(resolve => { let scannerPromise = new Promise(resolve => {
_scan_resolve = resolve; _scan_resolve = resolve;
@@ -711,11 +744,12 @@ export function startScan() {
return withScanSessionTimeout(Promise.race([scanPromise, scannerPromise])); return withScanSessionTimeout(Promise.race([scanPromise, scannerPromise]));
}).finally(() => { }).finally(() => {
_scan_resolve = null; _scan_resolve = null;
__clearScanSessionKey();
__closed(); __closed();
}); });
} }
export function scanImage() { export function scanImage(key) {
if (!isSupportImageScan()) { if (!isSupportImageScan()) {
printDebug("Not support image scanner"); printDebug("Not support image scanner");
return; return;
@@ -724,6 +758,7 @@ export function scanImage() {
return; return;
} }
unlockScanBeep(); unlockScanBeep();
__beginScanSession(key);
__scanning(); __scanning();
withScanSessionTimeout(__startImageScan()).catch(err => { withScanSessionTimeout(__startImageScan()).catch(err => {
if (err && err.cancel) { if (err && err.cancel) {
@@ -731,12 +766,13 @@ export function scanImage() {
} }
__notifyImageScanFailure(err); __notifyImageScanFailure(err);
}).finally(() => { }).finally(() => {
__clearScanSessionKey();
__closed(); __closed();
}); });
} }
/** 由原生/业务传入已选图片 File避免 WebView 无法从 input.files 取文件 */ /** 由原生/业务传入已选图片 File避免 WebView 无法从 input.files 取文件 */
export function scanImageFromFile(file) { export function scanImageFromFile(file, key) {
if (!isSupportImageScan()) { if (!isSupportImageScan()) {
printDebug("Not support image scanner"); printDebug("Not support image scanner");
return; return;
@@ -746,6 +782,7 @@ export function scanImageFromFile(file) {
} }
unlockScanBeep(); unlockScanBeep();
cleanupWebScanResiduals(); cleanupWebScanResiduals();
__beginScanSession(key);
__scanning(); __scanning();
withScanSessionTimeout( withScanSessionTimeout(
detectImageFileForScan(file).then(resp => { detectImageFileForScan(file).then(resp => {
@@ -759,7 +796,7 @@ export function scanImageFromFile(file) {
__notifyImageScanFailure(resp); __notifyImageScanFailure(resp);
return resp; return resp;
} }
__result(resp.result); __result(resp.result, { source: "image" });
return resp; return resp;
}) })
).catch(err => { ).catch(err => {
@@ -768,6 +805,7 @@ export function scanImageFromFile(file) {
} }
__notifyImageScanFailure(err); __notifyImageScanFailure(err);
}).finally(() => { }).finally(() => {
__clearScanSessionKey();
__closed(); __closed();
}); });
} }

10
types/index.d.ts vendored
View File

@@ -363,15 +363,17 @@ interface IScan {
*/ */
stopScan(): void; stopScan(): void;
/** /**
* 开启扫码 * 开启扫码(摄像头 / 桥接 / 微信等)
* @param key 可选,指定后结果仅分发给同 key 的 onScanListener
*/ */
startScan(): void; startScan(key?: string): void;
/** /**
* 选择图片进行识别 * 选择图片进行识别
* @param key 可选,指定后结果仅分发给同 key 的 onScanListener
*/ */
scanImage(): void; scanImage(key?: string): void;
/** 由业务/原生传入已选图片 File 识别WebView input.files 异常时使用) */ /** 由业务/原生传入已选图片 File 识别WebView input.files 异常时使用) */
scanImageFromFile(file: File | Blob): void; scanImageFromFile(file: File | Blob, key?: string): void;
/** /**
* 清除全部监听 * 清除全部监听
*/ */