开发指南
监听用户状态变化
在执行登录接口前,需要先设置全局的用户状态变化回调,以方便游戏响应退出登录、第三方账号绑定/解绑成功等状态变更。
- Android
- iOS
- Unity
- UE
import com.xd.intl.account.XDGAccount;
import com.xd.intl.common.callback.XDGUserStatusChangeCallback;
import com.xd.intl.common.constants.Constants;
XDGAccount.addUserStatusChangeCallback(new XDGUserStatusChangeCallback(){
@Override
public void userStatusChange(int code,String message){
if(code == Constants.USER_STATUS_RESULT.LOGOUT_CODE){
// 用户退出登录
} else if (code == Constants.USER_STATUS_RESULT.BIND_CHANGE_CODE) {
// 绑定成功
} else if (code == Constants.USER_STATUS_RESULT.UNBIND_CHANGE_CODE) {
// 解绑成功
} else if (code == Constants.USER_STATUS_RESULT.PROTOCOL_AGREED_AFTER_LOGOUT_CODE) {
// 用户退出登录后点击同意协议
}
}
});
用户状态 code 码定义:
public class Constants {
// ...
public static class USER_STATUS_RESULT {
public final static int LOGOUT_CODE = 0x9001;
public final static int BIND_CHANGE_CODE = 0x1001;
public final static int UNBIND_CHANGE_CODE = 0x1002;
public final static int PROTOCOL_AGREED_AFTER_LOGOUT_CODE = 0x2001;
}
//...
}
typedef NS_ENUM(NSInteger,XDGUserStateChangeCode) {
XDGUserStateChangeCodeLogout = 0x9001, // user logout
XDGUserStateChangeCodeBindSuccess = 0x1001, // user bind success,msg = entry type in string,eg: @"TAPTAP"
XDGUserStateChangeCodeUnBindSuccess = 0x1002, // user unbind success,msg = entry type in string
XDGUserStateChangeCodeProtocolAgreedAfterLogout = 0x2001, // user clicked confirm in agreement dialog showed after logout
};
[XDGAccount addUserStatusChangeCallback:^(XDGUserStateChangeCode userStateChangeCode, NSString *message) {
if (userStateChangeCode == XDGUserStateChangeCodeBindSuccess) {
// 绑定新平台成功
NSLog(@"TDSGlobalDEMO 绑定成功:%@", message);
[XDGAccount getUser:^(XDGUser *_Nullable result, NSError *_Nullable error) {
NSLog(@"TDSGlobalDEMO boundAccounts:%@", result.boundAccounts);
}];
} else if (userStateChangeCode == XDGUserStateChangeCodeUnBindSuccess) {
// 解绑平台成功
NSLog(@"TDSGlobalDEMO 解除绑定成功:%@", message);
[XDGAccount getUser:^(XDGUser *_Nullable result, NSError *_Nullable error) {
NSLog(@"TDSGlobalDEMO boundAccounts:%@", result.boundAccounts);
}];
} else if (userStateChangeCode == XDGUserStateChangeCodeLogout) {
// 用户退出登录
} else if (userStateChangeCode == XDGUserStateChangeCodeProtocolAgreedAfterLogout) {
// 用户退出登录后点击同意协议
}
}];
XDGAccount.AddUserStatusChangeCallback((type, msg) => {
if (type == XDGUserStatusCodeType.LOGOUT){
//SDK已经退出,游戏需要切换到登录页面
}
});
public enum XDGUserStatusCodeType : int{
// 登出
LOGOUT = 0x9001,
// 绑定
BIND = 0x1001,
// 解绑
UNBIND = 0x1002,
// 退出登录后确认协议
ProtocolAgreedAfterLogout = 0x2001,
//出错了,未知code
ERROR = -100
}
enum class EXDGUserChangeState : int64 {
UserLogout = 0x9001, // user logout
UserBindSuccess = 0x1001, // user bind success,msg = entry type in string,eg: @"TAPTAP"
UserUnBindSuccess = 0x1002, // user unbind success,msg = entry type in string
ProtocolAgreedAfterLogout = 0x2001, // user clicked confirm in agreement dialog showed after logout
};
FXDGAccount::OnUserStatusChange.AddLambda([](EXDGUserChangeState UserState, const FString& Msg) {
if (UserState == EXDGUserChangeState::UserLogout) {
// 游戏账号应登出
} else if (UserState == EXDGUserChangeState::UserBindSuccess) {
// 账号被绑定
} else if (UserState == EXDGUserChangeState::UserUnBindSuccess) {
// 账号被解绑
} else if (UserState == EXDGUserChangeState::ProtocolAgreedAfterLogout) {
// 账号登出后协议同意
}
});
发起登录
需要在初始化成功后才可使用登录相关功能。
普通登录
调用流程
- 调用
LoginByType(Default)
尝试进行自动登录,如果玩家之前已经登录过且还未过期,则能直接登录成功。 - 如果自动登录返回失败,则游戏需要绘制包含各类型登录按钮的登录页面,等待玩家选择登录方式。
- 玩家点击登录按钮时调用
LoginByType(targetType)
,需要传入对应的登录类型来触发对应的流程,等待接口回调。 - 登录成功后,需要尽早执行
XDGCommon.TrackUser
,用于 TapDB 统计用户数据。 - 国内在登录成功后需要执行实名防沉迷的流程,请按照 TapSDK 文档 接入,当防沉迷系统返回可以进入时才能允许游戏进入游戏。
- XDSDK 登录成功时内建账户(TDSUser/LCUser)无法立即使用,需要执行
var tdsUser = await TDSUser.GetCurrent().Result.Fetch()
获取可用对象。
- Android
- iOS
- Unity
- UE
public enum LoginEntryType {
DEFAULT(-1, "Default"),
GUEST(0, "Guest"),
APPLE(2, "Apple"),
GOOGLE(3, "Google"),
FACEBOOK(4, "Facebook"),
TAP_TAP(5, "TapTap"),
LINE(6, "LINE"),
TWITTER(7, "Twitter"),
STEAM(10, "Steam"),
PHONE(11, "Phone"),
EMAIL(12, "Email");
}
import com.xd.intl.account.XDGAccount;
import com.xd.intl.common.base.XDGError;
import com.xd.intl.common.bean.XDGUser;
import com.xd.intl.common.callback.Callback;
import com.xd.intl.common.entities.LoginEntryType;
import java.util.Map;
XDGAccount.loginByType(LoginEntryType.DEFAULT, new Callback<XDGUser>() {
@Override
public void onCallback(XDGUser xdgUser, XDGError xdgError) {
if (xdgUser != null && xdgError == null) {
// 登录成功
String XDUserID = xdgUser.getId(); // 用户在 XD 账户系统的 XD User ID(用户唯一标识)
String avatarUrl = xdgUser.getAvatar();
String nickName = xdgUser.getNickName();
} else {
// 登录失败
if (xdgError != null) {
// 获取 error code、error 简述和 error 详细内容(详细内容一般是 json 格式,SDK 封装成了 map)
int code = xdgError.getCode();
String errorMsg = xdgError.getMessage();
Map<String,Object> errorDataMap = xdgError.getErrorDataMap();
}
}
}
});
LoginEntryTypeDefault (自动登录)
LoginEntryTypeTapTap
LoginEntryTypeApple (只支持 iOS 13 以上)
LoginEntryTypeGoogle
LoginEntryTypeFacebook
LoginEntryTypeLine
LoginEntryTypeTwitter
LoginEntryTypeSteam
LoginEntryTypeGuest
LoginEntryTypePhone // 6.9.0 支持国内,6.22.0 支持海外
LoginEntryTypeEmail // 6.22.0 支持海外
LoginEntryType type = LoginEntryTypeDefault;
[XDGAccount loginByType:type loginHandler:^(XDGUser * _Nullable result, NSError * _Nullable error) {
if (error) {
// 登录失败
// error.code (错误码,用来区分类型)
// error.localizedDescriptio (可以用来展示给用户的错误原因文案)
// error.userInfo[@"extraData"](详细内容,是个 NSDictionary,只在特定 code 下存在)
} else {
// 登陆成功
// 建议登陆成功后调用 trackUser
[XDGSDK trackUser];
NSString *xdUserID = result.userId; // result.userId 为用户在 XD 账户系统的 XD User ID(用户唯一标识)
NSString *name = result.name;
NSString *nickName = result.nickName;
NSString *avatar = result.avatar;
}
}];
public enum LoginType{
Default,
TapTap,
Google,
Facebook,
Apple,
LINE,
Twitter,
Steam,
Guest,
Phone,
Email
}
XDGAccount.LoginByType(LoginType loginType, xdgUser => {
//登录成功,国内开始处理防沉迷,海外就可以进游戏了
// xdgUser.userId 为用户在 XD 账户系统的 XD User ID(用户唯一标识)
Debug.LogFormat($"Wrapper Tap登录成功! userId: {xdgUser.userId} 昵称: {xdgUser.nickName} 头像: {xdgUser.avatar}");
},
error => {
// 登录失败
});
UENUM(BlueprintType)
enum class EXDGLoginType : uint8 {
// 自动登录
Default = MAX_uint8,
// 游客登录
Guest = 0,
WeChat = 1,
Apple = 2,
Google = 3,
Facebook = 4,
TapTap = 5,
LINE = 6,
Twitter = 7,
QQ = 8,
Steam = 10,
Phone = 11,// 6.9.0 支持国内,6.22.0 支持海外
Email = 12 // 6.22.0 支持海外
};
FXDGAccount::LoginByType(LoginType,
FXDGUser::FDelegate::CreateLambda([](const FXDGUser& User) {
// 登录成功
// *User.UserId 为用户在 XD 账户系统的 XD User ID(用户唯一标识)
UE_LOG(LogTemp, Log, TEXT("登录成功: XDUserID[%s], 头像Url[%s], 昵称[%s]"), *User.UserId, *User.Avatar, *User.NickName);
}), FXDGError::FDelegate::CreateLambda([](const FXDGError& Error) {
// 登录失败
}));
主机登录
我们可以把「Steam/PS/Nintendo」等平台上发行的游戏称之为主机游戏,对于这些游戏,用户们会更习惯用该平台账号登录游戏。对于这类游戏,推荐使用这个接口来登录。
游戏如何正确的使用该接口,可以参考这里的方案
- Unity PC
- UE
// 参考 https://github.com/xd-platform/xd_sdk_pc_upm 文档
XDGAccount.LoginByConsole(xdgUser => {
ResultText.text = $"Steam 主机登录成功:{xdgUser.nickName} userId: {xdgUser.userId} kid: {xdgUser.token.kid}";
}, null,
error => {
ResultText.text = $"Steam 主机登录失败:{error}";
}
);
在项目配置目录(Configs)下的 DefaultXDConfig.ini 文件中添加如下设置开启Steam登录:
bSteamSDKLoginEnable=True
同时需要开启UnrealEngine的"OnlineSubsystem"和"OnlineSubsystemSteam"两个插件
FXDGAccount::LoginByConsole(FXDGUser::FDelegate::CreateLambda([](const FXDGUser& User) {
// 成功
}), FSimpleDelegate::CreateLambda([]() {
// 登录失败,未绑定XDUser
}), FXDGError::FDelegate::CreateLambda([](const FXDGError& Error) {
// 发生错误
}));
在 TapTap 沙盒环境内实现无感登录
XDSDK 从 6.6.0 开始在 Android 上开始支持 TapTap 沙盒环境内的无感登录,需要将 XDConfig.json 中 tapsdk
的 permissions
内容改为只有一个 basic_info
,这个权限代表游戏只能获取 Tap 授权后的 unionid 和 openid,此时在 TapTap 的沙盒环境中用户在点击 Tap 登录后将不需要在授权页点击确认,能直接获得授权成功。
- basic_info 的权限只能单独使用,如果额外配上诸如 public_profile、user_friends 的权限,则不会有无感登录的效果。在无感登录的结果中,我们将无法提供用户昵称和头像的数据,如果业务需要使用相关数据,需要游戏自行另外调用 TDSUser 的登录接口,并传入相关的权限来重新触发授权。
- iOS 和沙盒外的 Android 环境也能使用 basic_info,但不会有无感登录的效果,会走正常用户手动确认的流程。
- PC SDK 目前不支持 basic_info。
{
xxx,
"tapsdk": {
xxx:xxx,
"permissions": [
"basic_info"
]
},
xxx
}
退出登录
如果需要退出当前账号,可以使用该接口。调用后 SDK 会重新弹出协议窗口并在用户状态回调中返回 LOGOUT_CODE 事件。在玩家点击同意协议后会返回 PROTOCOL_AGREED_AFTER_LOGOUT_CODE 事件。
- Android
- iOS
- Unity
- UE
import com.xd.intl.account.XDGAccount;
XDGAccount.logout();
[XDGAccount logout];
XDGAccount.Logout();
FXDGAccount::Logout();
获取当前用户信息
在用户已登录的情况下,调用此方法可获取当前已登录用户的信息:
- Android
- iOS
- Unity
- UE
import com.xd.intl.account.XDGAccount;
import com.xd.intl.common.base.XDGError;
import com.xd.intl.common.bean.XDGUser;
import com.xd.intl.common.callback.Callback;
XDGAccount.getUser(new Callback<XDGUser>() {
@Override
public void onCallback(XDGUser xdgUser, XDGError xdgError) {
String XDUserID = xdgUser.getId(); // 用户在 XD 账户系统的 XD User ID(用户唯一标识)
String avatarUrl = xdgUser.getAvatar();
String nickName = xdgUser.getNickName();
}
});
[XDGAccount getUser:^(XDGUser *_Nullable xdgUser, NSError *_Nullable error) {
if (error) {
// 没登录
} else {
// 当前登录用户为 xdgUser
NSString *xdUserID = xdgUser.userId; // xdgUser.userId 为用户在 XD 账户系统的 XD User ID(用户唯一标识)
NSString *name = xdgUser.name;
NSString *nickName = xdgUser.nickName;
NSString *avatar = xdgUser.avatar;
}
}];
XDGAccount.GetUser(Action<XDGUser> callback, Action<XDGError> errorCallback);
XDGAccount.GetUser((xdgUser) => {
// xdgUser.userId 为用户在 XD 账户系统的 XD User ID(用户唯一标识)
Debug.LogFormat($"Wrapper Tap 登录成功! userId: {xdgUser.userId} 昵称: {xdgUser.nickName} 头像: {xdgUser.avatar}");
}, (error) => {
Debug.LogErrorFormat($"Wrapper Tap登录失败:{error}");
});
FXDGAccount::GetUser();
if (TSharedPtr<FXDGUser> User = FXDGAccount::GetUser())
{
// *User.UserId 为用户在 XD 账户系统的 XD User ID(用户唯一标识)
UE_LOG(LogTemp, Log, TEXT("登录成功: XDUserID[%s], 头像Url[%s], 昵称[%s]"), *User->UserId, *User->Avatar, *User->NickName);
}
else
{
//当前未登录
}
打开用户中心
在用户已登录的情况下,SDK 在用户中心展示了当前已登录用户的一些基本信息,在此页面,用户可操作绑定/解绑第三方登录平台进行帐户的关联。
- Android
- iOS
- Unity
- UE
import com.xd.intl.account.XDGAccount;
XDGAccount.openUserCenter();
[XDGAccount openUserCenter];
XDGAccount.OpenUserCenter();
// @param bShowLogoutButton 用户中心是否显示退出登录按钮 [Win64] [macOS]
FXDGAccount::OpenUserCenter(bool bShowLogoutButton = true);
打开个人信息页
在用户已登录的情况下,调用此接口可打开个人信息页面,在这个页面中会展示游戏和 SDK 收集的和玩家个人信息相关的内容。
- Android
- iOS
- Unity
- UE
import com.xd.intl.account.XDGAccount;
import com.xd.intl.account.v2.entity.RoleInfo;
XDGAccount.openUserDashboard(
RoleInfo.newBuilder()
.setRoleId(roleId)
.setRoleName(roleName)
.setServerId(serverId)
.setExtra(extra)
.build()
);
XDGRoleInfo *roleInfo = [XDGRoleInfo new];
roleInfo.roleId = roleId; // 必填
roleInfo.roleName = roleName; // 必填
roleInfo.serverId = serverId; // 必填
// roleInfo.extra = extra; // 暂时不传,预留后续扩展
[XDGAccount openUserDashboardWithInfo:roleInfo];
XDGRoleInfo roleInfo = new XDGRoleInfo();
roleInfo.roleId = roleIdInput.text; // 必填
roleInfo.roleName = roleNameInput.text; // 必填
roleInfo.serverId = serverIdInput.text; // 必填
// roleInfo.extra = extraInput.text; // 暂时不传,预留后续扩展
XDGAccount.OpenUserDashboard(roleInfo);
FDashboardRoleInfo Info;
Info.ServerId = TEXT("ServerId"); // 必填
Info.RoleId = TEXT("RoleId"); // 必填
Info.RoleName = TEXT("RoleName"); // 必填
Info.Extra = TEXT("Extra"); // 暂时不传,预留后续扩展
FXDGAccount::OpenUserDashboard(Info);
打开帐户注销页面
用户可通过此方法进行帐户的注销操作。当用户成功发起注销且关闭当前页面时,会在用户状态回调中返回退出登录的事件,游戏需要同步退出登录状态。此时玩家账号还未真正被删除,需要参考服务端通知对接完成对接后收到通知时在游戏侧删除相应账号的数据。
- Android
- iOS
- Unity
- UE
import com.xd.intl.account.XDGAccount;
XDGAccount.accountCancellation();
[XDGAccount accountCancellation];
XDGAccount.OpenUnregister();
FXDGAccount::AccountCancellation();
绑定第三方账号
当游戏通过一些报错信息得知用户的某个授权已经过期后,可以使用该接口让用户重新授权以正常使用某些第三方平台的数据。
Added in v6.4.1
绑定接口对于玩家来说如果授权了和之前授权不一样的账号的话,存在「换绑」的可能性,所以游戏需要谨慎使用该方法,使用前需要给到用户明确的提醒。参考 绑定账号接口 文档。
- Android
- iOS
- Unity
- UE
import com.xd.intl.account.XDGAccount;
import com.xd.intl.common.base.XDGError;
import com.xd.intl.common.callback.XDGBindResultCallback;
import com.xd.intl.common.entities.LoginEntryType;
XDGAccount.bindByType(LoginEntryType.FACEBOOK, new XDGBindResultCallback(){
@Override
public void onBindResult(boolean success,XDGError xdgError){
if(success){
// 绑定成功
} else {
// 绑定失败
}
}
});
[XDGAccount bindByType:bindType
bindHandler:^(BOOL success, NSError *_Nullable error) {
if (success) {
// 绑定成功
} else {
// 绑定失败
}
}];
XDGAccount.BindByType(LoginType, (success, error) => {
if(success){
// 绑定成功
} else {
// 绑定失败
ResultText.text = $"绑定结果:{b}, error:{JsonUtility.ToJson(error)}";
}
});
FXDGAccount::BindByType(LoginType, FXDGAccount::FBindResult::CreateLambda([](bool IsSuccess, const FXDGError& Error) {
if (IsSuccess) {
} else {
}
}));
检查本地某个平台的授权是否有效
v6.4.1 支持 TapTap 和 Facebook
v6.7.0 新增支持 Twitter
- Android
- iOS
- Unity
- UE
import com.xd.intl.account.XDGAccount;
import com.xd.intl.common.entities.LoginEntryType;
boolean isTokenActive = XDGAccount.isTokenActiveWithType(LoginEntryType.TAP_TAP);
BOOL isTokenActive = [XDGAccount isTokenActiveWithType:LoginEntryTypeTapTap];
XDGAccount.IsTokenActiveWithType(LoginType.Facebook, (isActive) => {
ResultText.text = $"结果:{isActive}";
});
// [iOS][Android]
FXDGAccount::IsTokenActiveWithType(LoginType);