zhuli 3 недель назад
Родитель
Сommit
988ba1d133
1 измененных файлов с 149 добавлено и 63 удалено
  1. 149 63
      HBuilderProjects/shareIndex.html

+ 149 - 63
HBuilderProjects/shareIndex.html

@@ -475,13 +475,19 @@
 
 		#fabWrapWx.is-active {
 			display: block;
+			pointer-events: auto;
 		}
 
+		/* 开放标签宿主必须有明确宽高,否则微信内 Shadow 内容可能不占位、看起来像「没按钮」 */
 		#launch-btn {
 			display: block;
 			width: 100%;
 			max-width: 320px;
+			height: 48px;
+			min-height: 48px;
 			margin: 0 auto;
+			pointer-events: auto;
+			overflow: visible;
 		}
 
 		.fab {
@@ -1006,7 +1012,7 @@
 					}
 				</style>
 				<button class="wx-open-app-btn" aria-label="APP内打开">
-					<img src="https://test.ailien.shop/h5/HBuilderProjects/images/uBtn.png" alt="APP内打开" />
+					<img src="images/uBtn.png" alt="APP内打开" />
 				</button>
 			</script>
 		</wx-open-launch-app>
@@ -1054,6 +1060,8 @@
 		var WX_GET_CONFIG_SIGN_URL = 'https://test.ailien.shop/h5/HBuilderProjects/shareIndex.html';
 		/** wx.config 已成功(开放标签可展示);与「用户已成功唤起 App」不是同一回事 */
 		var weChatJssdkConfigured = false;
+		var wxConfigSignRetriedBaseUrl = false;
+		var wxSignUrlFullBeforeStrip = '';
 
 		/**
 		 * 关店(businessStatus=99)更多推荐:POST …/ai/multimodal-services/api/v1/search/global/store-recommend
@@ -1163,22 +1171,52 @@
 			return API_BASE.replace(/\/$/, '') + (custom.charAt(0) === '/' ? custom : '/' + custom);
 		}
 
+		/** 微信 JSSDK 参与签名的 url:完整链(含 ?),不含 # */
+		function getWxSignUrlFull() {
+			var forced = String(q('wxSignUrl') || '').trim();
+			if (forced) return forced.split('#')[0];
+			if (location.origin && /^https?:/i.test(location.origin)) {
+				return (
+					location.origin +
+					(location.pathname || '/h5/HBuilderProjects/shareIndex.html') +
+					(location.search || '')
+				);
+			}
+			var href = String(location.href || '').split('#')[0];
+			if (href && href.indexOf('file:') !== 0) return href;
+			return WX_GET_CONFIG_SIGN_URL;
+		}
+
+		/** 无 query 的页面地址(后端若只签该地址,须配合 syncBrowserUrlForWxSign) */
+		function getWxSignUrlBase() {
+			if (location.origin && /^https?:/i.test(location.origin)) {
+				return location.origin + (location.pathname || '/h5/HBuilderProjects/shareIndex.html');
+			}
+			return WX_GET_CONFIG_SIGN_URL;
+		}
+
+		function getWxConfigSignUrl() {
+			if (String(q('wxSignBaseOnly') || '') === '1') return getWxSignUrlBase();
+			return getWxSignUrlFull();
+		}
+
 		/**
-		 * /wx/getWxConfig 与 wx.config 签名用 url(微信官方要求):
-		 * 当前页完整地址,包含 ? 后 GET 参数,不包含 # 后内容。
-		 * 若只签 https://.../shareIndex.html 而实际打开带 ?id=...,会报 invalid signature。
+		 * 微信校验签名用的是地址栏当前 url(不含#)。
+		 * 若后端只签了无参地址,须先把地址栏 sync 成与签名 url 一致再 wx.config。
 		 */
