跳到主要内容

平台能力集成

Host SDK 支持接入方覆写部分开放给小游戏开发者的 JS 接口以集成平台方登录 SDK、广告 SDK、支付 SDK 等功能。 接入 Host SDK 的开发者可以通过 CustomCommand 接口 接入定制功能。

1 登录 SDK​

1.1 登录组件接口列表​

Host SDK 给小游戏开发者提供了的登录 JS 接口如下。

  • tj.login

    • 输入参数: Object args
    属性类型必填说明
    timeoutnumberN超时时间,单位ms
    successfunctionN接口调用成功的回调函数
    failfunctionN接口调用失败的回调函数
    completefunctionN接口调用结束的回调函数(调用成功、失败都会执行)
    • args.success 回调函数参数: Object res
    属性类型说明
    codestring调用接口获取登录凭证(code)

登录能力可通过CustomCommand覆写 tj.login 接口实现。

1.2 登录全流程​

登录全流程示意图如下:

游戏客户端通过调用tj.login(流程图中的第3步)获取code后,需要通过JS code2session获取用户的登录信息,实现用户登录。

jscode2session​

提供平台方的登录能力,宿主后台会将用户的登录凭证(code)传递给平台方,平台方需要根据该凭证返回用户的登录信息。

宿主后台会结合请求的上下文,将平台方返回的 uid 映射为游戏侧可用的 openid 和 unionid,同时转发 session_key 给游戏侧做为登录凭证。

请求示例:

GET /jscode2session?js_code={code} HTTP/1.1
Authorization: Bearer {service_token}

请求参数说明:

参数说明
js_code平台方登录凭证
Authorization服务端令牌,格式为 Bearer {service_token}

响应示例:

HTTP/1.1 200 OK
Content-Type: application/json

{
"uid": "123456"
"session_key": "abcdefg",
"errcode": 0,
"errmsg": "ok"
}

响应字段说明:

字段说明
uid平台方返回的用户唯一标识
session_key平台方返回的 session_key
errcode错误码,0 表示成功
errmsg错误信息

2 广告 SDK​

2.1 广告组件接口​

Host SDK 给小游戏开发者提供了的广告 JS 接口如下。

tj.createRewardedVideoAd()​

返回值为RewardedVideoAd,暴露的方法有:

函数名函数说明返回值
RewardedVideoAd.load()加载激励视频广告Promise
  • 激励视频广告加载数据的结果
RewardedVideoAd.show()显示激励视频广告Promise
  • 激励视频广告显示操作的结果
RewardedVideoAd.destroy()销毁激励视频广告实例
RewardedVideoAd.onLoad(function listener)监听激励视频广告加载事件。参数:function listener
  • 激励视频广告加载事件的监听函数
RewardedVideoAd.offLoad(function listener)监听激励视频广告加载事件。参数:function listener
  • onLoad 传入的监听函数。不传此参数则移除所有监听函数。
RewardedVideoAd.onError(function listener)监听激励视频错误事件。参数:function listener
  • 激励视频错误事件的监听函数
RewardedVideoAd.offError(function listener)移除激励视频错误事件的监听函数参数:function listener
  • onError 传入的监听函数。不传此参数则移除所有监听函数。
RewardedVideoAd.onClose(function listener)监听用户点击 关闭广告 按钮的事件。参数:function listener
  • 用户点击 关闭广告 按钮的事件的监听函数
RewardedVideoAd.offClose(function listener)移除用户点击 关闭广告 按钮的事件的监听函数参数:function listener
  • onClose 传入的监听函数。不传此参数则移除所有监听函数。

下面以 “创建激励视频广告” 为例子,介绍怎样覆盖广告接口,接入广告逻辑。

2.2 广告组件接口示例​

tj.createRewardedVideoAd()此接口用于创建插屏广告组件,并返回 RewardedVideoAd 实例,实例暴露的部分方法有:

  • RewardedVideoAd.load() 加载激励广告,返回一个 Promise

  • RewardedVideoAd.onLoad(callback) 接收函数作为参数,监听插屏广告加载事件

  • RewardedVideoAd.offLoad(callback) 移除插屏广告加载事件的监听函数,不传参数则移除所有

Host SDK 并不内置广告功能,仅提供了 tj.createRewardedVideoAd() 的一个默认实现,此实现返回的 RewardedVideoAd 实例暴露的方法均为空实现,小游戏开发者调用 RewardedVideoAd.load() 并不能真实加载激励广告。

因此接入方 App 需要覆写此 tj.createRewardedVideoAd(),使得 RewardedVideoAd.load() 内调用 App 内接入的第三方广告 SDK 的加载接口,同理实现 RewardedVideoAd 暴露的其他接口以实现广告功能的集成。

接入方 App 可在工程内提供若干自定义 JS 文件用于覆写 JS 接口,并在设置游戏启动参数时指定自定义 JS 文件的路径。

可以参考 Demo 中添加的用于覆写广告接口的 JS 文件 ad.js 后,设置游戏启动参数如下:

