qb-pc-sdk 1.0.6 → 1.0.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.js +104 -0
- package/package.json +2 -2
- package/src/ad-sdk-wrapper.js +264 -172
package/index.js
CHANGED
|
@@ -194,6 +194,110 @@ if (isBrowser && window.XMLHttpRequest && !window._qbsdkXHRBlocked) {
|
|
|
194
194
|
window._qbsdkXHRBlocked = true;
|
|
195
195
|
}
|
|
196
196
|
|
|
197
|
+
// 拦截 iframe 的创建,阻止加载 wxgamesdkframe.html
|
|
198
|
+
if (isBrowser && !window._qbsdkIframeBlocked) {
|
|
199
|
+
const OriginalCreateElement = document.createElement;
|
|
200
|
+
document.createElement = function(tagName, options) {
|
|
201
|
+
const element = OriginalCreateElement.call(this, tagName, options);
|
|
202
|
+
|
|
203
|
+
// 如果是 iframe,拦截 src 属性的设置
|
|
204
|
+
if (tagName.toLowerCase() === 'iframe') {
|
|
205
|
+
const originalSetAttribute = element.setAttribute;
|
|
206
|
+
const originalSetProperty = Object.getOwnPropertyDescriptor(HTMLElement.prototype, 'src') ||
|
|
207
|
+
Object.getOwnPropertyDescriptor(HTMLIFrameElement.prototype, 'src');
|
|
208
|
+
|
|
209
|
+
// 拦截 setAttribute
|
|
210
|
+
element.setAttribute = function(name, value) {
|
|
211
|
+
if (name === 'src' && value && /wxgamesdkframe/i.test(value)) {
|
|
212
|
+
// 阻止加载 wxgamesdkframe
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
return originalSetAttribute.apply(this, arguments);
|
|
216
|
+
};
|
|
217
|
+
|
|
218
|
+
// 拦截 src 属性设置
|
|
219
|
+
if (originalSetProperty && originalSetProperty.set) {
|
|
220
|
+
Object.defineProperty(element, 'src', {
|
|
221
|
+
set: function(value) {
|
|
222
|
+
if (value && /wxgamesdkframe/i.test(value)) {
|
|
223
|
+
// 阻止加载 wxgamesdkframe
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
226
|
+
originalSetProperty.set.call(this, value);
|
|
227
|
+
},
|
|
228
|
+
get: function() {
|
|
229
|
+
return originalSetProperty.get ? originalSetProperty.get.call(this) : this.getAttribute('src');
|
|
230
|
+
},
|
|
231
|
+
configurable: true
|
|
232
|
+
});
|
|
233
|
+
} else {
|
|
234
|
+
// 降级方案:使用 Object.defineProperty
|
|
235
|
+
let _src = '';
|
|
236
|
+
Object.defineProperty(element, 'src', {
|
|
237
|
+
set: function(value) {
|
|
238
|
+
if (value && /wxgamesdkframe/i.test(value)) {
|
|
239
|
+
// 阻止加载 wxgamesdkframe
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
242
|
+
_src = value;
|
|
243
|
+
if (originalSetAttribute) {
|
|
244
|
+
originalSetAttribute.call(this, 'src', value);
|
|
245
|
+
}
|
|
246
|
+
},
|
|
247
|
+
get: function() {
|
|
248
|
+
return _src || this.getAttribute('src') || '';
|
|
249
|
+
},
|
|
250
|
+
configurable: true
|
|
251
|
+
});
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
return element;
|
|
256
|
+
};
|
|
257
|
+
window._qbsdkIframeBlocked = true;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
// 使用 MutationObserver 监听已存在的 iframe,阻止加载 wxgamesdkframe
|
|
261
|
+
if (isBrowser && window.document && window.MutationObserver && !window._qbsdkObserverAdded) {
|
|
262
|
+
const observer = new MutationObserver(function(mutations) {
|
|
263
|
+
mutations.forEach(function(mutation) {
|
|
264
|
+
mutation.addedNodes.forEach(function(node) {
|
|
265
|
+
if (node.nodeType === 1 && node.tagName && node.tagName.toLowerCase() === 'iframe') {
|
|
266
|
+
const src = node.src || node.getAttribute('src') || '';
|
|
267
|
+
if (src && /wxgamesdkframe/i.test(src)) {
|
|
268
|
+
// 阻止加载
|
|
269
|
+
node.src = '';
|
|
270
|
+
node.setAttribute('src', '');
|
|
271
|
+
// 移除 iframe
|
|
272
|
+
try {
|
|
273
|
+
node.parentNode && node.parentNode.removeChild(node);
|
|
274
|
+
} catch (e) {
|
|
275
|
+
// 忽略错误
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
});
|
|
280
|
+
});
|
|
281
|
+
});
|
|
282
|
+
|
|
283
|
+
// 等待 DOM 加载完成
|
|
284
|
+
if (window.document.body) {
|
|
285
|
+
observer.observe(window.document.body, {
|
|
286
|
+
childList: true,
|
|
287
|
+
subtree: true
|
|
288
|
+
});
|
|
289
|
+
} else {
|
|
290
|
+
window.addEventListener('DOMContentLoaded', function() {
|
|
291
|
+
observer.observe(window.document.body, {
|
|
292
|
+
childList: true,
|
|
293
|
+
subtree: true
|
|
294
|
+
});
|
|
295
|
+
});
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
window._qbsdkObserverAdded = true;
|
|
299
|
+
}
|
|
300
|
+
|
|
197
301
|
// 浏览器中预加载底层 SDK(仅 side-effect,挂载 window.GDTAdSDK)
|
|
198
302
|
if (isBrowser) {
|
|
199
303
|
try {
|
package/package.json
CHANGED
package/src/ad-sdk-wrapper.js
CHANGED
|
@@ -7,194 +7,281 @@
|
|
|
7
7
|
|
|
8
8
|
// 兼容浏览器和 Node.js 环境
|
|
9
9
|
const window = typeof global !== 'undefined' && global.window ? global.window : (typeof window !== 'undefined' ? window : global);
|
|
10
|
+
const isBrowser = typeof window !== 'undefined' && typeof window.document !== 'undefined';
|
|
10
11
|
|
|
11
|
-
//
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
const
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
//
|
|
22
|
-
if (
|
|
23
|
-
|
|
24
|
-
// 不调用原始 open,直接返回,阻止请求
|
|
25
|
-
return;
|
|
26
|
-
}
|
|
27
|
-
return originalOpen.apply(this, arguments);
|
|
28
|
-
};
|
|
29
|
-
|
|
30
|
-
// 拦截 send 方法,如果请求被阻止则不发送
|
|
31
|
-
xhr.send = function(data) {
|
|
32
|
-
if (xhr._qbsdkBlocked) {
|
|
33
|
-
// 请求已被阻止,不发送
|
|
34
|
-
return;
|
|
35
|
-
}
|
|
36
|
-
return originalSend.apply(this, arguments);
|
|
37
|
-
};
|
|
38
|
-
|
|
39
|
-
return xhr;
|
|
40
|
-
};
|
|
41
|
-
window._qbsdkXHRBlocked = true;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
// 拦截并过滤微信游戏SDK相关的错误日志(仅拦截一次)
|
|
45
|
-
if (typeof window !== 'undefined' && window.console && !window.console.error._qbsdkFiltered) {
|
|
46
|
-
const originalError = window.console.error;
|
|
47
|
-
const originalWarn = window.console.warn;
|
|
48
|
-
|
|
49
|
-
// 过滤函数,检查是否应该过滤
|
|
50
|
-
const shouldFilter = function(...args) {
|
|
51
|
-
const errorText = args.join(' ').toLowerCase();
|
|
52
|
-
// 检查是否包含 localhost.weixin.qq.com(各种格式)
|
|
53
|
-
const hasWeixinLocalhost = /https?:\/\/localhost\.weixin\.qq\.com/i.test(errorText) ||
|
|
54
|
-
/localhost\.weixin\.qq\.com/i.test(errorText) ||
|
|
55
|
-
errorText.includes('localhost.weixin.qq.com');
|
|
56
|
-
|
|
57
|
-
return (
|
|
58
|
-
errorText.includes('微信') ||
|
|
59
|
-
errorText.includes('wechat') ||
|
|
60
|
-
errorText.includes('weixin') ||
|
|
61
|
-
errorText.includes('wxgame') ||
|
|
62
|
-
errorText.includes('微信游戏') ||
|
|
63
|
-
errorText.includes('微信小游戏') ||
|
|
64
|
-
errorText.includes('wxgamesdkframe') ||
|
|
65
|
-
hasWeixinLocalhost ||
|
|
66
|
-
errorText.includes('wx_game_base') ||
|
|
67
|
-
errorText.includes('getgamesession') ||
|
|
68
|
-
errorText.includes('xmlhttprequest') ||
|
|
69
|
-
errorText.includes('err_failed') ||
|
|
70
|
-
errorText.includes('err_connection_refused') ||
|
|
71
|
-
errorText.includes('cors policy') ||
|
|
72
|
-
errorText.includes('secure context') ||
|
|
73
|
-
errorText.includes('loopback') ||
|
|
74
|
-
errorText.includes('more-private address space') ||
|
|
75
|
-
errorText.includes('net::') ||
|
|
76
|
-
errorText.includes('timeout') ||
|
|
77
|
-
errorText.includes('frame on invoke') ||
|
|
78
|
-
errorText.includes('/wx_game_base/api/business') ||
|
|
79
|
-
/localhost\.weixin\.qq\.com:\d+/.test(errorText) ||
|
|
80
|
-
/:\d{5}\/wx_game_base/.test(errorText) ||
|
|
81
|
-
/:\d{5}\/wx_game_base/.test(errorText)
|
|
82
|
-
);
|
|
83
|
-
};
|
|
84
|
-
|
|
85
|
-
const filteredError = function(...args) {
|
|
86
|
-
// 如果不是微信相关的错误,正常输出
|
|
87
|
-
if (!shouldFilter(...args)) {
|
|
88
|
-
originalError.apply(window.console, args);
|
|
89
|
-
}
|
|
90
|
-
};
|
|
91
|
-
|
|
92
|
-
const filteredWarn = function(...args) {
|
|
93
|
-
// 如果不是微信相关的警告,正常输出
|
|
94
|
-
if (!shouldFilter(...args)) {
|
|
95
|
-
originalWarn.apply(window.console, args);
|
|
96
|
-
}
|
|
97
|
-
};
|
|
98
|
-
|
|
99
|
-
// 标记已过滤,避免重复拦截
|
|
100
|
-
filteredError._qbsdkFiltered = true;
|
|
101
|
-
filteredWarn._qbsdkFiltered = true;
|
|
102
|
-
window.console.error = filteredError;
|
|
103
|
-
window.console.warn = filteredWarn;
|
|
104
|
-
|
|
105
|
-
// 拦截全局错误事件,过滤微信游戏SDK相关的错误
|
|
106
|
-
if (!window._qbsdkErrorHandlerAdded) {
|
|
107
|
-
const originalOnError = window.onerror;
|
|
108
|
-
window.onerror = function(message, source, lineno, colno, error) {
|
|
109
|
-
const errorText = (message || '').toLowerCase() + (source || '').toLowerCase();
|
|
110
|
-
if (shouldFilter(errorText)) {
|
|
111
|
-
// 静默处理,不输出
|
|
112
|
-
return true; // 阻止默认错误处理
|
|
113
|
-
}
|
|
114
|
-
// 其他错误正常处理
|
|
115
|
-
if (originalOnError) {
|
|
116
|
-
return originalOnError.call(this, message, source, lineno, colno, error);
|
|
117
|
-
}
|
|
118
|
-
return false;
|
|
119
|
-
};
|
|
120
|
-
|
|
121
|
-
// 拦截未捕获的 Promise rejection
|
|
122
|
-
const originalUnhandledRejection = window.onunhandledrejection;
|
|
123
|
-
window.addEventListener('unhandledrejection', function(event) {
|
|
124
|
-
const reason = event.reason || {};
|
|
125
|
-
const errorText = (reason.message || reason || '').toString().toLowerCase();
|
|
126
|
-
if (shouldFilter(errorText)) {
|
|
127
|
-
// 阻止默认行为,静默处理
|
|
128
|
-
event.preventDefault();
|
|
129
|
-
return;
|
|
130
|
-
}
|
|
131
|
-
// 其他错误正常处理
|
|
132
|
-
if (originalUnhandledRejection) {
|
|
133
|
-
originalUnhandledRejection.call(window, event);
|
|
134
|
-
}
|
|
135
|
-
});
|
|
136
|
-
|
|
137
|
-
// 拦截 XMLHttpRequest 的错误事件,只隐藏错误日志,不阻止请求
|
|
138
|
-
if (window.XMLHttpRequest) {
|
|
139
|
-
const OriginalXHR = window.XMLHttpRequest;
|
|
140
|
-
window.XMLHttpRequest = function() {
|
|
141
|
-
const xhr = new OriginalXHR();
|
|
142
|
-
const originalAddEventListener = xhr.addEventListener;
|
|
143
|
-
|
|
144
|
-
// 拦截 addEventListener,过滤错误事件
|
|
145
|
-
xhr.addEventListener = function(type, listener, options) {
|
|
146
|
-
if (type === 'error' || type === 'loadend' || type === 'abort') {
|
|
147
|
-
const wrappedListener = function(event) {
|
|
148
|
-
const url = (xhr.responseURL || xhr._requestURL || '').toLowerCase();
|
|
149
|
-
// 如果请求被标记为需要过滤,或者 URL 匹配过滤规则,则静默处理
|
|
150
|
-
if (xhr._qbsdkFiltered || shouldFilter(url)) {
|
|
151
|
-
return; // 静默处理错误事件
|
|
152
|
-
}
|
|
153
|
-
if (listener) {
|
|
154
|
-
listener.apply(this, arguments);
|
|
155
|
-
}
|
|
156
|
-
};
|
|
157
|
-
return originalAddEventListener.call(this, type, wrappedListener, options);
|
|
158
|
-
}
|
|
159
|
-
return originalAddEventListener.apply(this, arguments);
|
|
160
|
-
};
|
|
12
|
+
// ============================================================
|
|
13
|
+
// 核心拦截逻辑:在 SDK 加载前彻底屏蔽 WeChat Localhost 请求
|
|
14
|
+
// ============================================================
|
|
15
|
+
if (isBrowser) {
|
|
16
|
+
// 0. 拦截 iframe 的创建,阻止加载 wxgamesdkframe.html
|
|
17
|
+
if (window.document && !window._qbsdkIframeBlocked) {
|
|
18
|
+
const OriginalCreateElement = window.document.createElement;
|
|
19
|
+
window.document.createElement = function(tagName, options) {
|
|
20
|
+
const element = OriginalCreateElement.call(this, tagName, options);
|
|
21
|
+
|
|
22
|
+
// 如果是 iframe,拦截 src 属性的设置
|
|
23
|
+
if (tagName.toLowerCase() === 'iframe') {
|
|
24
|
+
const originalSetAttribute = element.setAttribute;
|
|
161
25
|
|
|
162
|
-
//
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
if (url && /localhost\.weixin\.qq\.com/i.test(url)) {
|
|
168
|
-
xhr._qbsdkFiltered = true;
|
|
26
|
+
// 拦截 setAttribute
|
|
27
|
+
element.setAttribute = function(name, value) {
|
|
28
|
+
if (name === 'src' && value && /wxgamesdkframe/i.test(value)) {
|
|
29
|
+
// 阻止加载 wxgamesdkframe
|
|
30
|
+
return;
|
|
169
31
|
}
|
|
170
|
-
return
|
|
32
|
+
return originalSetAttribute.apply(this, arguments);
|
|
171
33
|
};
|
|
172
34
|
|
|
173
|
-
// 拦截
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
//
|
|
179
|
-
|
|
180
|
-
|
|
35
|
+
// 拦截 src 属性设置
|
|
36
|
+
let _src = '';
|
|
37
|
+
Object.defineProperty(element, 'src', {
|
|
38
|
+
set: function(value) {
|
|
39
|
+
if (value && /wxgamesdkframe/i.test(value)) {
|
|
40
|
+
// 阻止加载 wxgamesdkframe
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
_src = value;
|
|
44
|
+
if (originalSetAttribute) {
|
|
45
|
+
originalSetAttribute.call(this, 'src', value);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// 如果 iframe 加载完成,在其内部也设置拦截
|
|
49
|
+
if (value && element.contentWindow) {
|
|
50
|
+
try {
|
|
51
|
+
const iframeWindow = element.contentWindow;
|
|
52
|
+
if (iframeWindow && iframeWindow.XMLHttpRequest && !iframeWindow._qbsdkXHRBlocked) {
|
|
53
|
+
const OriginalXHR = iframeWindow.XMLHttpRequest;
|
|
54
|
+
iframeWindow.XMLHttpRequest = function() {
|
|
55
|
+
const xhr = new OriginalXHR();
|
|
56
|
+
const originalOpen = xhr.open;
|
|
57
|
+
const originalSend = xhr.send;
|
|
58
|
+
|
|
59
|
+
xhr.open = function(method, url, async, user, password) {
|
|
60
|
+
if (url && /localhost\.weixin\.qq\.com/i.test(url)) {
|
|
61
|
+
xhr._qbsdkBlocked = true;
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
return originalOpen.apply(this, arguments);
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
xhr.send = function(data) {
|
|
68
|
+
if (xhr._qbsdkBlocked) {
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
return originalSend.apply(this, arguments);
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
return xhr;
|
|
75
|
+
};
|
|
76
|
+
iframeWindow._qbsdkXHRBlocked = true;
|
|
77
|
+
}
|
|
78
|
+
} catch (e) {
|
|
79
|
+
// 跨域 iframe 无法访问,忽略
|
|
181
80
|
}
|
|
182
|
-
}
|
|
183
|
-
originalAddEventListener.call(this, 'error', wrappedHandler);
|
|
81
|
+
}
|
|
184
82
|
},
|
|
185
83
|
get: function() {
|
|
186
|
-
return this.
|
|
84
|
+
return _src || this.getAttribute('src') || '';
|
|
187
85
|
},
|
|
188
86
|
configurable: true
|
|
189
87
|
});
|
|
190
88
|
|
|
191
|
-
|
|
89
|
+
// 监听 iframe 加载事件,在加载后设置拦截
|
|
90
|
+
element.addEventListener('load', function() {
|
|
91
|
+
try {
|
|
92
|
+
const iframeWindow = element.contentWindow;
|
|
93
|
+
if (iframeWindow && iframeWindow.XMLHttpRequest && !iframeWindow._qbsdkXHRBlocked) {
|
|
94
|
+
const OriginalXHR = iframeWindow.XMLHttpRequest;
|
|
95
|
+
iframeWindow.XMLHttpRequest = function() {
|
|
96
|
+
const xhr = new OriginalXHR();
|
|
97
|
+
const originalOpen = xhr.open;
|
|
98
|
+
const originalSend = xhr.send;
|
|
99
|
+
|
|
100
|
+
xhr.open = function(method, url, async, user, password) {
|
|
101
|
+
if (url && /localhost\.weixin\.qq\.com/i.test(url)) {
|
|
102
|
+
xhr._qbsdkBlocked = true;
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
return originalOpen.apply(this, arguments);
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
xhr.send = function(data) {
|
|
109
|
+
if (xhr._qbsdkBlocked) {
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
return originalSend.apply(this, arguments);
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
return xhr;
|
|
116
|
+
};
|
|
117
|
+
iframeWindow._qbsdkXHRBlocked = true;
|
|
118
|
+
}
|
|
119
|
+
} catch (e) {
|
|
120
|
+
// 跨域 iframe 无法访问,忽略
|
|
121
|
+
}
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
return element;
|
|
126
|
+
};
|
|
127
|
+
window._qbsdkIframeBlocked = true;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// 0.1. 使用 MutationObserver 监听已存在的 iframe,阻止加载 wxgamesdkframe
|
|
131
|
+
if (window.document && window.MutationObserver && !window._qbsdkObserverAdded) {
|
|
132
|
+
const observer = new MutationObserver(function(mutations) {
|
|
133
|
+
mutations.forEach(function(mutation) {
|
|
134
|
+
mutation.addedNodes.forEach(function(node) {
|
|
135
|
+
if (node.nodeType === 1 && node.tagName && node.tagName.toLowerCase() === 'iframe') {
|
|
136
|
+
const src = node.src || node.getAttribute('src') || '';
|
|
137
|
+
if (src && /wxgamesdkframe/i.test(src)) {
|
|
138
|
+
// 阻止加载
|
|
139
|
+
node.src = '';
|
|
140
|
+
node.setAttribute('src', '');
|
|
141
|
+
// 移除 iframe
|
|
142
|
+
try {
|
|
143
|
+
node.parentNode && node.parentNode.removeChild(node);
|
|
144
|
+
} catch (e) {
|
|
145
|
+
// 忽略错误
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
});
|
|
150
|
+
});
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
observer.observe(window.document.body || window.document.documentElement, {
|
|
154
|
+
childList: true,
|
|
155
|
+
subtree: true
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
window._qbsdkObserverAdded = true;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// 1. 拦截 XMLHttpRequest
|
|
162
|
+
if (window.XMLHttpRequest && !window._qbsdkXHRBlocked) {
|
|
163
|
+
const OriginalXHR = window.XMLHttpRequest;
|
|
164
|
+
|
|
165
|
+
// 定义一个安全的 XHR 代理类
|
|
166
|
+
window.XMLHttpRequest = function() {
|
|
167
|
+
const xhr = new OriginalXHR();
|
|
168
|
+
const originalOpen = xhr.open;
|
|
169
|
+
const originalSend = xhr.send;
|
|
170
|
+
|
|
171
|
+
// 标记此实例是否被阻断
|
|
172
|
+
xhr._qbsdkBlocked = false;
|
|
173
|
+
|
|
174
|
+
xhr.open = function(method, url, async, user, password) {
|
|
175
|
+
const targetUrl = (url || '').toString().toLowerCase();
|
|
176
|
+
|
|
177
|
+
// 严格匹配 localhost.weixin.qq.com 及其变体
|
|
178
|
+
if (targetUrl.includes('localhost.weixin.qq.com') ||
|
|
179
|
+
targetUrl.includes('wx_game_base') ||
|
|
180
|
+
/127\.0\.0\.1:\d+\/wx_game_base/.test(targetUrl)) {
|
|
181
|
+
|
|
182
|
+
xhr._qbsdkBlocked = true;
|
|
183
|
+
|
|
184
|
+
// 伪造一个成功的状态,防止 SDK 内部抛出未捕获异常导致重试
|
|
185
|
+
// 我们不调用 originalOpen,而是让它"空转"
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
return originalOpen.apply(this, arguments);
|
|
190
|
+
};
|
|
191
|
+
|
|
192
|
+
xhr.send = function(data) {
|
|
193
|
+
if (xhr._qbsdkBlocked) {
|
|
194
|
+
// 模拟异步响应,防止同步阻塞
|
|
195
|
+
setTimeout(() => {
|
|
196
|
+
// 如果 SDK 监听了 error 或 loadend,我们需要伪造一个响应
|
|
197
|
+
// 但为了静默,通常什么都不做最好,或者触发一个假的 load 事件
|
|
198
|
+
// 这里选择静默失败,不触发网络层面的报错
|
|
199
|
+
if (xhr.readyState !== 4) {
|
|
200
|
+
Object.defineProperty(xhr, 'readyState', { value: 4, writable: true });
|
|
201
|
+
Object.defineProperty(xhr, 'status', { value: 0, writable: true }); // 0 status usually implies network error but internally handled
|
|
202
|
+
Object.defineProperty(xhr, 'statusText', { value: 'Blocked by AdSDKWrapper', writable: true });
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// 触发 fake error 事件以满足某些 SDK 的超时逻辑,但不会在 Console 报 net::ERR
|
|
206
|
+
if (xhr.onerror) xhr.onerror(new ProgressEvent('error'));
|
|
207
|
+
}, 0);
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
return originalSend.apply(this, arguments);
|
|
192
211
|
};
|
|
212
|
+
|
|
213
|
+
return xhr;
|
|
214
|
+
};
|
|
215
|
+
|
|
216
|
+
// 复制静态属性 (如 UNSENT, OPENED 等)
|
|
217
|
+
for (let key in OriginalXHR) {
|
|
218
|
+
if (Object.prototype.hasOwnProperty.call(OriginalXHR, key)) {
|
|
219
|
+
window.XMLHttpRequest[key] = OriginalXHR[key];
|
|
220
|
+
}
|
|
193
221
|
}
|
|
194
222
|
|
|
195
|
-
window.
|
|
223
|
+
window._qbsdkXHRBlocked = true;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// 2. 拦截 Fetch API (很多现代 SDK 混用 XHR 和 Fetch)
|
|
227
|
+
if (window.fetch && !window._qbsdkFetchBlocked) {
|
|
228
|
+
const originalFetch = window.fetch;
|
|
229
|
+
window.fetch = function(input, init) {
|
|
230
|
+
let url = '';
|
|
231
|
+
if (typeof input === 'string') {
|
|
232
|
+
url = input;
|
|
233
|
+
} else if (input instanceof Request) {
|
|
234
|
+
url = input.url;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
url = url.toLowerCase();
|
|
238
|
+
|
|
239
|
+
if (url.includes('localhost.weixin.qq.com') || url.includes('wx_game_base')) {
|
|
240
|
+
// 返回一个永远 pending 或者 立即 reject 的 Promise
|
|
241
|
+
// 为了不报错,返回一个伪造的 Response
|
|
242
|
+
return Promise.resolve(new Response(JSON.stringify({ code: -1, msg: 'Blocked' }), {
|
|
243
|
+
status: 200,
|
|
244
|
+
statusText: 'OK',
|
|
245
|
+
headers: { 'Content-Type': 'application/json' }
|
|
246
|
+
}));
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
return originalFetch.apply(this, arguments);
|
|
250
|
+
};
|
|
251
|
+
window._qbsdkFetchBlocked = true;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
// 3. 拦截 Console (保留原有的日志过滤逻辑作为第二道防线)
|
|
255
|
+
if (window.console && !window.console.error._qbsdkFiltered) {
|
|
256
|
+
const originalError = window.console.error;
|
|
257
|
+
const originalWarn = window.console.warn;
|
|
258
|
+
|
|
259
|
+
const shouldFilter = (args) => {
|
|
260
|
+
const text = args.map(String).join(' ').toLowerCase();
|
|
261
|
+
return (
|
|
262
|
+
text.includes('localhost.weixin.qq.com') ||
|
|
263
|
+
text.includes('wx_game_base') ||
|
|
264
|
+
text.includes('err_connection_refused') ||
|
|
265
|
+
text.includes('err_failed') ||
|
|
266
|
+
text.includes('cors policy') ||
|
|
267
|
+
text.includes('wxgamesdkframe')
|
|
268
|
+
);
|
|
269
|
+
};
|
|
270
|
+
|
|
271
|
+
window.console.error = function(...args) {
|
|
272
|
+
if (!shouldFilter(args)) originalError.apply(console, args);
|
|
273
|
+
};
|
|
274
|
+
|
|
275
|
+
window.console.warn = function(...args) {
|
|
276
|
+
if (!shouldFilter(args)) originalWarn.apply(console, args);
|
|
277
|
+
};
|
|
278
|
+
|
|
279
|
+
window.console.error._qbsdkFiltered = true;
|
|
196
280
|
}
|
|
197
281
|
}
|
|
282
|
+
// ============================================================
|
|
283
|
+
// 拦截逻辑结束
|
|
284
|
+
// ============================================================
|
|
198
285
|
|
|
199
286
|
// 内部常量配置
|
|
200
287
|
const API_CONFIG = {
|
|
@@ -419,6 +506,11 @@
|
|
|
419
506
|
}
|
|
420
507
|
|
|
421
508
|
_handleError(error, message) {
|
|
509
|
+
// 内部错误也进行过滤,防止将过滤掉的错误再次打印
|
|
510
|
+
const errStr = String(error).toLowerCase();
|
|
511
|
+
if (errStr.includes('localhost.weixin.qq.com') || errStr.includes('blocked by adsdkwrapper')) {
|
|
512
|
+
return;
|
|
513
|
+
}
|
|
422
514
|
console.error(`[AdSDK Error] ${message}:`, error);
|
|
423
515
|
if (this.config.onAdError) {
|
|
424
516
|
this.config.onAdError(error, message);
|
|
@@ -447,4 +539,4 @@
|
|
|
447
539
|
|
|
448
540
|
// 返回类供直接使用
|
|
449
541
|
return AdSDKWrapper;
|
|
450
|
-
})(typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : this);
|
|
542
|
+
})(typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : this);
|