Skip to content

Commit 549182f

Browse files
authored
Merge pull request #21 from hackathonweekly/fix/miniprogram-webview-payment
fix(wechat): use navigateTo for mini program WebView payment
2 parents 46f8304 + a37aa35 commit 549182f

2 files changed

Lines changed: 91 additions & 32 deletions

File tree

‎apps/web/src/modules/public/events/components/PaymentModal.tsx‎

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@ import {
2828
type WechatPayPayload,
2929
type WechatPaymentChannel,
3030
} from "@community/lib-shared/payments/wechat-payment";
31-
import { ensureWechatMiniProgramBridge } from "./wechat-payment-client-context";
3231

3332
export interface PaymentOrderData {
3433
orderId: string;
@@ -129,21 +128,16 @@ const invokeMiniProgramBridgePay = async (
129128
);
130129
}
131130

132-
const requestPayment = ensureWechatMiniProgramBridge()?.requestPayment;
133-
if (!requestPayment) {
131+
const navigateTo = (window as any).wx?.miniProgram?.navigateTo;
132+
if (typeof navigateTo !== "function") {
134133
throw new WechatBridgeError(
135134
WECHAT_BRIDGE_ERROR_CODES.BRIDGE_NOT_SUPPORTED,
135+
"wx.miniProgram.navigateTo not available",
136136
);
137137
}
138138

139-
const result = await requestPayment(params);
140-
if (!result.ok) {
141-
const code =
142-
result.errCode === "PAY_CANCELLED"
143-
? WECHAT_BRIDGE_ERROR_CODES.PAY_CANCELLED
144-
: WECHAT_BRIDGE_ERROR_CODES.PAY_FAILED;
145-
throw new WechatBridgeError(code, result.errMsg);
146-
}
139+
const encodedParams = encodeURIComponent(JSON.stringify(params));
140+
navigateTo({ url: `/pages/pay/pay?params=${encodedParams}` });
147141
};
148142

149143
export function PaymentModal({

‎apps/web/src/modules/public/events/components/wechat-payment-client-context.ts‎

Lines changed: 86 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ interface MiniProgramBridgeEnvelope {
3232

3333
interface WechatMiniProgramRuntime {
3434
postMessage?: (params: { data: MiniProgramBridgeEnvelope }) => void;
35+
navigateTo?: (params: { url: string }) => void;
3536
}
3637

3738
interface WechatRuntime {
@@ -49,6 +50,7 @@ const BRIDGE_NAME = "HW_MINI_PAYMENT_BRIDGE";
4950
const BRIDGE_GET_CAPABILITIES = "HW_MINI_BRIDGE_GET_CAPABILITIES";
5051
const BRIDGE_REQUEST_PAYMENT = "HW_MINI_BRIDGE_REQUEST_PAYMENT";
5152
const 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

5355
const CAPABILITIES_TIMEOUT_MS = 5_000;
5456
const REQUEST_PAYMENT_TIMEOUT_MS = 35_000;
@@ -62,6 +64,7 @@ const pendingBridgeRequests = new Map<
6264
>();
6365

6466
let messageListenerBound = false;
67+
let wechatJSSDKLoadPromise: Promise<void> | null = null;
6568

6669
const 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+
204275
const 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

344409
export const buildWechatPaymentClientContextQuery = (

0 commit comments

Comments
 (0)