接入文档
当前页面用于完成Unity游戏发布安卓和ios版本的接入
一、SDK接入步骤
开发前准备
广告位文档、上报埋点统计文档。@运营同学
导入SDK插件
Unity游戏:将
DN_PLUGIN_UNITY.unitypackage
插件,导入到游戏unity工程。
下载链接:https://gui.vigame.cn/CP/Unity/UnityPackage/DN_PLUGIN_UNITY_2.1.9_C.unitypackage
Android接入
使用模板接入,模板工程已接入sdk所需要的配置。只需将游戏unity工程Android导出,将资源和lib等文件拷贝到对应文件中即可。
下载链接:https://gui.vigame.cn/CP/Unity/build-templates/build-templates.zip
模板工程目录结构:

替换unity-classes.jar
文件:

替换so
文件:

替换资源文件:

修改游戏icon和名称

修改启动页闪屏图

操作完上述步骤后即可运行工程,查看游戏内容。
关于包名
由动能打包时,自行更换正式包名。
关于签名
如无特殊要求,正式包会使用动能的签名文件。
iOS接入
Unity直接选择File->Build Setting导出iOS工程,并将xcode工程提供给动能以进行iOS打包。

iOS授权和证书
1、需要授予我们公司appid账号(appstore@bubbleteastudios.cc)app管理权限,如下图所示

2、需提供发布证书的dev,dis类型的p12(包括密码),以及这两个发布证书对应的dev,dis描述文件