-		function getWxConfigSignUrl() {
-			var u = String(location.href || '').split('#')[0];
-			if (!u || u.indexOf('file:') === 0) {
-				return WX_GET_CONFIG_SIGN_URL;
+		function syncBrowserUrlForWxSign(signUrl) {
+			var target = String(signUrl || '').split('#')[0];
+			if (!target) return;
+			var hash = location.hash || '';
+			var current = String(location.href || '').split('#')[0];
+			if (current !== target) {
+				history.replaceState(history.state, document.title, target + hash);
 			}
-			return u;
 		}
 
-		/** 唤起 App 的 extinfo:与签名 url 相同规则 */
+		/** 唤起 App 的 extinfo:保留完整分享链 */
 		function getPageUrlForWxSign() {
-			return getWxConfigSignUrl();
+			return getWxSignUrlFull();
 		}
 
 		function buildWxGetConfigRequestUrl(signPageUrl) {
@@ -1240,7 +1278,7 @@
 			return String(raw).trim();
 		}
 
-		function normalizeWxJssdkSignPayload(res) {
+		function normalizeWxJssdkSignPayload(res, signUrlUsed) {
 			if (!res || typeof res !== 'object') return null;
 			var d = res.data != null && typeof res.data === 'object' ? res.data : res;
 			if (!d || typeof d !== 'object') return null;
@@ -1249,11 +1287,18 @@
 			var nonceStr = d.nonceStr || d.noncestr || d.nonce;
 			var signature = d.signature || d.sign;
 			if (!appId || timestamp == null || !nonceStr || !signature) return null;
+			var signedUrl =
+				d.signUrl != null && String(d.signUrl).trim() !== ''
+					? String(d.signUrl).trim().split('#')[0]
+					: signUrlUsed != null && String(signUrlUsed).trim() !== ''
+						? String(signUrlUsed).trim().split('#')[0]
+						: '';
 			return {
 				appId: String(appId),
 				timestamp: Number(timestamp),
 				nonceStr: String(nonceStr),
-				signature: String(signature)
+				signature: String(signature),
+				signUrl: signedUrl
 			};
 		}
 
@@ -1263,15 +1308,14 @@
 			else if (typeof err === 'string') errMsg = err;
 			var tip = '微信 JSSDK 配置失败';
 			if (/invalid signature/i.test(errMsg)) {
-				var signUrl = signPageUrl || getWxConfigSignUrl();
-				var hasQuery = signUrl.indexOf('?') >= 0;
+				var signUrl = signPageUrl || getWxSignUrlFull();
+				var pageNow = String(location.href || '').split('#')[0];
 				return (
 					tip +
-					':签名无效(invalid signature)。后端签名用的 url 必须与微信当前页完全一致(含?后参数、不含#):' +
-					signUrl +
-					(hasQuery
-						? ''
-						: '(若分享链带 id/storeId,不能只用无参数的 shareIndex.html 签名)')
+					':签名无效。请让后端用与地址栏完全相同的 url 参与签名(不含#)。当前地址栏:' +
+					pageNow +
+					';本次请求签名 url:' +
+					signUrl
 				);
 			}
 			if (/invalid appid/i.test(errMsg)) {
@@ -1284,8 +1328,8 @@
 			return tip + ',开放标签不可用。';
 		}
 
-		function fetchWeChatJssdkSign() {
-			var signPageUrl = getWxConfigSignUrl();
+		function fetchWeChatJssdkSign(signPageUrl) {
+			signPageUrl = signPageUrl || getWxConfigSignUrl();
 			var urls = [];
 			var custom = getWeChatJssdkSignRequestUrl();
 			if (custom) {
@@ -1313,7 +1357,7 @@
 								throw new Error(res.msg || 'sign rejected');
 							}
 						}
-						var pack = normalizeWxJssdkSignPayload(res);
+						var pack = normalizeWxJssdkSignPayload(res, signPageUrl);
 						if (!pack) throw new Error('empty sign payload');
 						return pack;
 					})
@@ -1324,6 +1368,81 @@
 			return tryUrl(0);
 		}
 
+		function applyWxConfig(sign, signPageUrl) {
+			var urlForWx =
+				sign.signUrl && String(sign.signUrl).trim() !== ''
+					? String(sign.signUrl).trim()
+					: signPageUrl;
+			syncBrowserUrlForWxSign(urlForWx);
+			console.log('[wx.config] appId=', sign.appId, 'signUrl=', urlForWx, 'page=', location.href.split('#')[0]);
+
+			return new Promise(function (resolve) {
+				wx.config({
+					debug: String(q('wxDebug') || '') === '1',
+					appId: sign.appId,
+					timestamp: sign.timestamp,
+					nonceStr: sign.nonceStr,
+					signature: sign.signature,
+					jsApiList: ['checkJsApi'],
+					openTagList: ['wx-open-launch-app']
+				});
+				wx.ready(function () {
+					weChatJssdkConfigured = true;
+					if (wxSignUrlFullBeforeStrip) {
+						var restore = wxSignUrlFullBeforeStrip + (location.hash || '');
+						history.replaceState(history.state, document.title, restore);
+						wxSignUrlFullBeforeStrip = '';
+					}
+					var tag = document.getElementById('launch-btn');
+					if (tag) {
+						try {
+							tag.setAttribute('extinfo', buildWeChatLaunchExtinfo());
+						} catch (eReady) {}
+					}
+					setFabLaunchMode('wx');
+					resolve(true);
+				});
+				wx.error(function (err) {
+					console.warn('[wx.config]', err, 'signUrl=', urlForWx);
+					var errMsg = err && err.errMsg ? String(err.errMsg) : '';
+					var baseUrl = getWxSignUrlBase();
+					var fullUrl = getWxSignUrlFull();
+					if (
+						!/invalid signature/i.test(errMsg) ||
+						wxConfigSignRetriedBaseUrl ||
+						baseUrl === fullUrl ||
+						urlForWx === baseUrl
+					) {
+						weChatJssdkConfigured = false;
+						showAppOpenFailTip(formatWxConfigErrorTip(err, urlForWx));
+						setFabLaunchMode('scheme');
+						resolve(false);
+						return;
+					}
+					wxConfigSignRetriedBaseUrl = true;
+					wxSignUrlFullBeforeStrip = fullUrl;
+					console.warn('[wx.config] retry with base url (no query):', baseUrl);
+					fetchWeChatJssdkSign(baseUrl)
+						.then(function (sign2) {
+							if (!sign2) {
+								weChatJssdkConfigured = false;
+								showAppOpenFailTip(formatWxConfigErrorTip(err, urlForWx));
+								setFabLaunchMode('scheme');
+								resolve(false);
+								return;
+							}
+							applyWxConfig(sign2, baseUrl).then(resolve);
+						})
+						.catch(function () {
+							weChatJssdkConfigured = false;
+							showAppOpenFailTip(formatWxConfigErrorTip(err, urlForWx));
+							setFabLaunchMode('scheme');
+							resolve(false);
+						});
+				});
+			});
+		}
+
 		function setFabLaunchMode(mode) {
 			var wxWrap = document.getElementById('fabWrapWx');
 			var fbWrap = document.getElementById('fabWrapFallback');
@@ -1343,7 +1462,7 @@
 				}
 				if (fbWrap) {
 					fbWrap.style.display = '';
-					fbWrap.setAttribute('aria-hidden', 'false');
+					fbWrap.removeAttribute('aria-hidden');
 				}
 			}
 		}
