05d278f8f7
移动壳 HostBridge 能力失败日志只记录稳定阶段标签 更新 badge notification haptics network share navigation 失败测试断言 扩展移动壳配置门禁禁止能力日志打印原生 error 对象 补充 Expo 与 Tauri 宿主壳方案中的移动诊断日志边界
81 lines
2.3 KiB
TypeScript
81 lines
2.3 KiB
TypeScript
import { Share } from 'react-native';
|
|
|
|
import {
|
|
type HostBridgeError,
|
|
type HostBridgeRequest,
|
|
normalizeHostBridgeShareOpenPayload,
|
|
type ShareOpenPayload,
|
|
} from '../../../../packages/shared/src/contracts/hostBridge';
|
|
import { invalidRequest, ok } from './protocol';
|
|
|
|
let currentShareTarget: ShareOpenPayload | null = null;
|
|
|
|
function logMobileShareFailure(label: string, _error: unknown) {
|
|
console.warn(`mobile share failed for ${label}`);
|
|
}
|
|
|
|
export function setMobileHostBridgeShareTarget(request: HostBridgeRequest) {
|
|
const payload = request.payload;
|
|
const target =
|
|
payload && typeof payload === 'object'
|
|
? (payload as { target?: unknown }).target
|
|
: undefined;
|
|
if (target === undefined) {
|
|
throw invalidRequest('target is required');
|
|
}
|
|
const normalizedTarget = normalizeHostBridgeShareOpenPayload(target);
|
|
if (normalizedTarget.status !== 'valid') {
|
|
throw invalidRequest(
|
|
normalizedTarget.status === 'invalid'
|
|
? 'share target is invalid'
|
|
: 'share target is required',
|
|
);
|
|
}
|
|
|
|
currentShareTarget = normalizedTarget.payload;
|
|
return ok(request, true);
|
|
}
|
|
|
|
export function resetMobileHostBridgeShareTargetForTest() {
|
|
currentShareTarget = null;
|
|
}
|
|
|
|
export async function openShare(request: HostBridgeRequest) {
|
|
const explicitPayload = normalizeHostBridgeShareOpenPayload(request.payload);
|
|
if (explicitPayload.status === 'invalid') {
|
|
throw invalidRequest('share target is invalid');
|
|
}
|
|
|
|
const cachedPayload =
|
|
explicitPayload.status === 'valid'
|
|
? explicitPayload
|
|
: normalizeHostBridgeShareOpenPayload(currentShareTarget);
|
|
if (cachedPayload.status === 'invalid') {
|
|
throw invalidRequest('share target is invalid');
|
|
}
|
|
|
|
const sharePayload =
|
|
cachedPayload.status === 'valid' ? cachedPayload.payload : undefined;
|
|
if (!sharePayload) {
|
|
throw invalidRequest('share target is required');
|
|
}
|
|
|
|
const url = sharePayload?.url;
|
|
const message = [sharePayload?.message, url].filter(Boolean).join('\n');
|
|
|
|
try {
|
|
await Share.share({
|
|
title: sharePayload?.title,
|
|
message: message || url || sharePayload?.title || '',
|
|
url,
|
|
});
|
|
} catch (error) {
|
|
logMobileShareFailure('open.share', error);
|
|
throw {
|
|
code: 'host_error',
|
|
message: 'share unavailable',
|
|
} satisfies HostBridgeError;
|
|
}
|
|
return ok(request, true);
|
|
}
|