接入iOS模拟测试模块
1、clone自动化脚本到工程目录
2、安装插件
gem install plist
gem install xcodeproj
2、执行脚本
sh ./vigame/auto.sh b3e75b912e672146
3、出包测试
二、常用接口
基础(必接)
日志打印
调用该接口后会开启日志输出
/// <summary>
/// 日志打印开关
/// </summary>
/// <param name="isDebug">true是可打印日志,false否不打印日志</param>
public void SetDebug(bool isDebug)
隐私政策和用户协议(必接)
示例
// 隐私政策
Wb.CoreManager.Instance.OpenPrivacyPolicy();
// 用户协议
Wb.CoreManager.Instance.OpenUserAgreement();
签名验证 (防止盗版包必接)
游戏开始时,需要签名验证,调用该方法验签,只有动能认可的签名信息才能通过验证。
/// <summary>
/// 签名验证
/// </summary>
/// <param name="successCall">成功回调</param>
/// <param name="failCall">失败回调</param>
public void CheckSignature(UnityAction successCall, UnityAction failCall)
示例
Wb.CoreManager.Instance.CheckSignature(delegate ()
{
//验签成功,正常进入游戏
},
delegate ()
{
//验签失败,直接闪退等
});
自测
过滤日志CheckSign查看验签结果
可以使用其他签名文件签名,签名apk运行后是否启动闪退。
广告(必接)
本地广告配置
可以拷贝模板工程 build-templates\wbLibrary\src\main\assets\ADPositions.xml 中的配置添加游戏使用的广告位(广告位不可是中文等特殊字符),添加到游戏工程资源目录测试。
<?xml version="1.0" encoding="utf-8"?>
<appid>10001</appid><!------- 限定调试包使用,请勿修改参数 ----->
<channel>baibao</channel><!------- 限定调试包使用,请勿修改参数 ----->
<adlist>
<ad>
<type>splash</type>
<positions>splash,game_awaken</positions>
</ad>
<ad>
<type>banner</type>
<positions>banner</positions>
</ad>
<ad>
<type>plaque</type> <!------- 插屏 ----->
<positions>pause,exit_game</positions>
</ad>
<ad>
<type>video</type> <!------- 视频 ----->
<positions>home_mfzs,level_win_mfzs</positions>
</ad>
<ad>
<type>msg</type>
<positions>game_msg,yuans,load_msg,tx_msg</positions>
</ad>
<ad>
<type>icon</type>
<positions>mini_video,chouj</positions>
</ad>
</adlist>
广告是否准备好(选接)
/// <summary>
/// 广告是否准备好
/// </summary>
/// <param name="adName">广告位</param>
public bool IsAdReady(string adName)
关卡是否可以打开该广告(选接)
/// <summary>
/// 关卡是否可以打开该广告
/// </summary>
/// <param name="adName">广告位</param>
/// <param name="level">关卡</param>
public bool IsAdBeOpenInLevel(string adName, int level)
获取原生广告参数(选接)
/// <summary>
/// 获取广告参数
/// </summary>
/// <param name="adName">广告位</param>
/// <returns></returns>
public string GetNativeData(string adName)
打开嵌入式广告(选接)
/// <summary>
/// 打开嵌入式广告
/// </summary>
/// <param name="adName">广告位</param>
/// <param name="showRect">展示区域</param>
/// <param name="clickRect">点击区域数组</param>
/// <param name="callBackFun1">关闭广告回调</param>
/// <param name="callBackFun2">打开成功失败回调</param>
public void ShowMsgAD(string adName, RectTransform showRect, RectTransform[] clickRect, ADCallback callBackFun1 = null, ADCallback callBackFun2 = null)
打开广告(必接)
/// <summary>
/// 打开广告
/// </summary>
/// <param name="adName">广告位名称</param>
/// <param name="callBackFun">广告关闭回调</param>
/// <param name="adStartFun">广告播放状态回调(可不设置回调)</param>
public void OpenAd(string adName, ADCallback callBackFun = null, AdStartCallback adStartFun = null)
打开信息流广告(选接)
/// <summary>
/// 打开信息流广告
/// </summary>
/// <param name="rect">广告展示区域,锚点为中心</param>
/// <param name="adName">广告位</param>
public void OpenYsAd(RectTransform rect, string adName = "yuans")
示例
//打开视频广告
public void OpenVideo()
{
Wb.ADManager.Instance.OpenAd("home_mfzs", (result, resultParam) =>
{
if (result == Wb.ADResult.NotReady)
{
Debug.Log("广告未准备好~");
}
else if (result == Wb.ADResult.Success)
{
Debug.Log(resultParam.ToString());
Debug.Log("广告打开成功~");
}
else
{
Debug.Log(resultParam.ToString());
Debug.Log("广告打开失败~");
}
});
}
//打开插屏广告
public void OpenPlaque()
{
Wb.ADManager.Instance.OpenAd("pause", (result, resultParam) =>
{
if (result == Wb.ADResult.NotReady)
{
Debug.Log("广告未准备好~");
}
else if (result == Wb.ADResult.Success)
{
Debug.Log(resultParam.ToString());
Debug.Log("广告打开成功~");
}
else
{
Debug.Log(resultParam.ToString());
Debug.Log("广告打开失败~");
}
});
}
//打开banner广告
public void OpenBanner()
{
Wb.ADManager.Instance.OpenAd("banner");
}
统计(必接)
列举的接口根据游戏实际情况使用,事件id参数使用上报文档中的参数填写。游戏自定义事件通过自定义上报接口进行上报。
自定义事件(选接)
单独事件
/// <summary>
/// 单独事件上报
/// </summary>
/// <param name="eventId">事件id,可根据统计文档填写</param>
public void TJCustomEvent(string eventId)
app_loading_show和app_home_show推荐接入,以便于分析启动漏斗转化。
事件名称
事件ID
触发时机
附加参数
游戏loading页面
app_loading_show
游戏引擎初始化后就触发上报
无
游戏内首页
app_home_show
主页展示时
无
示例
//进入冷启动Loading页面时
Wb.TjManager.Instance.TJCustomEvent("app_loading_show");
//进入游戏首页时
Wb.TjManager.Instance.TJCustomEvent("app_home_show");
携带标签上报
/// <summary>
/// 上报
/// </summary>
/// <param name="eventId">事件id,可根据统计文档填写</param>
/// <param name="label">label内容</param>
public void TJCustomEvent(string eventId, string label)
示例
Wb.TjManager.Instance.TJCustomEvent("事件id","label内容");
多属性上报
/// <summary>
/// 多属性上报
/// </summary>
/// <param name="eventId">事件id,可根据统计文档填写</param>
/// <param name="attributes">attributes</param>
public void TJCustomEvent(string eventId, Dictionary<string, string> attributes)
示例
//关卡触发的自定义事件
Dictionary<string, string> ps = new Dictionary<string, string>();
ps["level"] = level.ToString();
ps["skinID"] = skinID.ToString();
ps["boost"] = boost ? "1" : "0";
Wb.TjManager.Instance.TJCustomEvent("事件id", ps);
//视频广告奖励按钮显示时,检查广告是否已准备好。如没有准备好,则需要隐藏视频按钮;如果准备好,则显示按钮,并调用此方法统计。
Dictionary<string, string> ps = new Dictionary<string, string>();
ps["ad_pos"] = adName;
Wb.TjManager.Instance.TJCustomEvent("ad_video_ready", ps);
关卡开始(必接)
/// <summary>
/// 关卡开始
/// </summary>
/// <param name="level">关卡id</param>
public void StartLevel(string level)
示例
Wb.TjManager.Instance.StartLevel("1");
关卡获胜(必接)
/// <summary>
/// 关卡获胜
/// </summary>
/// <param name="level">关卡id</param>
/// <param name="score">得分</param>
public void FinishLevel(string level, string score)
示例
Wb.TjManager.Instance.FinishLevel("1", "100");
关卡失败(必接)
/// <summary>
/// 关卡失败
/// </summary>
/// <param name="level">关卡id</param>
/// <param name="score">得分</param>
public void FailLevel(string level, string score)
示例
Wb.TjManager.Instance.FailLevel("1", "10");
商店联运
如您的游戏不需要在商店进行上线,可直接跳过。
游戏退出(必接)
游戏退出时先判断是否支持第三方退出,支持则调用SDK接口,不支持则调用游戏本身的退出逻辑。用例参考
void Update()
{
if (Input.GetKeyDown(KeyCode.Escape))
{
if (Wb.PayManager.Instance.IsSupportExit())
{
//如果支持退出,则调用openExitGame接口
Wb.PayManager.Instance.OpenExitGame();
} else {
//否则展示游戏的退出窗口
}
}
}
反馈邮箱(必接)
在设置界面显示邮箱信息,获取到数据就显示,没有就不显示。
安卓:读取assets/ConfigVigame.xml中的Email字段。
iOS:读取VigameLibrary.plist中的Email字段。
//get email config from ConfigVigame.xml
string str = Wb.CoreManager.Instance.getConfigVigameValue("Email");
if (str.Length == 0)
{
//not have the Email config
}
else
{
// have the Email config show the config on Setting.
}
更多精彩(必接)
先判断是否显示更多精彩按钮结果返回true才显示
否显示更多精彩按钮
/// <summary>
/// 否显示更多精彩按钮
/// </summary>
public bool IsMoreGameBtn()
打开更多精彩
/// <summary>
/// 打开更多精彩
/// </summary>
public void OpenMoreGame()
示例
//否显示更多精彩按钮
Wb.PayManager.Instance.IsMoreGameBtn();
//打开更多精彩
Wb.PayManager.Instance.OpenMoreGame();
按钮资源