var files: [String] = []

if let adJsUrl = Bundle(for: type(of: self)).url(
forResource: "ad",
withExtension: "js")
{
files.append(adJsUrl.path)
}

options[TJConstants.CUSTOM_SCRIPT_FILES] = files

Host SDK 会读取该文件,并使用文件内定义的方法覆写 Host SDK 提供的 JS 接口。

2.3 接入第三方广告 SDK​

以集成说明所述激励广告 API 为例,可参考 Demo 项目中 ad.js 如下:

let rewardedVideoAdOnLoadCallbacks = [];

tj.createRewardedVideoAd = (obj) => {
return {
onLoad: (callback) => {
console.info("[Host] invoke RewardedVideoAd.onLoad");
if (callback && typeof callback === "function") {
if (!rewardedVideoAdOnLoadCallbacks.includes(callback)) {
rewardedVideoAdOnLoadCallbacks.push(callback);
}
}
},
load: () => {
console.info("[Host] invoke RewardedVideoAd.load");

tj.customCommand("loadRewardAd", {
success: function (res) {
console.info("[Host] RewardedVideoAd.load success");
},
fail: function (obj) {
console.info("[Host] RewardedVideoAd.load fail");
},
complete: function () {
console.info("[Host] RewardedVideoAd.load complete");
},
});
},
offLoad: (callback) => {
console.info("[Host] invoke RewardedVideoAd.offLoad");
if (callback === undefined) rewardedVideoAdOnLoadCallbacks = [];
else if (callback && typeof callback === "function") {
rewardedVideoAdOnLoadCallbacks = rewardedVideoAdOnLoadCallbacks.filter(
(cb) => cb !== callback
);
}
},
// Other RewardedVideoAd methods ...
};
};

rewardedVideoLoadCallback = () => {
try {
rewardedVideoAdOnLoadCallbacks.forEach((callback) => callback());
} catch (error) {
console.error("[Host] Error in rewardedVideoLoadCallback:", error);
}
};

在此 ad.js 中,通过定义 tj.createRewardedVideoAd 实现了对其默认实现的覆写,并在其返回的 RewardedVideoAd 实例的 load() 方法内使用 CustomCommand(用于 JS 与 App 之间的相互调用,具体可参考 API Reference)

设置监听 loadRewardAd 的代码如下:

gameHandle.setCustomCommandListener("loadRewardAd") { _, handle in
guard let gameHandle = self.gameHandle else {
return
}

handle.success(result: [:])
}

// 广告拉起后通知 js 回调
gameHandle.runCustomScript("""
rewardedVideoLoadCallback();
""") { _, _ in
TJLogger.debug("[\(Config.APP_LOG_TAG)] load success ad.")
}

在 Demo 示例中,监听到来自 JS 的 loadRewardAd 调用后,执行 Ad SDK API 加载激励广告,并在加载完成的回调内再通过 CustomCommand 调用 JS 方法 rewardedVideoLoadCallback() 通知 JS 侧执行小游戏开发者注册的回调,从而实现小游戏开发者调用 Host JS 接口到 SDK API 再到小游戏开发者注册的 JS 回调的完整逻辑。

3 支付 SDK​

3.1 流程图​

3.1.1 小游戏支付​

3.1.2 主动查询订单​

3.2 客户端接口​

tj.requestPayment(Object obj)​

参数说明

属性名类型默认值必填说明
modestringgame是支付的类型,枚举值
  • game -目前仅支持该类型
envnumber0是环境配置,枚举值
  • 0 - 表示支付正式环境,目前仅支持该类型
currencyTypestringCNY是币种,枚举值
  • CNY - 表示人民币
  • VND - 表示越南盾
  • EUR - 表示欧元
  • ...
platformstring是申请接入时的平台,android或者ios
buyQuantitynumber否所购买的数量
zoneIdstring1否游戏服务区 id,开发者自定义。游戏不分大区则默认填写"1"
customIdstring是游戏开发者自定义的唯一订单号,订单支付成功后通过服务端支付结果回调回传。必须具有唯一性,如果不传或重复传相同值,则会报错。
extraInfostring否游戏开发者自定义的其他信息,订单支付成功后通过服务端支付结果回调回传。字符串长度最大不能超过 256。
goodTypenumber2否支付场景,枚举值
  • 2 - 表示道具直购场景,目前仅支持该类型
orderAmountnumber是代表道具现金价格,单位为【人民币分】
goodNamestring是goodType为道具直购场景时,代表道具名称,长度限制小于等于10个字符,用于区分道具类型
optionsmap否扩展参数,可以根据平台需求定制
successfunction否接口调用成功的回调函数
failfunction否接口调用失败的回调函数
completefunction否接口调用结束的回调函数(调用成功、失败都会执行)

3.2.1 回调成功参数​

Object类型,属性如下

属性名类型说明
errMsgstringrequestPayment:ok

3.2.2 回调失败参数​

Object类型,属性如下

属性名类型说明
errMsgstring"requestPayment:fail " + 错误详情
errCodenumber错误码,对应信息可参考错误码说明

