@@ -32,6 +32,7 @@ interface MiniProgramBridgeEnvelope {
3232
3333interface WechatMiniProgramRuntime {
3434 postMessage ?: ( params : { data : MiniProgramBridgeEnvelope } ) => void ;
35+ navigateTo ?: ( params : { url : string } ) => void ;
3536}
3637
3738interface WechatRuntime {
@@ -49,6 +50,7 @@ const BRIDGE_NAME = "HW_MINI_PAYMENT_BRIDGE";
4950const BRIDGE_GET_CAPABILITIES = "HW_MINI_BRIDGE_GET_CAPABILITIES" ;
5051const BRIDGE_REQUEST_PAYMENT = "HW_MINI_BRIDGE_REQUEST_PAYMENT" ;
5152const BRIDGE_RESPONSE_TYPE = "HW_MINI_BRIDGE_RESPONSE" ;
53+ const WECHAT_JSSDK_SRC = "https://res.wx.qq.com/open/js/jweixin-1.6.0.js" ;
5254
5355const CAPABILITIES_TIMEOUT_MS = 5_000 ;
5456const REQUEST_PAYMENT_TIMEOUT_MS = 35_000 ;
@@ -62,6 +64,7 @@ const pendingBridgeRequests = new Map<
6264> ( ) ;
6365
6466let messageListenerBound = false ;
67+ let wechatJSSDKLoadPromise : Promise < void > | null = null ;
6568
6669const isObject = ( value : unknown ) : value is Record < string , unknown > =>
6770 typeof value === "object" && value !== null ;
@@ -201,6 +204,74 @@ const bindMiniProgramMessageListener = () => {
201204 messageListenerBound = true ;
202205} ;
203206
207+ const isWeChatUserAgent = ( ) => {
208+ if ( typeof window === "undefined" ) {
209+ return false ;
210+ }
211+
212+ return window . navigator . userAgent . toLowerCase ( ) . includes ( "micromessenger" ) ;
213+ } ;
214+
215+ const ensureWechatJSSDK = async ( ) => {
216+ if ( typeof window === "undefined" || typeof document === "undefined" ) {
217+ return ;
218+ }
219+
220+ if ( ! isWeChatUserAgent ( ) ) {
221+ return ;
222+ }
223+
224+ if ( typeof window . wx ?. miniProgram ?. postMessage === "function" ) {
225+ return ;
226+ }
227+
228+ if ( wechatJSSDKLoadPromise ) {
229+ return wechatJSSDKLoadPromise ;
230+ }
231+
232+ wechatJSSDKLoadPromise = new Promise < void > ( ( resolve , reject ) => {
233+ const existingScript = document . querySelector (
234+ `script[src="${ WECHAT_JSSDK_SRC } "]` ,
235+ ) as HTMLScriptElement | null ;
236+
237+ if ( existingScript ) {
238+ if (
239+ existingScript . dataset . hwLoaded === "true" ||
240+ typeof window . wx !== "undefined"
241+ ) {
242+ resolve ( ) ;
243+ return ;
244+ }
245+ existingScript . addEventListener ( "load" , ( ) => resolve ( ) , {
246+ once : true ,
247+ } ) ;
248+ existingScript . addEventListener (
249+ "error" ,
250+ ( ) => reject ( new Error ( "Failed to load WeChat JSSDK" ) ) ,
251+ { once : true } ,
252+ ) ;
253+ return ;
254+ }
255+
256+ const script = document . createElement ( "script" ) ;
257+ script . src = WECHAT_JSSDK_SRC ;
258+ script . async = true ;
259+ script . onload = ( ) => {
260+ script . dataset . hwLoaded = "true" ;
261+ resolve ( ) ;
262+ } ;
263+ script . onerror = ( ) => reject ( new Error ( "Failed to load WeChat JSSDK" ) ) ;
264+ document . head . appendChild ( script ) ;
265+ } ) ;
266+
267+ try {
268+ await wechatJSSDKLoadPromise ;
269+ } catch ( error ) {
270+ wechatJSSDKLoadPromise = null ;
271+ throw error ;
272+ }
273+ } ;
274+
204275const callMiniProgramBridge = < TResult > ( params : {
205276 type : string ;
206277 payload ?: unknown ;
@@ -316,29 +387,23 @@ export const buildWechatPaymentClientContext =
316387 return { environmentType } ;
317388 }
318389
319- const bridge = ensureWechatMiniProgramBridge ( ) ;
320- if ( ! bridge ?. getCapabilities ) {
321- return {
322- environmentType,
323- miniProgramBridgeSupported : false ,
324- } ;
325- }
326-
327390 try {
328- const capabilities = await bridge . getCapabilities ( ) ;
329- return {
330- environmentType,
331- miniProgramBridgeSupported :
332- capabilities . supportsRequestPayment === true ,
333- miniProgramBridgeVersion : capabilities . bridgeVersion ,
334- shellVersion : capabilities . shellVersion ,
335- } ;
336- } catch {
337- return {
338- environmentType,
339- miniProgramBridgeSupported : false ,
340- } ;
391+ await ensureWechatJSSDK ( ) ;
392+ } catch ( error ) {
393+ console . warn ( "WeChat JSSDK init failed" , error ) ;
341394 }
395+
396+ // Use navigateTo detection instead of postMessage-based capability
397+ // handshake, since postMessage only delivers on web-view back/share
398+ // and cannot be used for real-time communication.
399+ const hasNavigateTo =
400+ typeof window . wx ?. miniProgram ?. navigateTo === "function" ;
401+
402+ return {
403+ environmentType,
404+ miniProgramBridgeSupported : hasNavigateTo ,
405+ miniProgramBridgeVersion : hasNavigateTo ? "1.3.0" : undefined ,
406+ } ;
342407 } ;
343408
344409export const buildWechatPaymentClientContextQuery = (
0 commit comments