按宿主能力声明启用原生能力

HostBridge 契约沉淀 method 与 capability 白名单

H5 解析 hostCapabilities 并按能力调用原生桥

发布分享弹窗仅在声明 share.open 时显示系统分享

补充能力声明测试和宿主壳文档
This commit is contained in:
2026-06-18 00:48:13 +08:00
parent ee49c26868
commit 38ed2227d3
13 changed files with 194 additions and 35 deletions

View File

@@ -2,12 +2,14 @@ import type {
FileExportTextPayload,
FileExportTextResult,
HapticsImpactPayload,
HostBridgeCapability,
HostBridgeMethod,
HostBridgeRuntimeResult,
OpenExternalUrlPayload,
ShareOpenPayload,
} from '../../../packages/shared/src/contracts/hostBridge';
import {
isHostBridgeCapability,
normalizeHostBridgeExternalUrl,
} from '../../../packages/shared/src/contracts/hostBridge';
import type {
@@ -34,6 +36,7 @@ export type HostRuntimeSnapshot = {
hostShell: string | null;
hostPlatform: string | null;
hostVersion: string | null;
hostCapabilities: HostBridgeCapability[];
miniProgramEnv: string | null;
};
@@ -103,6 +106,17 @@ async function requestNativeHostBoolean(
}
}
function runtimeHasNativeCapability(
capability: HostBridgeCapability,
context: HostRuntimeContext = {},
) {
const runtime = getHostRuntime(context);
return (
runtime.kind === 'native_app' &&
runtime.hostCapabilities.includes(capability)
);
}
function resolveLocation(context: HostRuntimeContext) {
return (
context.location ?? (typeof window !== 'undefined' ? window.location : null)
@@ -157,6 +171,10 @@ export function resolveHostRuntime(
const hostShell = params.get('hostShell');
const hostPlatform = params.get('hostPlatform');
const hostVersion = params.get('hostVersion');
const hostCapabilities = (params.get('hostCapabilities') ?? '')
.split(',')
.map((capability) => capability.trim())
.filter(isHostBridgeCapability);
const miniProgramEnv = params.get('miniProgramEnv');
const navigatorLike = resolveNavigator(context);
const wxBridge = resolveWxBridge(context);
@@ -176,6 +194,7 @@ export function resolveHostRuntime(
hostShell,
hostPlatform,
hostVersion,
hostCapabilities,
miniProgramEnv,
};
}
@@ -193,6 +212,7 @@ export function resolveHostRuntime(
hostShell,
hostPlatform,
hostVersion,
hostCapabilities,
miniProgramEnv,
};
}
@@ -204,6 +224,7 @@ export function resolveHostRuntime(
hostShell,
hostPlatform,
hostVersion,
hostCapabilities,
miniProgramEnv,
};
}
@@ -222,6 +243,13 @@ export function isNativeAppRuntime(context: HostRuntimeContext = {}) {
return resolveHostRuntime(context).kind === 'native_app';
}
export function canUseNativeHostCapability(
capability: HostBridgeCapability,
context: HostRuntimeContext = {},
) {
return runtimeHasNativeCapability(capability, context);
}
export function loadWechatMiniProgramBridge(
errorMessage = '请在微信小程序内完成操作',
) {
@@ -303,6 +331,9 @@ export async function navigateHostNativePage(
) {
const runtime = getHostRuntime();
if (runtime.kind === 'native_app') {
if (!runtime.hostCapabilities.includes('navigation.openNativePage')) {
return false;
}
const result = await requestNativeHostBoolean(
'navigation.openNativePage',
{ url },
@@ -325,6 +356,9 @@ export async function navigateHostNativePage(
export async function requestHostLogin() {
if (getHostRuntime().kind === 'native_app') {
if (!canUseNativeHostCapability('auth.requestLogin')) {
return false;
}
return await requestNativeHostBoolean('auth.requestLogin');
}
@@ -343,6 +377,9 @@ export async function requestHostPayment({
}: HostPaymentRequest) {
const runtime = getHostRuntime();
if (runtime.kind === 'native_app') {
if (!runtime.hostCapabilities.includes('payment.request')) {
return false;
}
return await requestNativeHostBoolean('payment.request', {
payload,
orderId,
@@ -452,6 +489,9 @@ export async function openWechatMiniProgramShareGridPage(
export function setHostShareTarget(message: unknown) {
if (getHostRuntime().kind === 'native_app') {
if (!canUseNativeHostCapability('share.setTarget')) {
return false;
}
void requestNativeAppHostBridge('share.setTarget', {
target: message,
}).catch(() => {
@@ -475,7 +515,7 @@ export function setHostShareTarget(message: unknown) {
}
export async function openHostShare(params: HostShareOpenRequest) {
if (getHostRuntime().kind !== 'native_app') {
if (!canUseNativeHostCapability('share.open')) {
return false;
}
@@ -487,7 +527,7 @@ export async function openHostShare(params: HostShareOpenRequest) {
}
export async function openHostExternalUrl({ url }: HostExternalUrlRequest) {
if (getHostRuntime().kind !== 'native_app') {
if (!canUseNativeHostCapability('app.openExternalUrl')) {
return false;
}
@@ -510,7 +550,7 @@ export function postWechatMiniProgramMessage(message: unknown) {
}
export async function getNativeAppHostRuntime() {
if (getHostRuntime().kind !== 'native_app') {
if (!canUseNativeHostCapability('host.getRuntime')) {
return null;
}
@@ -522,7 +562,7 @@ export async function getNativeAppHostRuntime() {
export async function writeHostClipboardText({
text,
}: HostClipboardWriteTextRequest) {
if (getHostRuntime().kind !== 'native_app') {
if (!canUseNativeHostCapability('clipboard.writeText')) {
return false;
}
@@ -536,7 +576,7 @@ export async function writeHostClipboardText({
export async function exportHostTextFile(
params: HostFileExportTextRequest,
) {
if (getHostRuntime().kind !== 'native_app') {
if (!canUseNativeHostCapability('file.exportText')) {
return false;
}
@@ -557,7 +597,7 @@ export async function exportHostTextFile(
export async function requestHostHapticsImpact(
params: HostHapticsImpactRequest = {},
) {
if (getHostRuntime().kind !== 'native_app') {
if (!canUseNativeHostCapability('haptics.impact')) {
return false;
}
@@ -570,7 +610,7 @@ export async function requestHostHapticsImpact(
export async function setHostAppTitle({ title }: HostAppTitleRequest) {
const normalizedTitle = title.trim();
if (!normalizedTitle || getHostRuntime().kind !== 'native_app') {
if (!normalizedTitle || !canUseNativeHostCapability('app.setTitle')) {
return false;
}