3.2.3 回调结束参数​

Object类型,属性如下

属性名类型说明
errMsgstringrequestPayment:ok

3.2.4 错误码说明​

根据实际支持情况映射

errCodeerrMsg说明
-1requestPayment:fail 支付失败用户支付失败
-1requestPayment:fail internal error小游戏框架内部错误
-2requestPayment:fail 支付取消用户取消支付
3requestPayment:fail error_tip_start_cash_register_fail拉起收银台失败,如遇小游戏框架内部错误
4requestPayment:fail 网络异常用户网络异常
-15002requestPayment:fail 请求参数不合法请求参数不合法
-15006requestPayment:fail app 没有支付权限请确认是否设置游戏币汇率
-15098requestPayment:fail 当前用户未通过实名认证当前用户未通过实名认证
-15099requestPayment:fail 当前用户累计支付金额超过限制当前用户累计支付金额超过限制
-15101requestPayment:fail customId 为空或者不唯一customId 为空或者不唯一
-16000requestPayment:fail 用户未登录用户未登录
-20002requestPayment:fail 交易存在风险交易存在风险,被风控策略拦截
21113requestPayment:fail face authentication failed检测到疑似未成年下单,拉起人脸核验,人脸验证不通过

3.2.5 示例代码​

tj.requestPayment({
mode: 'game',
env: 0,
currencyType: 'CNY',
platform: 'ios',
zoneId: '1',
customId: 'order_' + Date.now(),
extraInfo: JSON.stringify({
orderId: 'test_order_' + Date.now(),
userId: '10001'
}),
goodType: 2,
orderAmount: 100,
goodName: '去广告',
options: {
'PRODUCT_CODE': '1001'
},
success: function success(res) {
console.log('[游戏JS端] 支付成功:', res);
tj.showToast({
title: '支付成功,再来一局!',
duration: 2000
});
},
fail: function fail(err) {
if (err.errCode && err.errCode == -2) {
console.log('[游戏JS端] 用户取消支付');
tj.showToast({
title: '支付取消,请重新支付!',
duration: 2000
});
} else {
console.error('[游戏JS端] 支付失败:', err);
tj.showToast({
title: '支付失败,请重试!',
duration: 2000
});
}
},
complete: function complete(res) {
console.log('[游戏JS端] 支付流程结束:', res);
}
})

3.3 服务端接口​

3.3.1 服务端回调接口​

支付成功后,平台方服务端向宿主服务端发送支付成功回调。宿主服务端在验签后将回调发送给游戏服务端。

3.3.1.1 回调地址​

POST https://minihost.tuanjie.cn/game-api/v1/payment/callback

3.3.1.2 请求参数​
参数名类型说明
timestampstring时间戳
noncestring随机数
msgstringJson string类型的支付结果信息,参见2.1.3PaymentInfo对象
signaturestring签名,签名算法参见2.1.4签名部分
3.3.1.3 PaymentInfo​
参数名类型说明
appidstring平台方小游戏appid
cp_ordernostring开发者自定义订单号,tj.requestPayment方法中的customId参数
cp_extrastring开发者传的额外参数,tj.requestPayment方法中的extra参数
order_no_channelstring小游戏后台交易单号
amount_centint64订单金额,单位人民币分
amount_coinint64购买游戏币数量,平台方集成中不涉及该场景,可忽略
currencystring支付币种,CNY 人民币,DIAMOND 钻石
3.3.1.4 签名​

根据 token,timestamp,nonce,msg ,使用 SHA1 算法生成 signature,与平台方的服务端返回的 signature 对比。

前置条件:在关联游戏时,平台方需要将token传递给宿主,用于签名校验

golang示例代码:

sortedString := make([]string, 4)
sortedString = append(sortedString, token)
sortedString = append(sortedString, timestamp)
sortedString = append(sortedString, nonce)
sortedString = append(sortedString, string(msg))
sort.Strings(sortedString)h := sha1.New()
h.Write([]byte(strings.Join(sortedString, "")))_signature := h.Sum(nil)
3.3.1.5 响应​

宿主服务器返回200状态码,作为成功响应。若返回 http 状态码非200,表示通知失败,需要进行重试。

3.3.2 主动查询订单接口​

服务端支付回调可能由于网络异常等原因导致无法 100%触达,开发者可以通过该接口主动回查订单状态,防止超发漏发。开发者向宿主服务端发送查询订单请求,宿主封装后向平台方服务端发送查询订单请求。

3.3.2.1 接口地址​

由平台方提供

3.3.2.2 请求参数​
参数名类型说明
tokenstring双方约定服务端token
ordernostringcp 自定义订单号,在下单的时候传入,tj.requestPayment方法中的customId参数
3.3.2.3 响应​
参数名类型说明
statusstring支付状态。success 表示支付成功且发币到账,unsuccess 表示支付失败
3.3.2.4 鉴权​

请求需包含双方约定好的服务器令牌,放在Auhthorization header里,格式形如

Bearer {service_token}