11/08/2024 16:35:55
登录模块开发
一、插件开发说明
MSDK 登录功能,为游戏提供便捷的登录方式,玩家可以使第三方渠道的账号登录进入游戏。
1.1 登录态缓存说明
一般情况下,MSDK 客户端和第三方渠道 SDK 都会缓存之前登录态的数据,以减少拉起应用弹窗、用户确认、输入账号密码等操作。但是,这种逻辑也有可能会带来其他副作用,如下两个应用场景:
用户想要切换登录账号
一般来说,如果用户遇到这种场景可以通过设置界面中的
Logout
接口来解决该问题[info] 建议 由于渠道的实现差异,建议针对性的进行测试
用户在渠道 App 上修改密码,本次缓存数据未同步
一般应对盗号场景,用户修改密码之后,如果渠道 SDK 未做本地缓存有效性绑定,盗号者依旧可以进行登录
[info] 建议 增加对应的逻辑测试
1.2 自动登录说明
一般情况下 MSDK 自动登录逻辑不会调用到插件。MSDK 会验证本地登录态是否有效,如果有效直接发送请求到后台进行验证,验证通过后即自动登录成功。
某些特殊渠道需要在自动登录时进行一些逻辑处理,否则可能导致部分功能失效。因此 MSDK 提供一种能力可以让自动登录调用到插件,渠道登录类需要实现 AutoLoginInterface 接口,并实现 autoLogin 方法。
二、客户端插件开发
2.1 Android 平台
2.1.1 类实现规则说明
- 包名规则:固定为
com.tencent.gcloud.msdk.login
- 类名规则:
渠道 + Login
,如:GarenaLogin
- 必须实现
LoginInterface
接口:- login 函数,用于实现渠道登录功能
- logout 函数,用于实现渠道登出功能
- 可选实现
AutoLoginInterface
接口:- autoLogin 函数,用于支持某些渠道需要在 autoLogin 时调用到插件
- 必须实现一个
public CLASSNAME(String seqID)
构造函数,通常用于函数初始化
2.1.2 回调字段说明
回调函数说明,可参考 客户端插件开发规则
observerID
回调函数 IDMSDKObserverID.MSDK_LOGIN_OBSERVER_LOGIN_RET
用于登录或自动登录出错直接返回MSDKObserverID.MSDK_LOGIN_OBSERVER_LOGIN_PLUGIN
用于登录或自动登录成功时通知数据,并继续运行MSDKObserverID.MSDK_LOGIN_OBSERVER_LOGOUT_PLUGIN
用于登出时通知继续运行
ret
返回结构,必须是MSDKRet
的子类- 在登录或自动登录方法,返回结果为
MSDKLoginPluginInfo
。如需传递自定义数据,则需要放到MSDKLoginPluginInfo.pluginData
结构中,类型为 JSON 字符串 - 在登出方法,返回结果为
MSDKRet
- 在登录或自动登录方法,返回结果为
methodNameID
MSDK 定义的函数 ID,用于回调方法定义,建议统一采用MSDKBaseParams.methodID
2.1.3 LoginInterface 接口
Login 函数
调用渠道登录接口,并返回登录验证所需要的必要渠道登录验证数据
Logout 函数
调用渠道的登出函数,返回成功或失败即可
2.1.4 AutoLoginInterface 接口
autoLogin 函数
自动登录接口,用于支持某些渠道需要在 autoLogin 时调用到插件
2.1.5 代码示例
package com.tencent.gcloud.msdk.login;
public class GarenaLogin implements LoginInterface, AutoLoginInterface {
public GarenaLogin(String seqID) {
MSDKLog.d("[ " + seqID + "] Garena Login initialize start ");
// TODO 初始化 Garena 环境
...
}
@Override
public void login(final MSDKLoginParams params) {
// TODO Garena 登录逻辑
...
// 返回 MSDK 数据时,channel、channelID 必须返回。该定义必须与 MSDK 后台一致,一般在接入时进行申请和确认
MSDKLoginPluginInfo pluginResult = new MSDKLoginPluginInfo(params.methodId);
pluginResult.channel = GarenaConst.Channel.CHANNEL;
pluginResult.channelID = GarenaConst.Channel.CHANNEL_ID;
// channelOpenID 为渠道用户 ID,如果能够获取到,请尽量赋值
pluginResult.channelOpenID = (session == null ? "" : session.getOpenId());
// 组装返回数据结构,JSON 格式。这部分数据可以跟进渠道特性及后台的要求进行添加
try {
JSONObject params = new JSONObject();
params.put("uid", session.getOpenId());
params.put("token", session.getTokenValue().getAuthToken());
params.put("channel", session.getSessionProvider().getValue());
params.put("platform",session.getPlatform());
if (session.getSessionProvider() == GGLoginSession.SessionProvider.FACEBOOK) {
params.put("facebook_token", GGPlatform.GGGetFacebookAccessToken());
}
MSDKLog.d(params.toString());
// 关键赋值步骤
pluginResult.pluginData = params.toString();
} catch (JSONException e) {
// TODO 这里 catch 是为了保障健壮性,业务也可以根据需要进进行异常处理
MSDKLog.e("[ " + params.seqID + " ] catch exception : " + e.getMessage());
}
MSDKLog.d("[ " + params.seqID + " ] pluginResult = " + pluginResult.toString());
// 将数据发给 MSDK 服务器
IT.onPluginRetCallback(MSDKObserverID.MSDK_LOGIN_OBSERVER_LOGIN_PLUGIN, pluginResult, params.seqID);
}
@Override
public void autoLogin(MSDKLoginParams params) {
// TODO 判断当前是否有 Garena 登录态
// TODO 调用 Garena 自动登录逻辑
// TODO 参考 login 方法对自动登录数据进行回调
}
@Override
public void logout(MSDKBaseParams params) {
// Garena 登出逻辑
GGLoginSession.clearSession();
MSDKLog.d("[ " + params.seqID + " ] logout success" );
// 直接返回成功
IT.onPluginRetCallback(MSDKObserverID.MSDK_LOGIN_OBSERVER_LOGOUT_PLUGIN,
new MSDKRet(MSDKMethodNameID.MSDK_METHOD_LOGOUT, MSDKErrorCode.SUCCESS),
params.seqID);
}
}
[info] 详情请参考示例代码
2.2 iOS 平台
2.2.1 类实现规则说明
- 命名规则:固定为
MSDKLogin + 渠道
,如:MSDKLoginGarena
- 必须实现
MSDKLoginDelegate
协议 - 必须实现单例模块,建议使用
SYNTHESIZE_SINGLETON_FOR_CLASS_HEADER
+SYNTHESIZE_SINGLETON_FOR_CLASS_HEADER
宏处理
2.2.2 回调字段说明
回调函数说明,可参考 客户端插件开发规则
observerID
回调函数 IDkObserverIDLoginRet
用于登录或自动登录出错直接返回kObserverIDLoginPlugin
用于登录或自动登录成功时通知数据,并继续运行kObserverIDLogoutPlugin
用于登出时通知继续运行
ret
返回结构- 在登录或自动登录方法,返回结果为
InnerLoginPluginRet
。如需传递自定义数据,则需要放到InnerLoginPluginRet.pluginData
结构中,类型为 JSON 字符串 - 在登出方法,返回结果为
InnerBaseRet
- 在登录或自动登录方法,返回结果为
methodNameID
MSDK 定义的函数 ID,用于回调方法定义,建议统一采用 MSDKBaseParams.methodID
2.2.3 MSDKLoginDelegate 协议
Login 函数说明
登录函数,调用渠道登录接口,并返回登录验证所需要的必要渠道登录验证数据
函数原型:
- (void)login:(const MSDKLoginParams &)params;
【可选实现】autoLogin 函数说明
自动登录接口,用于支持某些渠道需要在 autoLogin 时调用到插件
函数原型:
- (void)autoLogin:(const MSDKLoginParams &)params;
Logout 函数说明
登出函数,调用渠道的登出函数,返回成功或失败即可
函数原型:
- (void)logout:(const MSDKBaseParams &)params;
【可选实现】渠道安装判断函数说明
函数原型:
- (BOOL)isChannelInstall;
用于判断渠道是否安装,渠道有接口或方案实现该逻辑,则需要实现
【可选实现】二维码扫描登录函数接口说明
函数原型:
- (void)qrCodeLogin:(const MSDKLoginParams &)params info:(const MSDKQRCodeInfo &)qrinfo;
当前应用于微信二维码扫描登录,一般渠道不需要实现
【可选实现】检查是否支持自动刷新渠道 token 函数接口说明
函数原型:
- (BOOL)checkAutoRefresh;
用于判断是否支持自动刷新渠道 token 功能,一般渠道没有自动刷新 token 机制,因此一般不用实现
2.2.4 代码示例
- (void)login:(const MSDKLoginParams &)params {
// TODO Garena 登录逻辑
...
// Garena 登录返回数据处理
InnerLoginPluginRet ret;
ret.methodNameID = params.methodID;
// 返回 MSDK 数据时,channel、channelID 必须返回。该定义必须与 MSDK 后台一致,一般在接入时进行申请和确认
ret.channelID = GARENA_CHANNEL_ID;
ret.channel = GARENA_CHANNEL;
// channelOpenID 为渠道用户 ID,如果能够获取到,请尽量赋值
ret.channelOpenID = loginRet.openID;
// 组装返回数据结构,JSON 格式。这部分数据可以跟进渠道特性及后台的要求进行添加
MSDKJsonWriter jsonWriter;
jsonWriter.StartJsonConvert();
jsonWriter.convert("uid", loginRet.openID);
// Garena Token 处理,包含两种类型的 Token:登录 Token 和 Refresh Token
for (int i=0; i<loginRet.token.size(); i++) {
GG::TokenRet* pToken = &loginRet.token[i];
if (pToken->type == GG::eToken_BT_Access) {
jsonWriter.convert("token", pToken->value);
} else {
jsonWriter.convert("refresh_token", pToken->value);
}
}
jsonWriter.convert("platform", loginRet.platform);
if(loginRet.platform == GG::ePlatform_FB) {
jsonWriter.convert("facebook_token", GG::GGPlatform::GetInstance()->GGGetFacebookAccessToken().c_str() ? : "");
}
jsonWriter.EndJsonConvert();
ret.pluginData = jsonWriter.GetJsonString().c_str();
LOG_DEBUG("[ %s ] plugin data %s", params.seqID.c_str(), ret.pluginData.c_str());
// 将数据发给 MSDK 服务器
MSDKInnerObserverHolder<InnerLoginPluginRet>::CommitToTaskQueue(ret, kObserverIDLoginPlugin, params.seqID);
}
- (void)autoLogin:(const MSDKLoginParams &)params {
// TODO 判断当前是否有 Garena 登录态
// TODO 调用 Garena 自动登录逻辑
// TODO 参考 login 方法对自动登录数据进行回调
}
- (void)logout:(const MSDKBaseParams &)params {
bool success = GG::GGPlatform::GetInstance()->GGGetLogout();
InnerBaseRet innerRet = InnerBaseRet(MSDKError::SUCCESS);
if (!success) {
innerRet = InnerBaseRet(MSDKError::THIRD_ERROR);
innerRet.thirdCode = MSDKError::NO_ASSIGN;
innerRet.thirdMsg = "GGGetLogout return false";
}
MSDKInnerObserverHolder<InnerBaseRet>::CommitToTaskQueue(innerRet, kObserverIDLogoutPlugin, params.seqID);
}
[info] 详情请参考示例代码
三、插件服务器开发
对于登录流程,游戏需要实现下列服务器接口:
- 登录接口,客户端登录核心接口,用于用户登录实现及渠道数据返回
- 【可选】登录校验接口,客户端登录核心接口,用于校验登录接口返回 Token 有效性
- 【可选】个人信息接口,主要提供用户基本信息查询能力
国内、海外游戏需要在接入时 MSDK 平台时进行选择
3.1 登录接口
3.1.1 接口名
接口名(/auth/login/
可以在管理端配置)
3.1.2 请求参数
参数 | 类型 | 描述 | 可选与否 |
---|---|---|---|
appid | string | 应用 ID | 必填 |
channel_info | json | 客户端入参中 channel_info 字段的值 | 必填 |
3.1.3 返回参数
参数 | 类型 | 描述 | 可选与否 |
---|---|---|---|
ret | uint | 返回码, 0 - 表示成功,其它 - 表示失败 | 必填 |
msg | string | 返回结果详细说明 | 必填 |
uid | string | 第三方渠道的用户标识 | 必填 |
token | string | 第三方渠道的 token | 必填 |
expires_in | uint | 第三方渠道 token 还有多少秒过期 | 必填 |
gender | uint | 性别,0 - 未定义, 1 - 男, 2 - 女 | 选填 |
user_name | string | 用户昵称 | 选填 |
picture_url | string | 头像地址 | 选填 |
extraJson | json | 额外信息 | 选填 |
3.1.4 请求示例
请求
POST /auth/login/?channelid=101&gameid=10&os=1&sig=0764cfef18e9b877b1805ede000eda38 HTTP/1.1 Host: openplatformtest.com Content-Type: application/json Content-Length: 308 { "appid": "xxxxx", "channel_info": { "access_token": "EAAGBC9HZB9l4BAEWkk4T3b4d2gZCTrQVFmmtPZA6SoH4VCPO0XKkce47LUaOMMdzuo6q7JWM2RDLjyT1nehQWTTLcwyjyvKxy2AeNzPRTkI9dpBz78s5KOYf8omVMfMzrykdKcnQSYuRJ0zaCyaHJ1ZCeOg5HBnc8XnHwYk5EUp9htCFXw7RbTBVNU0rGxAkurqnnMLZC92N5gTbYF4NOUMZBd2iJDa7dmE6RNOb3gPAZDZD" } }
响应
{ "ret": 0, "msg": "success", "uid": "openplatformtestloginuid", "token": "openplatformtestlogintokentest", "expires_in": 5184000, "user_name": "tamywang", "gender": 1, "picture_url": "http://exmaple.com/example.jpg", "extraJson": { "example": "self defined login extra info" } }
3.2 登录校验接口
3.2.1 接口名
接口名(/auth/verify_login/
可以在管理端配置)
3.2.2 请求参数
参数 | 类型 | 描述 | 可选与否 |
---|---|---|---|
appid | string | 应用 ID | 必填 |
uid | string | 第三方渠道的用户标识 | 必填 |
token | string | 第三方渠道的 token | 必填 |
extraJson | json | 额外信息 | 选填 |
3.2.3 返回参数
参数 | 类型 | 描述 | 可选与否 |
---|---|---|---|
ret | uint | 返回码, 0 - 表示成功,其它 - 表示失败 | 必填 |
msg | string | 返回结果详细说明 | 必填 |
3.2.4 请求示例
请求
POST /auth/verify_login/?channelid=101&gameid=10&os=1&sig=6e2cf8d1e6f560f9eecffc18251a544e HTTP/1.1 Host: openplatformtest.com Content-Type: application/json Content-Length: 142 { "appid": "xxxxx", "uid": "openplatformtestloginuid", "token": "openplatformtestlogintokentest", "extraJson": { "example": "example" } }
响应
{ "ret": 0, "msg": "success" }
3.3 个人信息接口
3.3.1 接口名
接口名(/profile/userinfo/
可以在管理端配置)
3.3.2 请求参数
参数 | 类型 | 描述 | 可选与否 |
---|---|---|---|
appid | string | 应用 ID | 必填 |
uid | string | 第三方渠道的用户标识 | 必填 |
token | string | 第三方渠道的 token | 必填 |
extraJson | json | 额外信息 | 选填 |
3.3.3 返回参数
参数 | 类型 | 描述 | 可选与否 |
---|---|---|---|
ret | uint | 返回码, 0 - 表示成功,其它 - 表示失败 | 必填 |
msg | string | 返回结果详细说明 | 必填 |
gender | uint | 性别,0 - 未定义, 1 - 男, 2 - 女 | 选填 |
user_name | string | 用户昵称 | 必填 |
picture_url | string | 头像地址 | 必填 |
extraJson | json | 额外信息 | 选填 |
3.3.4 请求示例
请求
POST /profile/userinfo/?channelid=101&gameid=10&os=1&sig=5b4ad2242a4cb680dc373aae5ba5e7e7 HTTP/1.1 Host: openplatformtest.com Content-Type: application/json Content-Length: 142 { "appid": "xxxxx", "uid": "openplatformtestloginuid", "token": "openplatformtestlogintokentest", "extraJson": { "example": "example" } }
响应
{ "ret": 0, "msg": "success", "user_name": "tamywang", "gender": 1, "picture_url": "http://exmaple.com/example.jpg", "extraJson": { "example": "login extra info" } }
All rights reserved.