qb-pc-sdk 1.0.7 → 1.0.9
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 +218 -13
- package/src/example-simple.html +2 -2
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
|
@@ -13,6 +13,151 @@
|
|
|
13
13
|
// 核心拦截逻辑:在 SDK 加载前彻底屏蔽 WeChat Localhost 请求
|
|
14
14
|
// ============================================================
|
|
15
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;
|
|
25
|
+
|
|
26
|
+
// 拦截 setAttribute
|
|
27
|
+
element.setAttribute = function(name, value) {
|
|
28
|
+
if (name === 'src' && value && /wxgamesdkframe/i.test(value)) {
|
|
29
|
+
// 阻止加载 wxgamesdkframe
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
return originalSetAttribute.apply(this, arguments);
|
|
33
|
+
};
|
|
34
|
+
|
|
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 无法访问,忽略
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
},
|
|
83
|
+
get: function() {
|
|
84
|
+
return _src || this.getAttribute('src') || '';
|
|
85
|
+
},
|
|
86
|
+
configurable: true
|
|
87
|
+
});
|
|
88
|
+
|
|
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
|
+
|
|
16
161
|
// 1. 拦截 XMLHttpRequest
|
|
17
162
|
if (window.XMLHttpRequest && !window._qbsdkXHRBlocked) {
|
|
18
163
|
const OriginalXHR = window.XMLHttpRequest;
|
|
@@ -140,8 +285,8 @@
|
|
|
140
285
|
|
|
141
286
|
// 内部常量配置
|
|
142
287
|
const API_CONFIG = {
|
|
143
|
-
INIT: 'http://
|
|
144
|
-
POSITION: 'http://
|
|
288
|
+
INIT: 'http://app.qubiankeji.com:8084/pc/init',
|
|
289
|
+
POSITION: 'http://app.qubiankeji.com:8084/pc/position',
|
|
145
290
|
GDT_SDK_ID: 2 // 标识
|
|
146
291
|
};
|
|
147
292
|
|
|
@@ -202,14 +347,33 @@
|
|
|
202
347
|
fetch(`${API_CONFIG.POSITION}?positionId=${this.config.placementId}`).then(r => r.json())
|
|
203
348
|
]);
|
|
204
349
|
|
|
350
|
+
// 处理返回数据结构:支持 { data: {...} } 或直接返回数据
|
|
351
|
+
const initData = initRes.data || initRes;
|
|
352
|
+
const posData = posRes.data || posRes;
|
|
353
|
+
|
|
205
354
|
// 2. 提取 AppID
|
|
206
|
-
this.gdtAppId =
|
|
355
|
+
this.gdtAppId = initData.thirdIdMap ? initData.thirdIdMap[String(API_CONFIG.GDT_SDK_ID)] : null;
|
|
207
356
|
|
|
208
357
|
// 3. 执行广告位筛选逻辑
|
|
209
|
-
this.gdtPlacementId = this._selectPlacementId(
|
|
358
|
+
this.gdtPlacementId = this._selectPlacementId(posData);
|
|
359
|
+
|
|
360
|
+
// 添加调试日志(始终输出,便于排查问题)
|
|
361
|
+
console.log('[AdSDK] 初始化数据:', {
|
|
362
|
+
initRes: initRes,
|
|
363
|
+
posRes: posRes,
|
|
364
|
+
initData: initData,
|
|
365
|
+
posData: posData,
|
|
366
|
+
gdtAppId: this.gdtAppId,
|
|
367
|
+
gdtPlacementId: this.gdtPlacementId
|
|
368
|
+
});
|
|
210
369
|
|
|
211
370
|
if (!this.gdtAppId || !this.gdtPlacementId) {
|
|
212
|
-
|
|
371
|
+
const errorMsg = `未找到匹配的(sdkId:2)配置信息 - AppId: ${this.gdtAppId}, PlacementId: ${this.gdtPlacementId}`;
|
|
372
|
+
console.error('[AdSDK]', errorMsg, {
|
|
373
|
+
initData: initData,
|
|
374
|
+
posData: posData
|
|
375
|
+
});
|
|
376
|
+
throw new Error(errorMsg);
|
|
213
377
|
}
|
|
214
378
|
|
|
215
379
|
this._checkAndRun();
|
|
@@ -223,21 +387,62 @@
|
|
|
223
387
|
* 规则:headSetList优先;否则选positionSetList中优先级最高的
|
|
224
388
|
*/
|
|
225
389
|
_selectPlacementId(data) {
|
|
390
|
+
if (!data) {
|
|
391
|
+
console.error('[AdSDK] _selectPlacementId: data 为空');
|
|
392
|
+
return null;
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
// 添加调试信息
|
|
396
|
+
console.log('[AdSDK] _selectPlacementId 输入数据:', data);
|
|
397
|
+
const targetSdkId = API_CONFIG.GDT_SDK_ID;
|
|
398
|
+
console.log('[AdSDK] 查找 sdkId (类型:', typeof targetSdkId, '值:', targetSdkId, ')');
|
|
399
|
+
|
|
226
400
|
// A. 优先检查 headSetList
|
|
227
|
-
if (data.headSetList && data.headSetList.length > 0) {
|
|
228
|
-
|
|
229
|
-
|
|
401
|
+
if (data.headSetList && Array.isArray(data.headSetList) && data.headSetList.length > 0) {
|
|
402
|
+
console.log('[AdSDK] 检查 headSetList:', data.headSetList);
|
|
403
|
+
const headAd = data.headSetList.find(item => {
|
|
404
|
+
// 支持数字和字符串类型的比较
|
|
405
|
+
const itemSdkId = Number(item.sdkId);
|
|
406
|
+
const match = itemSdkId === targetSdkId || String(item.sdkId) === String(targetSdkId);
|
|
407
|
+
if (!match) {
|
|
408
|
+
console.log('[AdSDK] headSetList 项不匹配:', item, 'sdkId:', item.sdkId, '类型:', typeof item.sdkId);
|
|
409
|
+
}
|
|
410
|
+
return match;
|
|
411
|
+
});
|
|
412
|
+
if (headAd) {
|
|
413
|
+
console.log('[AdSDK] ✅ 在 headSetList 中找到匹配项:', headAd);
|
|
414
|
+
return headAd.positionId;
|
|
415
|
+
}
|
|
230
416
|
}
|
|
231
417
|
|
|
232
418
|
// B. 检查 positionSetList
|
|
233
|
-
if (data.positionSetList && data.positionSetList.length > 0) {
|
|
419
|
+
if (data.positionSetList && Array.isArray(data.positionSetList) && data.positionSetList.length > 0) {
|
|
420
|
+
console.log('[AdSDK] 检查 positionSetList:', data.positionSetList);
|
|
234
421
|
const sortedList = data.positionSetList
|
|
235
|
-
.filter(item =>
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
422
|
+
.filter(item => {
|
|
423
|
+
// 支持数字和字符串类型的比较
|
|
424
|
+
const itemSdkId = Number(item.sdkId);
|
|
425
|
+
const match = itemSdkId === targetSdkId || String(item.sdkId) === String(targetSdkId);
|
|
426
|
+
console.log('[AdSDK] positionSetList 项检查:', {
|
|
427
|
+
item: item,
|
|
428
|
+
itemSdkId: item.sdkId,
|
|
429
|
+
itemSdkIdType: typeof item.sdkId,
|
|
430
|
+
targetSdkId: targetSdkId,
|
|
431
|
+
targetSdkIdType: typeof targetSdkId,
|
|
432
|
+
match: match
|
|
433
|
+
});
|
|
434
|
+
return match;
|
|
435
|
+
})
|
|
436
|
+
.sort((a, b) => (b.callbackPriority || 0) - (a.callbackPriority || 0)); // 按优先级从大到小排序
|
|
437
|
+
|
|
438
|
+
console.log('[AdSDK] 筛选后的列表:', sortedList);
|
|
439
|
+
if (sortedList.length > 0) {
|
|
440
|
+
console.log('[AdSDK] ✅ 在 positionSetList 中找到匹配项:', sortedList[0]);
|
|
441
|
+
return sortedList[0].positionId;
|
|
442
|
+
}
|
|
239
443
|
}
|
|
240
444
|
|
|
445
|
+
console.error('[AdSDK] ❌ 未找到匹配的 sdkId:', targetSdkId, '数据:', data);
|
|
241
446
|
return null;
|
|
242
447
|
}
|
|
243
448
|
|
package/src/example-simple.html
CHANGED
|
@@ -39,8 +39,8 @@
|
|
|
39
39
|
|
|
40
40
|
// 初始化广告
|
|
41
41
|
new window.AdSDK({
|
|
42
|
-
appId: '
|
|
43
|
-
placementId: '
|
|
42
|
+
appId: '1999364640831725629',
|
|
43
|
+
placementId: '2003009002186760245',
|
|
44
44
|
container: '#ad-slot-1',
|
|
45
45
|
onAdLoaded: () => console.log('✅ 广告加载完成'),
|
|
46
46
|
onAdError: (err, msg) => console.log('❌ 广告报错:', err, msg),
|