init commit

This commit is contained in:
iqudoo
2026-04-30 17:31:08 +08:00
parent 46da9edfb4
commit 1215b6eea6
11 changed files with 132 additions and 37 deletions

View File

@@ -238,7 +238,7 @@ IScan.offScanListener("order");
listener.cancel();
```
### `getStatus(): "scanning" | "closed"`
### `getStatus(): "scanning" | "ready"`
获取当前扫码状态。
@@ -301,7 +301,7 @@ interface ScanResult {
key: string;
}
type ScanStatus = "scanning" | "closed";
type ScanStatus = "scanning" | "ready";
type ScanResultCallback = (result: ScanResult) => any;
type ScanStatusCallback = (status: ScanStatus) => any;

File diff suppressed because one or more lines are too long

View File

@@ -4,7 +4,7 @@
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no" />
<title>IScan Demo</title>
<title>IScan</title>
<script src="https://cdn.jsdelivr.net/npm/vconsole@3.12.0/dist/vconsole.min.js"></script>
<script>
var vconsole = new VConsole();
@@ -332,24 +332,20 @@ IScan.stopScan();</pre>
}
function stopScan() {
hide();
IScan.stopScan();
setStatus(IScan.getStatus());
}
function startScan() {
hide();
IScan.startScan();
setStatus(IScan.getStatus());
}
function scanImage() {
hide();
IScan.scanImage();
}
function scanVideo() {
hide();
IScan.scanVideo();
}

6
dist/index.d.ts vendored
View File

@@ -2,6 +2,10 @@
* 扫码初始化选项
*/
interface ScanConfigOptions {
/**
* 扫码重启延迟单位毫秒默认500ms
*/
scanRestartDelay?: number,
/**
* 桥接是否启用,默认启用
*/
@@ -138,7 +142,7 @@ interface ScanListenerInfo {
/**
* 监听状态
*/
type ScanStatus = "scanning" | "closed";
type ScanStatus = "scanning" | "ready";
/**
* 监听结果回调

6
dist/index.html vendored
View File

@@ -1,4 +1,4 @@
<!doctype html><html lang="zh-CN"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,minimum-scale=1,maximum-scale=1,user-scalable=no"/><title>IScan Demo</title><script src="https://cdn.jsdelivr.net/npm/vconsole@3.12.0/dist/vconsole.min.js"></script><script>var vconsole = new VConsole();</script><style>* {
<!doctype html><html lang="zh-CN"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,minimum-scale=1,maximum-scale=1,user-scalable=no"/><title>IScan</title><script src="https://cdn.jsdelivr.net/npm/vconsole@3.12.0/dist/vconsole.min.js"></script><script>var vconsole = new VConsole();</script><style>* {
box-sizing: border-box;
}
@@ -262,24 +262,20 @@ IScan.stopScan();</pre></section></main><script>(function () {
}
function stopScan() {
hide();
IScan.stopScan();
setStatus(IScan.getStatus());
}
function startScan() {
hide();
IScan.startScan();
setStatus(IScan.getStatus());
}
function scanImage() {
hide();
IScan.scanImage();
}
function scanVideo() {
hide();
IScan.scanVideo();
}

2
dist/index.js vendored

File diff suppressed because one or more lines are too long

Binary file not shown.

View File

@@ -1,17 +1,22 @@
import { inRuntime, bridgeAsync } from "../bridge";
import { isSupportWebScan, startScanForWeb, stopScanForWeb, isSupportImageScan, startScanForImage } from "../web";
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 = "closed";
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 = 2000;
const SCAN_RESTART_DELAY = 500;
function getScanRestartDelay() {
return toAny(getConfig("scanRestartDelay"), SCAN_RESTART_DELAY);
}
function __checkScanner() {
if (_scan_listener_list.length > 0) {
@@ -46,7 +51,7 @@ function __result(result) {
}
}
if (matched) {
_scan_next_start_time = Date.now() + SCAN_RESTART_DELAY;
_scan_next_start_time = Date.now() + getScanRestartDelay();
}
return matched;
}
@@ -71,10 +76,10 @@ function __scanning() {
}
function __closed() {
if (_scan_status !== "closed") {
_scan_status = "closed";
if (_scan_status !== "ready") {
_scan_status = "ready";
if (_scan_status_listener) {
_scan_status_listener({ status: "closed" });
_scan_status_listener({ status: "ready" });
}
}
}
@@ -332,6 +337,7 @@ export function startScan() {
scanPromise = __startWxScan();
} else if (isSupportWebScan()) {
console.log("startScanForWeb");
unlockScanBeep();
scanPromise = startScanForWeb(getConfig("webScanCanvasStyle"), __result);
} else if (isSupportImageScan()) {
console.log("startScanForImage");
@@ -351,6 +357,10 @@ export function scanVideo() {
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 => {

View File

@@ -1,5 +1,5 @@
let _scannerCallback = null;
let _scannerStatus = "closed";
let _scannerStatus = "ready";
let _scannerValue = "";
let _scannerTimer = null;
let _scannerLastInputTime = 0;
@@ -82,7 +82,7 @@ export function stopScanner(){
if (_scannerStatus !== "scanning") {
return;
}
_scannerStatus = "closed";
_scannerStatus = "ready";
_scannerCallback = null;
clearScannerValue();
window.removeEventListener("keydown", onScannerKeydown);

View File

@@ -5,17 +5,25 @@ import scanBeepAudio from "../../../res/scan_beep.ogg";
const scanWeb = {
uuid: null,
finish: true
finish: true,
stream: null,
videoEl: null
}
const DEFAULT_SCAN_BEEP_AUDIO = scanBeepAudio;
const ZXING_READER_WASM_URL = "./lib/reader.wasm";
let barcodeDetectorPreparePromise = null;
let scanBeepAudioEl = null;
let scanBeepAudioSrc = null;
let scanBeepUnlocked = false;
function removeEl(id) {
function removeEl(id, uuid) {
try {
let el = document.getElementById(id);
if (uuid && el && el.uuid !== uuid) {
return;
}
document.body.removeChild(el);
} catch (error) {
}
@@ -32,6 +40,32 @@ function createEl(tagName, id, style, appendChild) {
return el;
}
function stopMediaStream(stream) {
try {
const tracks = stream && stream.getTracks && stream.getTracks();
if (tracks && tracks.length) {
for (let i = 0; i < tracks.length; i++) {
tracks[i].stop();
}
}
} catch (e) {
}
}
function stopActiveWebScan() {
scanWeb.uuid = null;
stopMediaStream(scanWeb.stream);
try {
if (scanWeb.videoEl) {
scanWeb.videoEl.pause && scanWeb.videoEl.pause();
scanWeb.videoEl.srcObject = null;
}
} catch (e) {
}
scanWeb.stream = null;
scanWeb.videoEl = null;
}
function transformPoint(point, width, height, mirrorHorizontal, mirrorVertical, cover) {
let x = point.x;
let y = point.y;
@@ -206,12 +240,14 @@ function playScanBeep() {
if (getConfig("webScanBeepEnabled") === false) {
return;
}
const audioSrc = getConfig("webScanBeepAudio") || DEFAULT_SCAN_BEEP_AUDIO;
if (!audioSrc || typeof Audio === 'undefined') {
const audio = getScanBeepAudio();
if (!audio) {
return;
}
try {
const audio = new Audio(audioSrc);
audio.muted = false;
audio.volume = 1;
audio.currentTime = 0;
const playPromise = audio.play();
playPromise && playPromise.catch && playPromise.catch(() => {
// no thing
@@ -220,12 +256,45 @@ function playScanBeep() {
}
}
function getScanBeepAudio() {
const audioSrc = getConfig("webScanBeepAudio") || DEFAULT_SCAN_BEEP_AUDIO;
if (!audioSrc || typeof Audio === 'undefined') {
return null;
}
if (!scanBeepAudioEl || scanBeepAudioSrc !== audioSrc) {
scanBeepAudioSrc = audioSrc;
scanBeepUnlocked = false;
scanBeepAudioEl = new Audio(audioSrc);
scanBeepAudioEl.preload = "auto";
try {
scanBeepAudioEl.load && scanBeepAudioEl.load();
} catch (e) {
}
}
return scanBeepAudioEl;
}
export function unlockScanBeep() {
if (getConfig("webScanBeepEnabled") === false || scanBeepUnlocked) {
return;
}
const audio = getScanBeepAudio();
if (!audio) {
return;
}
try {
// 这里只做预加载,不主动 play避免部分浏览器露出提示音。
audio.load && audio.load();
scanBeepUnlocked = true;
} catch (e) {
}
}
export function isSupportWebScan() {
return typeof navigator !== 'undefined'
&& navigator.mediaDevices
&& navigator.mediaDevices.getUserMedia
&& !!getBarcodeDetectorClass()
&& getConfig("webCanvasEnabled") !== false;
&& !!getBarcodeDetectorClass();
}
export function isSupportImageScan() {
@@ -236,7 +305,7 @@ export function isSupportImageScan() {
export function stopScanForWeb() {
return Promise.resolve().then(() => {
scanWeb.uuid = null;
stopActiveWebScan();
})
}
@@ -319,8 +388,10 @@ export function startScanForImage() {
}
export function startScanForWeb(canvasStyle, onResult) {
let currentUuid = null;
return new Promise((resolve, reject) => {
try {
stopActiveWebScan();
scanWeb.uuid = createUUID();
scanWeb.finish = false;
let videoEl = createEl("video",
@@ -338,10 +409,11 @@ export function startScanForWeb(canvasStyle, onResult) {
let canvasDisplaySize = getCanvasDisplaySize(canvasEl, 300, 240);
canvasEl.style.display = "none";
let context = canvasEl.getContext("2d");
let currentUuid = scanWeb.uuid;
currentUuid = scanWeb.uuid;
videoEl.width = 300;
videoEl.height = 300;
videoEl.uuid = scanWeb.uuid;
canvasEl.uuid = scanWeb.uuid;
createBarcodeDetector(getConfig("webScanType")).then(detector => {
return navigator.mediaDevices.getUserMedia({
video: {
@@ -356,6 +428,13 @@ export function startScanForWeb(canvasStyle, onResult) {
}).then(function (options) {
const detector = options.detector;
const stream = options.stream;
if (scanWeb.uuid !== currentUuid) {
stopMediaStream(stream);
reject({ cancel: 1 });
return;
}
scanWeb.stream = stream;
scanWeb.videoEl = videoEl;
const mirrorVideo = shouldMirrorWebVideo(stream);
const mirrorVideoVertical = shouldMirrorWebVideoVertical();
videoEl.srcObject = stream;
@@ -370,8 +449,14 @@ export function startScanForWeb(canvasStyle, onResult) {
return;
}
closed = true;
stopMediaStream(stream);
if (scanWeb.uuid === currentUuid || scanWeb.stream === stream) {
scanWeb.stream = null;
scanWeb.videoEl = null;
}
try {
stream.getTracks()[0].stop();
videoEl.pause && videoEl.pause();
videoEl.srcObject = null;
} catch (_e) { }
};
let tick = () => {
@@ -443,7 +528,7 @@ export function startScanForWeb(canvasStyle, onResult) {
reject({ error: e });
}
}).finally(() => {
removeEl("__webscan_video__");
removeEl("__webscan_canvas__");
removeEl("__webscan_video__", currentUuid);
removeEl("__webscan_canvas__", currentUuid);
})
}

6
types/index.d.ts vendored
View File

@@ -2,6 +2,10 @@
* 扫码初始化选项
*/
interface ScanConfigOptions {
/**
* 扫码重启延迟单位毫秒默认500ms
*/
scanRestartDelay?: number,
/**
* 桥接是否启用,默认启用
*/
@@ -138,7 +142,7 @@ interface ScanListenerInfo {
/**
* 监听状态
*/
type ScanStatus = "scanning" | "closed";
type ScanStatus = "scanning" | "ready";
/**
* 监听结果回调