CocosCreator优雅的集成跨平台广告SDK

前言

原来开发游戏可能仅需考虑安卓(GooglePlay)和苹果(AppStore),后来国内各大厂商也开始要求接入自己的sdk,现在又有一堆的小游戏平台,要编写跨平台代码,我们可能需要各种适配。一些跨平台的游戏,可能最常见的代码就是

1
2
3
4
5
if(Android原生) {
} else if(ios原生) {
} else if(微信小游戏) {
}
...

这种ifelse多层结构非常影响到代码的可读性,得益于CocosCreator产品的优秀跨平台能力,我们可以减轻很多适配的工作量。但是对于广告SDK这种百花齐放的产品,可能Cocos官方也应顾不暇,那我们程序员该如何跨平台呢?

Flag: 后期我将开源整合各家原生广告的DEMO

flag能不能实现,暂且不说,其实按照下面这种方式集成,后期非常容易聚合各类广告平台。

基本步骤

  1. 参考微信小游戏的api实现我们自己的api
  2. 在cocos里借助.d.ts代码实现代码提示
  3. 在build-templage里面实现各平台的调用

定义api

下面我们以激励视频api为例,实现我们的api

CCC已经支持ES6了,如果没有跨引擎的需求,也可以直接使用ES6语法来写

1
2
3
4
5
6
7
8
9
10
11
12
13
var RewardedVideoAd = function () {
this.load = function () { }
this.show = function () { }
this.destroy = function () { }
this.onLoad = function () { }
this.offLoad = function (callback) { }
this.onError = function (callback) { }
this.offError = function (callback) { }
this.onClose = function (callback) { }
this.offClose = function (callback) { }
}
var zz = {};
zz.createRewardedVideoAd = function (object) { }

总得来说,可以理解成我们把wx换成了zz(任何一个你喜欢的变量都行,只要你保证这个字段不冲突,比如cc就不行了)

定义.d.ts文件

这一步并不是必须的,但是对于ts开发而言,有代码提示简直是另一个天地。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class RewardedVideoAd {
load(): Promise;
show(): Promise;
destroy(): void;
onLoad(): void;
offLoad(callback: () => void): void;
onError(callback: (res: { errCode?: number, errMsg: string }) => void): void;
offError(callback: Function): void;
onClose(callback: (res: { isEnded: boolean }) => void): void
offClose(callback: Function): void
}
declare namespace zz {
export function createRewardedVideoAd(object: { adUnitId: string, multiton?: boolean }): RewardedVideoAd;
}

实现跨平台代码

小游戏平台的代码

我们这里以微信为例接入

因为我们的api就是参考微信官方的,相对编写就比较简单了,等于是复写了一遍api而已~

1
2
3
4
5
6
7
(function () {
let zz = {};
zz.createRewardedVideoAd = function (object) {
return wx.createRewardedVideoAd(object);
}
window.zz = zz;
})();

这里直接替换也是可以的,但是这样写的方便后期我们的扩展,比如新增的api版本判断等。

原生平台的代码

这里我们以安卓平台及穿山甲为例

脚本调用,主要是js与原生调用,比如创建激励视频

1
jsb.reflection.callStaticMethod('com/xyzzlky/test/BU', 'createRewardedVideoAd', '(Ljava/lang/String;)Z', adUnitId);

以及各种回调接收事件,比如加载结果

1
2
3
4
5
6
7
zz.loadRVResult = function (adUnitId, res) {
if (res) {
rvAd[adUnitId].loadResolve && rvAd[adUnitId].loadResolve();
} else {
rvAd[adUnitId].loadReject && rvAd[adUnitId].loadReject();
}
}

集成SDK的代码,穿山甲官方都有文档,这一块涉及游戏的内容不多,我就不再赘述,如有需求,请直接参考我的demo。

将代码引入

避免破坏项目工程,我们不要将这些文件放到工程里,而且如果平台较多,看着也不优雅,借助build-templates的平台定制(也可以自行写脚本实现),我们可以针对平台进行脚本加入。

  1. 微信平台引入

我们在game.js中引入我们的脚本即可

1
2
// 这里推荐通过插件写入,达到跨引擎版本的作用
require('zz-ccc.js');
  1. 原生平台的引入在main.js中引入
    1
    require('src/zz-ccc.js');
    如果不是在src、jsb-adapter、res文件夹下,则你需要在gradle中写好移动语句,参考官方的写法
    1
    2
    3
    4
    copy {
    from "${sourceDir}/res"
    into "${outputDir}/res"
    }

调用

脚本调用

1
2
3
4
5
6
7
8
9
10
11
12
// 因为每个平台的广告id不一样,推荐这里使用虚拟的广告位id,在各个平台通过后台换取真实adUnitId,当然也可以设置成object,区分各个平台的adUnitId
this.ad = zz.createRewardedVideoAd({ adUnitId: '代码位' });
this.ad.load().then(() => {
console.log('加载成功');
this.ad.show().then(() => {
console.log('显示成功');
}).catch(() => {
console.log('显示失败');
});
}).catch(() => {
console.log('加载失败');
});

调试问题

当为调试模式,则可以添加一个调试文件,让该文件仅在调试期间作用

1
2
3
4
if (CC_PREVIEW) { 
// ...
window.zz = zz;
}

可以通过对话框的形式,模拟加载和显示

1
var r = confirm('广告是否加载成功');

调试效果

如此一来,我们的代码就不必顾忌平台的差异了,如果增加了平台对我们而言可能就是加一个js文件而已,而且请注意这些代码都是跨项目通用的哦。

END

细心的小伙伴可能发现了,这种集成方式,跟我以前介绍的小游戏快速转制APP的方法非常相像,没错,其实就是用的那套原理,只是这里针对的是单一的广告对接。so,如果你将微信的api全部在多平台实现一套,那么恭喜你,你的游戏就可以一键发布到原生平台了。如果你还关注了我的【自动化构建】,那么只要你提交了代码,你就可以构建所有平台的产品了~

本次涉及各个平台代码较多,我这边将需要改动的代码放到了build-templates下面,各位根据需求修改即可。关注公众号,回复[ad]即可获取demo。