增值功能(选接)
客服中心
/// <summary>
/// 打开客服中心
/// </summary>
/// <param name="title">网页标题</param>
/// <param name="loginId">用户id</param>
public void OpenClientCenter(string title, string loginId)
支付和补单
如您的游戏不需要支付功能,可直接跳过。
支付流程

客户端补单流程

1. 支付
1.1 支付接口
有两种方式创建 PayParam 对象,根据使用的构造函数不同区分是否使用 sdk 计费配置。
调用支付接口 sdk 会自动上报内购统计 pay_purchase 事件。
userdata 为用户自定义数据,由于支付平台的限制,该数据长度限制在16个字符内,超过长度限制数据会被截取(已使用 custom 字段代替)。
custom 为用户自定义数据,只在 sdk 服务器生效不会向支付平台传递,长度限制在128个字符内,超过长度限制数据会被截取(服务端回传数据时可使用该字段传入自定义数据)。
/// <summary>
/// 通用-内购统计支付
/// </summary>
/// <param name="payParam">支付参数</param>
/// <param name="callFun">支付回调</param>
public void OrderPay(PayParam payParam, OrderPayCallbackHandler callFun)
参数说明:
payId 计费点id
price 金额(单位分)
payDesc 商品描述
payCode 支付code,没有填写计费点payId
giftId 礼包id,没有的话写计费点payId
giftType 礼包类型,没有填写空 非必传
giftNum 礼包数量,一次购买了几份,最小值为1
giftPrice 礼包价值,没有可填写price金额值(单位分)
levelId 有用户等级的传用户等级,没有用户等级的游戏传关卡id
tokenType 代币类型(当礼包类型为代币礼包时,传参。否则传空串)非必传
custom 用户自定义数据,最长128个字符(不会上传给平台) 非必传
userdata 用户自定义数据,由于支付平台的限制,最长16个字符(微信支付有效) 非必传
payPush 礼包推送:1主动点击;0被动推送 非必传
userId 户的账号ID,无账号游戏为空。最长128个字符 非必传
extParams 额外参数,传参后支付事件上报时携带该数据 非必传
Unity使用计费点配置示例
var payParam = new Wb.PayParam(payId, giftId, giftType, giftNum, giftPrice, levelId, tokenType, custom, payPush, userId);
payParam.extraParam.Add("k1", "自定义参数1");
payParam.extraParam.Add("k2", "自定义参数2");
Wb.PayManager.Instance.OrderPay(payParam, (result, id, userData, orderInfo) =>
{
if (result == Wb.PayStatus.PaySuccess)
{
Debug.Log("支付成功 orderInfo = " + orderInfo);
}
else if (result == Wb.PayStatus.PayFail)
{
Debug.Log("支付失败 orderInfo = " + orderInfo);
}
else if (result == Wb.PayStatus.PayCancel)
{
Debug.Log("支付取消 orderInfo = " + orderInfo);
}
});
Unity不使用计费点配置示例
var payParam = new Wb.PayParam(payId, price, payDesc, payCode, giftId, giftType, giftNum, giftPrice, levelId, tokenType, custom, payPush, userId);
payParam.extraParam.Add("k1", "自定义参数1");
payParam.extraParam.Add("k2", "自定义参数2");
Wb.PayManager.Instance.OrderPay(payParam, (result, id, userData, orderInfo) =>
{
if (result == Wb.PayStatus.PaySuccess)
{
Debug.Log("支付成功 orderInfo = " + orderInfo);
}
else if (result == Wb.PayStatus.PayFail)
{
Debug.Log("支付失败 orderInfo = " + orderInfo);
}
else if (result == Wb.PayStatus.PayCancel)
{
Debug.Log("支付取消 orderInfo = " + orderInfo);
}
});
2. 游戏发奖
2.1 游戏发奖
服务器发奖的游戏可以直接跳过该部分。
客户端发奖有可能会出现补单情况,需监听补单回调2.1.1 设置补单回调
,然后进行2.1.2充值到账上报
。
2.1.1 设置补单回调
/// <summary>
/// 设置补单回调
/// 请在合适时机调用该接口开启sdk补单逻辑
/// </summary>
/// <param name="callFun">支付回调</param>
public void SetInventoryCallBack(OrderPayCallbackHandler callFun)
示例
//设置补单回调
Wb.PayManager.Instance.SetInventoryCallBack((status, payId, userData, orderId) => {
Debug.Log($"pay 补单回调 status = {status}, payId = {payId}, userData = {userData}, traceId = {traceId}");
});
2.1.2 充值到账上报
充值成功后下发道具后进行上报(补单或非补单都要上报),需要自己调用TJPayOnAccount,接口内会自动上报pay_on_account事件,同时会触发消耗订单(微信米大师支付例外,因为米大师支付需要先扣币,扣币后服务器会自动消单)。 参数 tradeId 使用1.支付
回调返回的 tradeId 。
/// <summary>
/// 充值道具到账后上报
/// </summary>
/// <param name="tradeId">订单id</param>
public void TJPayOnAccount(string tradeId)
2.2 服务端发奖
推荐的对接流程如下:

