接入移动端原生扫码能力

新增 scanner.scanQrCode HostBridge 契约与二维码结果归一。

接入 Expo Camera 扫码 overlay 并保留 H5 浏览器扫码回退。

让 Tauri 白名单识别扫码 method 但不声明桌面扫码能力。

同步原生壳门禁、Expo 权限检查、方案文档和共享决策记录。
This commit is contained in:
2026-06-19 05:13:21 +08:00
parent a471e69455
commit e4b9cbf09d
26 changed files with 758 additions and 28 deletions
+32 -1
View File
@@ -73,6 +73,7 @@ import {
canUseNativeHostCapability,
type HostFileImportImageResult,
importHostImageFile,
scanHostQrCode,
} from '../../services/host-bridge/hostBridge';
import { shouldShowRechargeEntry } from '../../services/payment/paymentPlatform';
import type { CustomWorldProfile } from '../../types';
@@ -2595,6 +2596,9 @@ export function RpgEntryHomeView({
const [activeWorkSearchKeyword, setActiveWorkSearchKeyword] = useState('');
const [isQrScannerOpen, setIsQrScannerOpen] = useState(false);
const [qrScannerError, setQrScannerError] = useState<string | null>(null);
const [qrScannerMode, setQrScannerMode] = useState<'camera' | 'resultOnly'>(
'camera',
);
const [qrScannerResult, setQrScannerResult] = useState<string | null>(null);
const [selectedCategoryTag, setSelectedCategoryTag] = useState<string | null>(
null,
@@ -3160,7 +3164,32 @@ export function RpgEntryHomeView({
setQrScannerError(null);
setQrScannerResult(null);
setIsQrScannerOpen(true);
setQrScannerMode('camera');
void scanHostQrCode()
.then((result) => {
if (result === null) {
return;
}
if (result) {
setQrScannerMode('resultOnly');
setQrScannerResult(result.value);
setIsQrScannerOpen(true);
return;
}
setQrScannerMode('camera');
setIsQrScannerOpen(true);
})
.catch((error: unknown) => {
setQrScannerMode('resultOnly');
setQrScannerResult(null);
setQrScannerError(
error instanceof Error ? error.message : '扫码失败,请稍后重试',
);
setIsQrScannerOpen(true);
});
};
const clearWorkSearch = () => {
setActiveWorkSearchKeyword('');
@@ -4873,9 +4902,11 @@ export function RpgEntryHomeView({
const qrScannerModal: ReactNode = isQrScannerOpen ? (
<PlatformProfileQrScannerModal
error={qrScannerError}
mode={qrScannerMode}
result={qrScannerResult}
onClose={() => {
setIsQrScannerOpen(false);
setQrScannerMode('camera');
setQrScannerError(null);
setQrScannerResult(null);
}}