嵌入模式识别

This commit is contained in:
iqudoo
2026-05-02 13:40:28 +08:00
parent 1966dbbd51
commit ede67b61b4
8 changed files with 279 additions and 34 deletions

View File

@@ -3,6 +3,13 @@ let _defineConfig = {
}
let _defConfig = {
/**
* iframe / 嵌入场景下是否把调用转发到父页面的同名 SDKpostMessage
* - 'auto'(默认):只要处于子 frameparent !== window即转发含 startScan 等均走父页逻辑
* - true | 'on' | 'parent':在存在父 window 时强制转发
* - false | 'off' | 'local':始终在本页执行(子页自己要跑扫码时用)
*/
embedProxyMode: 'auto',
}
let _customConfig = {

View File

@@ -0,0 +1,40 @@
/**
* 嵌入场景下由父页探测得到的微信环境结论(子页跨域时无法读 top UA
*/
let parentWxEnvReport = null;
export function setParentWxEnvReport(wx) {
parentWxEnvReport = wx ? true : false;
}
export function getParentWxEnvReport() {
return parentWxEnvReport;
}
/**
* 在给定 window 上探测微信系 WebView公众号 / 部分企业微信)
* 与外层页面是否为同一套 SDK无关依赖 UA / WeixinJSBridge
*/
export function readWxLikeEnvFromWindow(win) {
if (!win) {
return false;
}
try {
const nav = win.navigator;
if (nav) {
const ua = nav.userAgent || "";
if (/micromessenger/i.test(ua)) {
return true;
}
if (/wxwork/i.test(ua)) {
return true;
}
}
if (win.WeixinJSBridge) {
return true;
}
} catch (e) {
// ignore
}
return false;
}

View File

@@ -0,0 +1,37 @@
import { getConfig } from "./config";
/** 是否存在可与 postMessage 交互的父 browsing context自身不是顶层 opener/parent */
export function hasDistinctParentWindow() {
if (typeof window === "undefined") {
return false;
}
try {
return window.parent != null && window.parent !== window;
} catch (e) {
return true;
}
}
/**
* 是否通过父页面 SDK 代理执行(每次调用重新读取 config
*
* embedProxyMode 为 auto默认只要 window.parent !== window处于子 frame
* 所有对外 API含 startScan均走 postMessage 由父页同一套 SDK 执行,避免子页重复跑扫码逻辑。
*/
export function resolveUseParentProxy() {
const mode = getConfig("embedProxyMode");
if (mode === false || mode === "local" || mode === "off") {
return false;
}
const parentOk = hasDistinctParentWindow();
if (!parentOk) {
return false;
}
if (mode === true || mode === "on" || mode === "parent") {
return true;
}
if (mode === "auto" || mode === undefined || mode === null) {
return parentOk;
}
return !!mode;
}

View File

@@ -1,4 +1,6 @@
import { getConfig } from "../config";
import { readWxLikeEnvFromWindow, getParentWxEnvReport } from "../embedEnvProbe";
import { resolveUseParentProxy } from "../embedProxy";
import { request } from "../../utils/request";
import { toAny } from "../../utils/toany";
@@ -46,6 +48,27 @@ function loadWxScript() {
});
}
/** 微信 JS-SDK 签名 URL嵌入且走父页代理时用父页地址与微信内打开的页面一致可配置 wxJssdkSignatureUrl 覆盖 */
function getPageUrlForWxJssdkSignature() {
const override = getConfig("wxJssdkSignatureUrl");
if (override) {
return String(override).split("#")[0];
}
if (resolveUseParentProxy()) {
try {
if (typeof window !== "undefined" && window.parent && window.parent !== window) {
return window.parent.location.href.split("#")[0];
}
} catch (e) {
// 跨域父页不可读 location由调用方配置 wxJssdkSignatureUrl
}
}
if (typeof window === "undefined") {
return "";
}
return window.location.href.split("#")[0];
}
function fetchWxConfig() {
let initWechatJssdk = toAny(getConfig("initWechatJssdk"), {});
if (!!initWechatJssdk.sdkConfig) {
@@ -59,7 +82,7 @@ function fetchWxConfig() {
url: apiUrl,
method: "GET",
data: {
url: window.location.href.split("#")[0]
url: getPageUrlForWxJssdkSignature()
}
}).then(res => {
let data = toAny(res.data, {});
@@ -77,8 +100,22 @@ function fetchWxConfig() {
}
export function isWxEnv() {
return typeof navigator !== "undefined"
&& /micromessenger/i.test(navigator.userAgent || "");
if (readWxLikeEnvFromWindow(typeof window !== "undefined" ? window : null)) {
return true;
}
if (typeof window !== "undefined") {
try {
if (window.top && window.top !== window && readWxLikeEnvFromWindow(window.top)) {
return true;
}
} catch (e) {
// 跨域不可读 top依赖父页 probeWxEnv / embedEnvProbe 缓存
}
}
if (resolveUseParentProxy() && getParentWxEnvReport() === true) {
return true;
}
return false;
}
export function isWxMiniProgramEnv() {
@@ -88,11 +125,14 @@ export function isWxMiniProgramEnv() {
export function isSupportWxScan() {
const wx = getWx();
return isWxMiniProgramEnv()
|| isWxEnv()
&& _wxReady
&& wx
&& wx.scanQRCode;
if (isWxMiniProgramEnv()) {
return true;
}
// 嵌入且 API 走父页时,子页未必初始化 wx只要识别为微信环境即视为支持实际能力由父页 SDK 决定)
if (resolveUseParentProxy() && isWxEnv()) {
return true;
}
return !!(isWxEnv() && _wxReady && wx && wx.scanQRCode);
}
export function initWxJssdk() {