用户数值由服务器统一管理的游戏,可直接由游戏服务器接收支付结果和发奖,可从根本上解决掉单的问题。整体流程可以参考下面的校验逻辑。 客户端支付成功后,sdk服务器会将充值结果通知游戏服务器,游戏服务器根据订单支付结果进行道具下发、到账上报、消单等操作。
3. 支付相关事件上报
3.1 代币变化上报
玩家游戏过程中虚拟货币发生变化时进行上报。内购上报统计事件为pay_token_change
。 示例
//以下参数仅供参考,以实际游戏为准
Dictionary<string, string> attributes = new Dictionary<string, string>();
attributes.Add("appid", Wb.CoreManager.Instance.GetAppid());
attributes.Add("pid", Wb.CoreManager.Instance.GetPrjid());
attributes.Add("level_id", "关卡ID(数值)");
attributes.Add("token_type", "代币类型(1金币,2钻石,3体力)");
attributes.Add("before_token", "变化前数量");
attributes.Add("change_token", "变化数量");
attributes.Add("after_token", "变化后数量");
attributes.Add("add_reduce", "增减标志(1增加, 2减少)");
attributes.Add("reason", "变化原因,新产品采用全新reason编号游戏内资产变化reason");
attributes.Add("scene", "场景(eg: 1游戏结束时、2游戏过程中、3商城)");
Wb.TjManager.Instance.TJCustomEvent("pay_token_change", attributes);
在线参数
1. 获取游戏在线参数配置
/// <summary>
/// 获取游戏在线参数
/// </summary>
/// <param name="version">配置版本, 没有特殊指定填1</param>
/// <param name="callFun">回调</param>
public void InitGameConfig(int version, GameConfigCallback callFun)
2. 根据key获取参数
/// <summary>
/// 根据key获取参数
/// </summary>
/// <param name="key">关键字</param>
/// <returns>参数值</returns>
public string GetGameConfigValue(string key)
示例
//请求游戏参数配置
Wb.CoreManager.Instance.InitGameConfig(1, (result) =>
{
if (result)
{
//获取成功,根据key获取参数
string str = Wb.CoreManager.Instance.GetConfigValue(inputValue);
Debug.Log("根据key获取参数 value = " + str);
}
else
{
//获取失败
Debug.Log("获取失败~");
}
});
兑换码
1. 兑换码开关
自定义配置参数 key:dhm
2. 使用兑换码
/// <summary>
/// 使用兑换码
/// </summary>
/// <param name="dhm">兑换码id</param>
/// <param name="callFun">回调</param>
public void UseCDKey(string dhm, Action<CDKeyState, string, string> callFun)
兑换码状态
// 兑换码状态
public enum CDKeyState
{
Success = 200, // 成功
ParamError = 401, // param is error 参数验证不通过
UnOperate = 402, // 无效操作
Invalid = 403, // 兑换码无效
Used = 405, // 兑换失败,当前兑换码已经被使用过了
UnUse = 406, // 当前兑换码已经失效
Repeat = 407, // 不能重复使用
UnExist = 408, // 兑换码不存在
Busy = 505, // 系统繁忙
}
示例
Wb.CoreManager.Instance.UseCDKey("兑换码", (state, value, msg)=>{
if(Wb.CDKeyState.Success == state) {
// CDKey Success value = {"test":"11","te":"22"} msg = 兑换成功
Debug.Log("CDKey Success value = " + value + " msg = " + msg);
} else {
Debug.Log("CDKey Fail value = " + value + " msg = " + msg);
}
});
3. 获取兑换码信息
/// <summary>
/// 获取兑换码信息
/// </summary>
/// <param name="dhm">兑换码</param>
/// <param name="callFun"></param>
public void GetCDKeyInfo(string dhm, Action<CDKeyState, string, string> callFun)
兑换码状态
// 兑换码状态
public enum CDKeyState
{
Success = 200, // 成功
ParamError = 401, // param is error 参数验证不通过
UnOperate = 402, // 无效操作
Invalid = 403, // 兑换码无效
Used = 405, // 兑换失败,当前兑换码已经被使用过了
UnUse = 406, // 当前兑换码已经失效
Repeat = 407, // 不能重复使用
UnExist = 408, // 兑换码不存在
Busy = 505, // 系统繁忙
}
示例
Wb.CoreManager.Instance.GetCDKeyInfo("兑换码", (state, value, msg) => {
//Debug.Log("CDKey info value = " + value + " msg = " + msg);
});
回调value示例
生成兑换码时配置了如下格式的value,查询成功将下发配置的value
{"rewards":[{"type":1,"name":"钞票","num":5},{"type":2,"name":"票券","num":10}]}
三方账号登录
获取渠道包登录类型适用vivo,huawei,xiaomi,oppo渠道。
LoginType loginType = Wb.SocialManager.Instance.GetLoginType();
1. 登录
登录类型
// 登录类型
public enum LoginType
{
TYPE_NULL = 0,
TYPE_WX = 1,
TYPE_QQ = 2,
TYPE_FACEBOOK = 3,
TYPE_MSDK = 4,
TYPE_AliGame = 5,
TYPE_Downjoy = 6,
TYPE_Vivo = 7,
TYPE_AliPay = 8,
TYPE_Common = 9, // 模拟登陆
TYPE_Huawei = 10,
TYPE_Xiaomi = 11,
TYPE_Oppo = 12,
CopyRight = 13 //版号包登录
}
示例
LoginType loginType = Wb.SocialManager.Instance.GetLoginType();
Wb.SocialManager.Instance.Login(loginType, (result) =>
{
if (result)
{
// 登录成功
}
else
{
// 登录失败
}
});
2. 获取用户信息
获取用户信息时账号未登录会拉起登录后再获取信息
示例
LoginType loginType = Wb.SocialManager.Instance.GetLoginType();
Wb.SocialManager.Instance.GetUserInfo(loginType, (result,info) =>
{
if (result)
{
// info 为返回的对象,可以使用下面方法获取具体信息
// public string GetOpenId();
// public string GetAccessToken();
// public string GetNickName();
// public string GetHeadImgUrl();
// 获取用户信息成功
Debug.Log("Social OpenId = " + info.GetOpenId());
Debug.Log("Social accesstoken = " + info.GetAccessToken());
}
else
{
// 获取用户信息失败
Debug.Log("获取用户信息失败 msg = " + info. ToString());
}
});
服务器响应示例
{
"reason": "登陆成功",
"openid": "86eb5d1f-ebf2-48a0-9e90-b7aab5210423",
"nickname": "模拟登陆",
"retCode": "1",
"token": "83bf4c31-b37b-4789-aa1d-40bd1b58d04f==",
"headimgUrl": "https://i.imgs.ovh/2023/09/27/PjNJW.jpeg",
"playerid": "f7590e24-df9d-438a-881d-c918b99e15f5="
}
注意
Last updated