AdSense 接入问题,实际上 npm 上已经有一些三方包了,正常的应用场景基本是能覆盖的,但有几个进阶的需求,便需要自己定制开发了:
- AdSense 配置需要从配置中心读取,以避免 hard code,也就是需要支持通过传入 option key 自动调用配置中心接口动态获取配置。
- 需要区分桌面端和移动端,分别设计不同的样式。
- 支持开关。
- 支持 Adblock Plus 等广告拦截插件的检测,在被屏蔽的情况下隐藏 AdSense,或者显示其他广告,比如京东联盟等。
以下是实现过程和对应的代码。
1、接入配置中心,动态获取 AdSense 配置
typescriptCopy code- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
const defaults: AdsenseConfig = {
clientId: '',
slotId: '',
format: '',
className: '',
style: '',
display: 'inline-block',
testMode: false
};
let adsenseConfig: Partial<AdsenseConfig> = {};
if (this.dynamic && this.optionKey) {
try {
adsenseConfig = JSON.parse(this.options[this.optionKey]);
} catch (e) {}
}
adsenseConfig = {
...defaults,
...adsenseConfig
};
const defaults: AdsenseConfig = {
clientId: '',
slotId: '',
format: '',
className: '',
style: '',
display: 'inline-block',
testMode: false
};
let adsenseConfig: Partial = {};
if (this.dynamic && this.optionKey) {
try {
adsenseConfig = JSON.parse(this.options[this.optionKey]);
} catch (e) {}
}
adsenseConfig = {
...defaults,
...adsenseConfig
};
通过optionKey
参数,直接读取options
中的配置,其中,options
对象通过订阅全局的 Observable 对象获取:
typescriptCopy code- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
this.optionService.options$
.pipe(
skipWhile((options) => isEmpty(options)),
takeUntil(this.destroy$)
)
.subscribe((options) => {
this.options = options;
...
});
this.optionService.options$
.pipe(
skipWhile((options) => isEmpty(options)),
takeUntil(this.destroy$)
)
.subscribe((options) => {
this.options = options;
...
});
2、区分桌面端和移动端
这个直接调用封装好的UserAgentService
即可:
xmlCopy code- 1
<div #adsense class="ads-wrap" [class.ads-wrap-desktop]="!isMobile" [class.ads-wrap-mobile]="isMobile"></div>
其中,isMobile
的值来自:
typescriptCopy code- 1
this.isMobile = this.userAgentService.isMobile();
this.isMobile = this.userAgentService.isMobile();
3、开关,Adblock Plus 检测,及备用方案
开关的实现无需多言(同样直接读取配置中心的配置),而至于 Adblock Plus 的检测,网络上的各种魔法解决方案都难免过于复杂,实际上,通过 AdSense 的调用原理,可以轻松找到解决方案。
typescriptCopy code- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
private loadAds() {
if (this.enableAds && this.platform.isBrowser && this.visible) {
const ads: Record<string, string | boolean> = {};
if (this.pageLevelAds) {
ads['google_ad_client'] = this.clientId;
ads['enable_page_level_ads'] = true;
}
if (window) {
try {
this.createAdsEle();
((window as any).adsbygoogle = (window as any).adsbygoogle || []).push(ads);
if (Array.isArray((window as any).adsbygoogle)) {
this.console.warn('Ads is blocked.');
this.hideAdsEle();
} else {
this.commonService.updateAdsFlag(false);
}
} catch (e) {
this.console.error('Ads: ', e.message || 'is not working.');
this.hideAdsEle();
}
}
} else {
this.console.warn('Ads is disabled.');
this.hideAdsEle();
}
}
private loadAds() {
if (this.enableAds && this.platform.isBrowser && this.visible) {
const ads: Record = {};
if (this.pageLevelAds) {
ads['google_ad_client'] = this.clientId;
ads['enable_page_level_ads'] = true;
}
if (window) {
try {
this.createAdsEle();
((window as any).adsbygoogle = (window as any).adsbygoogle || []).push(ads);
if (Array.isArray((window as any).adsbygoogle)) {
this.console.warn('Ads is blocked.');
this.hideAdsEle();
} else {
this.commonService.updateAdsFlag(false);
}
} catch (e) {
this.console.error('Ads: ', e.message || 'is not working.');
this.hideAdsEle();
}
}
} else {
this.console.warn('Ads is disabled.');
this.hideAdsEle();
}
}
以上代码融合了开关判断、Adblock Plus 拦截判断、隐藏 AdSense,以及发送状态通知(以调用京东联盟等)。完整效果可以直接在本页面体验。
至此,所有的需求都完美解决。[]~( ̄▽ ̄)~*
附录
完整实现代码请访问:https://github.com/ifuyun/ifuyun.com。