@@ -1384,6 +1503,7 @@
 		 */
 		function initWeChatOpenLaunchApp() {
 			var inWx = isWeChatInAppBrowser();
+			wxConfigSignRetriedBaseUrl = false;
 			var signPageUrl = getWxConfigSignUrl();
 			var reqUrl = buildWxGetConfigRequestUrl(signPageUrl);
 
@@ -1395,16 +1515,13 @@
 					console.warn('[wx]', domainHint);
 					showAppOpenFailTip(domainHint);
 				}
-				var fbWrap0 = document.getElementById('fabWrapFallback');
-				if (fbWrap0) {
-					fbWrap0.style.display = 'none';
-					fbWrap0.setAttribute('aria-hidden', 'true');
-				}
+				/* 签名完成前仍显示普通按钮,避免底部长时间空白 */
+				setFabLaunchMode('scheme');
 			}
 
 			console.log('[wx] GET', reqUrl);
 
-			return fetchWeChatJssdkSign()
+			return fetchWeChatJssdkSign(signPageUrl)
 				.then(function (sign) {
 					if (!inWx) {
 						if (!sign) {
@@ -1426,36 +1543,7 @@
 						setFabLaunchMode('scheme');
 						return false;
 					}
-					console.log('[wx.config] appId=', sign.appId, 'signUrl=', signPageUrl);
-					return new Promise(function (resolve) {
-						wx.config({
-							debug: String(q('wxDebug') || '') === '1',
-							appId: sign.appId,
-							timestamp: sign.timestamp,
-							nonceStr: sign.nonceStr,
-							signature: sign.signature,
-							jsApiList: ['checkJsApi'],
-							openTagList: ['wx-open-launch-app']
-						});
-						wx.ready(function () {
-							weChatJssdkConfigured = true;
-							var tag = document.getElementById('launch-btn');
-							if (tag) {
-								try {
-									tag.setAttribute('extinfo', buildWeChatLaunchExtinfo());
-								} catch (eReady) {}
-							}
-							setFabLaunchMode('wx');
-							resolve(true);
-						});
-						wx.error(function (err) {
-							console.warn('[wx.config]', err);
-							weChatJssdkConfigured = false;
-							showAppOpenFailTip(formatWxConfigErrorTip(err, signPageUrl));
-							setFabLaunchMode('scheme');
-							resolve(false);
-						});
-					});
+					return applyWxConfig(sign, signPageUrl);
 				})
 				.catch(function (e) {
 					console.warn('[wx] init failed', e);
@@ -2727,11 +2815,9 @@
 					tryOpenHBuilderApp();
 				});
 			}
+			initWeChatOpenLaunchApp();
 		}
 
-		/** 进入页立即请求 getWxConfig,不等到 window.onload */
-		initWeChatOpenLaunchApp();
-
 		if (document.readyState === 'complete') {
 			boot();
 		} else {