@@ -8,6 +8,7 @@ import {
|
||||
interface MiniProgramBridge {
|
||||
getEnv?: (callback: (result: { miniprogram?: boolean }) => void) => void
|
||||
navigateTo?: (options: { url: string; success?: () => void; fail?: (error: { errMsg?: string }) => void }) => void
|
||||
navigateBack?: (options: { delta?: number; success?: () => void; fail?: (error: { errMsg?: string }) => void }) => void
|
||||
}
|
||||
|
||||
export type WechatMiniProgramBridgeResult =
|
||||
@@ -15,6 +16,11 @@ export type WechatMiniProgramBridgeResult =
|
||||
| { status: 'not-embedded' }
|
||||
| { status: 'failed'; reason: 'invalid-target' | 'bridge-unavailable' | 'not-in-mini-program' | 'navigation-failed' | 'page-not-found' | 'timeout' }
|
||||
|
||||
export type WechatMiniProgramReturnResult =
|
||||
| { status: 'returned' }
|
||||
| { status: 'not-embedded' }
|
||||
| { status: 'failed'; reason: 'bridge-unavailable' | 'not-in-mini-program' | 'navigation-failed' | 'timeout' }
|
||||
|
||||
const SDK_URL = 'https://res.wx.qq.com/open/js/jweixin-1.3.2.js'
|
||||
const BRIDGE_WAIT_TIMEOUT = 2500
|
||||
const BRIDGE_POLL_INTERVAL = 50
|
||||
@@ -22,6 +28,7 @@ const GET_ENV_TIMEOUT = 1500
|
||||
const NAVIGATION_TIMEOUT = 3000
|
||||
|
||||
let pendingNavigation: Promise<WechatMiniProgramBridgeResult> | null = null
|
||||
let pendingReturn: Promise<WechatMiniProgramReturnResult> | null = null
|
||||
let sdkLoadPromise: Promise<void> | null = null
|
||||
|
||||
const getBridge = (): MiniProgramBridge | null => {
|
||||
@@ -108,6 +115,31 @@ const navigateToHostLocationPage = (bridge: MiniProgramBridge, target: WechatOpe
|
||||
}
|
||||
})
|
||||
|
||||
const navigateBackToHostPage = (bridge: MiniProgramBridge) => new Promise<WechatMiniProgramReturnResult>((resolve) => {
|
||||
if (!bridge.navigateBack) return resolve({ status: 'failed', reason: 'bridge-unavailable' })
|
||||
let settled = false
|
||||
const finish = (result: WechatMiniProgramReturnResult) => {
|
||||
if (settled) return
|
||||
settled = true
|
||||
clearTimeout(timeout)
|
||||
resolve(result)
|
||||
}
|
||||
const timeout = setTimeout(() => finish({ status: 'failed', reason: 'timeout' }), NAVIGATION_TIMEOUT)
|
||||
try {
|
||||
bridge.navigateBack({
|
||||
delta: 1,
|
||||
success: () => finish({ status: 'returned' }),
|
||||
fail: (error) => {
|
||||
console.error('返回微信小程序失败:', error)
|
||||
finish({ status: 'failed', reason: 'navigation-failed' })
|
||||
}
|
||||
})
|
||||
} catch (error) {
|
||||
console.error('调用微信小程序返回桥接失败:', error)
|
||||
finish({ status: 'failed', reason: 'navigation-failed' })
|
||||
}
|
||||
})
|
||||
|
||||
const openOnce = async (target: WechatOpenLocationTarget): Promise<WechatMiniProgramBridgeResult> => {
|
||||
const validation = validateWechatOpenLocationTarget(target)
|
||||
if (!validation.ok) return { status: 'failed', reason: 'invalid-target' }
|
||||
@@ -118,8 +150,22 @@ const openOnce = async (target: WechatOpenLocationTarget): Promise<WechatMiniPro
|
||||
return navigateToHostLocationPage(bridge, validation.value)
|
||||
}
|
||||
|
||||
const returnOnce = async (): Promise<WechatMiniProgramReturnResult> => {
|
||||
if (!isEmbeddedInWechatMiniProgram()) return { status: 'not-embedded' }
|
||||
const bridge = await waitForBridge()
|
||||
if (!bridge) return { status: 'failed', reason: 'bridge-unavailable' }
|
||||
if (!await isMiniProgramWebView(bridge)) return { status: 'failed', reason: 'not-in-mini-program' }
|
||||
return navigateBackToHostPage(bridge)
|
||||
}
|
||||
|
||||
export const openWechatMiniProgramLocation = (target: WechatOpenLocationTarget) => {
|
||||
if (pendingNavigation) return pendingNavigation
|
||||
pendingNavigation = openOnce(target).finally(() => { pendingNavigation = null })
|
||||
return pendingNavigation
|
||||
}
|
||||
|
||||
export const returnToWechatMiniProgram = () => {
|
||||
if (pendingReturn) return pendingReturn
|
||||
pendingReturn = returnOnce().finally(() => { pendingReturn = null })
|
||||
return pendingReturn
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user