登录注销
登录认证包括以下步骤。
Note
- SDK 4.7.0 以下的版本不支持 Helper。请参考 [以下内容] 了解现有的登录应用方法。
- 有关 AuthV4.Helper 的描述,请参阅 身份验证 页面。
登录¶
登录认证包括以下步骤。
Authv4Helper 是一个执行与登录相关的一系列过程的类,旨在根据响应值导航到适当的屏幕。 配置登录时,请参考以下几点。
Note
苹果不支持在 iOS 企业构建中使用 Apple Game Center 和应用内购买。因此,在 iOS 企业构建中无法使用 Apple Game Center 账户的隐式登录,显式登录也无法利用 Apple Game Center。当为 iOS 企业构建时,控制台中的 登录类型 不能包含 Apple Game Center。
Note
- 如果游戏主要面向13岁以下的儿童,则无法使用Google Play游戏服务,因此无法在Google构建中使用隐式登录。有关更多详细信息,请参阅Google Play游戏服务质量检查清单。
- Google Play游戏的隐式登录仅应在初始登录时尝试。有关更多详细信息,请参阅Google开发者指南1.5 记住玩家是否拒绝登录。
Note
- 在中国,Android上无法使用隐式登录,因为Google Play游戏不可用。
- 在中国,无法使用Facebook,因此Facebook不包含在IdP列表中。
- 由于只有经过实名认证的用户才能在中国充值或消费服务资源(自2017年5月1日起生效),因此从中国IP登录时不包含访客登录在IdP列表中。
Note
iOS即使在取消Apple Game Center登录时也不会显示登录屏幕。因此,指导消息可以通过SDK直接调用AuthV4Helper
类的showGameCenterLoginCancelDialog()
方法显示,或者由游戏选择显示。如果您想为用户提供重新链接其Game Center帐户的消息,请在AuthV4.signIn(AuthV4.ProviderType.APPLE, ...)
和AuthV4.connect(AuthV4.ProviderType.APPLE, ...)
的回调结果为取消时使用Game Center取消指导消息。
Note
如果用户尝试使用 Apple 登录,而他们的设备未使用 Apple ID 登录,则在调用 AuthV4Helper 类的 connect()
、signIn()
方法的过程中会发生 AuthV4SignInAppleUnknown 错误 在这里。Apple ID 登录指导弹出窗口会自动显示,因此游戏工作室无需显示单独的指导弹出窗口。
如果用户尝试使用 Apple 登录,而他们的设备没有使用 Apple ID 登录,则在调用 AuthV4Helper 类的 connect()
、signIn()
方法 的过程中会发生 AuthV4SignInAppleUnknown 错误。Apple ID 登录指导弹出窗口会自动显示,因此游戏工作室不需要单独显示一个 弹出窗口 进行指导。
Note
对于 PC X IdP 登录,可以使用 X 账户登录,但在 X 登录界面上不支持通过 Google 和 Apple 账户集成进行登录。 要使用 Google 或 Apple 账户集成登录 X,您必须先在外部浏览器中使用相应账户登录,然后在游戏中继续进行 X 登录。
对于 Steam Deck X IdP 登录,仅支持使用 X 账户登录。
自动登录和隐式登录¶
自动登录¶
这意味着用户通过在 iOS 上链接他们的 Apple Game Center 账户和在 Android 上链接他们的 Google Play Games 账户,自动登录,而无需选择登录方式。它实现了自动登录,并在自动登录失败的情况下执行隐式登录。
在 iOS 环境中使用自动登录,您需要添加游戏中心权限,如果您在 Unity 中勾选了“Apple GameCenter”依赖项,它将通过 Unity 后处理自动添加相应的权限。在 iOS 原生中,Xcode 将自动添加游戏中心权限。
离线模式¶
在 Hive SDK v4 23.1.0 及以上版本中,即使用户设备在应用启动时未连接网络,也可以提供自动登录功能(AuthV4.signIn
使用 ProviderType.AUTO
,或 AuthV4.Helper.signIn
)。要使用离线模式,请遵循以下说明。
- 您必须成功在线执行应用程序以进行显式、隐式、访客或自定义登录,并收到
playerId
和playerToken
。
从应用程序开发者的角度来看,必须至少在线成功执行过一次 AuthV4.Helper.signIn
、AuthV4.showSignIn
或 AuthV4.signInWithAuthKey
,才能接收到 playerId
和 playerToken
作为回调。从用户的角度来看,用户必须至少在设备连接到网络时成功登录过一次应用程序。然而,如果用户的账户在上次在线登录尝试时被暂停或限制,即使在离线模式下,用户也无法登录。
- 在Hive控制台中激活离线模式 应用中心 > 项目管理 > 游戏详情 > Hive 产品设置.
在Windows环境中的自动登录¶
Windows环境还支持自动登录,可以在Hive 控制台应用中心中启用/禁用。然而,Windows上的自动登录行为与移动设备有所不同。Windows上自动登录的不同之处如下。
- 在移动设备上,登录状态在登录后始终自动保持,但在Windows上,只有在用户激活“保持我登录”复选框(在登录UI的IdP列表底部显示)时,才会保持登录状态。在其他情况下,登录状态不会保持。
- 当执行 AuthV4Helper.Connect 时,在移动设备上,如果切换到新帐户,新帐户也会保持自动登录状态,但在Windows上,当切换到新帐户时,新帐户不会保持自动登录状态。
隐式登录¶
AuthV4.Helper.signIn
尝试使用 PlayerID 的身份验证令牌密钥自动登录。如果没有先前登录的身份验证令牌密钥,它将自动登录到 iOS 的 Apple Game Center 和 Android 的 Google Play Games。如果登录失败,它将根据响应值配置适当的登录屏幕。
Note
要使用自动登录,您必须添加 Game Center 权限。如果您勾选了“Apple GameCenter”依赖项,相关的权限将通过 Unity PostProcess 自动添加。
Note
使用AuthV4Helper类时
如果正在运行游戏的用户在PGS期间拒绝隐式登录尝试,它将记住这一点,并且不再尝试隐式登录。即使在玩家会话保持的情况下可以进行自动登录,它仍将继续记住隐式登录被拒绝的状态。此内容基于Google Play游戏服务指南。
以下是一个执行自动登录的示例代码。
API 参考: hive.AuthV4.Helper.signIn
// 尝试使用 Hive SDK 登录 (signIn)
AuthV4.Helper.signIn (delegate (ResultAPI result, AuthV4.PlayerInfo playerInfo) {
if (result.isSuccess()) {
// 登录成功
} else if (result.needExit()) {
// TODO: 实现应用退出功能
// 例如)Application.Quit();
} else {
switch (result.code) {
case ResultAPI.Code.AuthV4ConflictPlayer:
// 账户冲突
break;
case ResultAPI.Code.AuthV4HelperImplifiedLoginFail:
// 隐式登录失败
// 例如) AuthV4.showSignIn(...);
break;
default:
// 其他异常
break;
}
}
});
#include "HiveAuthV4.h"
// 尝试登录 (signIn) 到 Hive SDK
FHiveAuthV4::Helper::SignIn(FHiveAuthV4HelperDelegate::CreateLambda([this](const FHiveResultAPI& Result, const TOptional<FHivePlayerInfo>& PlayerInfo) {
if (Result.IsSuccess()) {
// 登录成功
} else if (Result.NeedExit()) {
// TODO: 实现应用退出功能
// 例如) UKismetSystemLibrary::QuitGame(GetWorld(), nullptr, EQuitPreference::Quit, false);
} else {
switch (Result.Code) {
case FHiveResultAPI::ECode::AuthV4ConflictPlayer:
// 账户冲突
break;
case FHiveResultAPI::ECode::AuthV4HelperImplifiedLoginFail:
// 隐式登录失败
// 例如) FHiveAuthV4::ShowSigIn()
break;
default:
// 其他异常
break;
}
}
}));
API 参考: Auth4::Helper::signIn
// 尝试使用 Hive SDK 登录 (signIn)
AuthV4::Helper::signIn([=](ResultAPI const & result, std::shared_ptr playerInfo) {
if (result.isSuccess()) {
// 登录成功
} else if (result.needExit()) {
// TODO: 实现应用退出功能
// Cocos2d-x 引擎用户
// 例如 exit(0);
// Unreal 引擎用户
// 例如 UKismetSystemLibrary::QuitGame(GetWorld(), nullptr, EQuitPreference::Quit, false);
} else {
switch (result.code) {
case ResultAPI::AuthV4ConflictPlayer:
// 账户冲突
break;
case ResultAPI::AuthV4HelperImplifiedLoginFail:
// 隐式登录失败
// 例如 AuthV4.showSignIn(...);
break;
default:
break;
}
}
});
API 参考: hive.AuthV4.Helper.signIn
// 尝试使用 Hive SDK 登录 (signIn)
AuthV4.Helper.signIn(object : AuthV4.Helper.AuthV4HelperListener {
override fun onAuthV4Helper(result: ResultAPI, playerInfo: AuthV4.PlayerInfo?) {
if (result.isSuccess) {
// 登录成功
} else if (result.needExit()) {
// TODO: 实现应用退出功能
// e.g.) exitProcess(0)
} else {
when (result.code) {
ResultAPI.Code.AuthV4ConflictPlayer -> {
// 账户冲突
}
ResultAPI.Code.AuthV4HelperImplifiedLoginFail -> {
// 隐式登录失败
// ex) AuthV4.showSignIn(...)
}
else -> {
// 其他异常情况
}
}
}
}
})
API 参考: com.hive.AuthV4.Helper.signIn
// Hive SDK AuthV4 authentication UI request
AuthV4.Helper.signIn(new AuthV4.Helper.AuthV4HelperListener() {
@Override
public void onAuthV4Helper(ResultAPI result, PlayerInfo playerInfo) {
if (result.isSuccess()) {
// 认证成功
} else if (result.needExit()) {
// TODO: 实现应用退出功能
// 例如)System.exit(0);
} else {
switch (result.code) {
case ResultAPI.Code.AuthV4ConflictPlayer:
// 账户冲突
break;
case ResultAPI.Code.AuthV4HelperImplifiedLoginFail:
// 隐式登录失败
// 例如)AuthV4.showSignIn(...);
break;
default:
// 其他异常
break;
}
}
}
});
API 参考: HIVEAuthV4Helper:signIn
// Hive SDK AuthV4 authentication UI request
AuthV4Interface.helper().signIn { (result, playerInfo) in
if result.isSuccess() {
// 认证成功
} else if result.needExit() {
// TODO: 实现应用退出功能
// e.g.) exit(0)
} else {
switch result.getCode() {
case .authV4ConflictPlayer:
// 账户冲突
break
case .authV4HelperImplifiedLoginFail:
// 隐式登录失败
// ex) AuthV4.showSignIn(...)
break
default:
// 其他异常
break
}
}
}
}
API 参考: HIVEAuthV4:signIn
// 尝试登录 (signIn) 到 Hive SDK
[[HIVEAuthV4 helper] signIn:^(HIVEResultAPI *result, HIVEPlayerInfo *playerInfo) {
if (result.isSuccess) {
// 登录成功
}
else if (result.needExit) {
// TODO: 实现应用退出功能
// ex) exit(0);
}
else {
switch (result.code) {
case kAuthV4ConflictPlayer:
// 账户冲突
break;
case kAuthV4HelperImplifiedLoginFail:
// 隐式登录失败
// ex) [HIVEAuthV4 showSignIn:^(HIVEResultAPI *result, HIVEPlayerInfo *playerInfo) {
// // 做一些事情...
// }];
break;
default:
// 其他异常
break;
}
}
}];
隐式登录行为:移动¶
在移动设备上隐式登录(Hive SDK Unity Android等,Android/iOS平台)(AuthV4.Helper.signIn
) 在使用不同账户登录时,如果出现账户冲突,会提示用户一个对话框,询问是否使用上次登录的账户进行登录。
隐式登录行为:PC¶
在PC上进行隐式登录(例如Hive SDK Unity for Windows和其他Windows平台)(AuthV4.Helper.signIn
)在首次登录后使用不同账户登录时,会自动使用上次登录的账户进行登录。账户冲突不会发生。
显式登录¶
显式登录是指用户选择身份提供者(IdP)进行身份验证的过程。如果自动登录和隐式登录都失败,则在用户移动到游戏标题屏幕后点击标题时执行显式登录。
显式登录用户界面可以使用Hive SDK提供的用户界面,也可以使用Hive SDK初始化完成后返回的IdP列表进行自定义。如果您正在自定义用户界面,请参考显式登录自定义部分。
身份提供者(IdP)列表由Hive平台根据各国的政策进行控制和提供。例如,在中国,Google Play游戏和Facebook对访客不可用。
显式登录截图¶
使用SDK提供的UI进行实现时¶
要使用SDK提供的UI实现显式登录,您只需调用showSignIn()
方法以调用IdP列表UI。
Note
如果用户通过按“X”按钮关闭SDK提供的IdP选择UI,则必须提供再次登录的方式。用户仍然没有登录。
Note
要自定义显式登录,请参考以下内容。
API 参考: hive.AuthV4.showSignIn
// Hive SDK AuthV4 认证 UI 请求
AuthV4.showSignIn((ResultAPI result, AuthV4.PlayerInfo playerInfo)=>{
if (result.isSuccess()) {
// 认证成功
// playerInfo : 认证用户信息
// 获取电子邮件信息的示例
foreach (KeyValuePair<AuthV4.ProviderType, AuthV4.ProviderInfo> entry in playerInfo.providerInfoData) {
AuthV4.ProviderInfo providerInfo = entry.Value;
if(providerInfo.providerEmail != null && providerInfo.providerEmail != "") {
string email = providerInfo.providerEmail;
break;
}
}
}
else if (result.needExit()) {
// TODO: 实现应用退出功能
// e.g.) Application.Quit();
}
});
#include "HiveAuthV4.h"
// Hive SDK AuthV4 认证 UI 请求
FHiveAuthV4::ShowSignIn(FHiveAuthV4OnSignInDelegate::CreateLambda([this](const FHiveResultAPI& Result, const FHivePlayerInfo& PlayerInfo) {
if (Result.IsSuccess()) {
// 认证成功 (PlayerInfo: 经过认证的用户信息)
// 获取电子邮件信息的示例
for (const auto& ProviderInfoEntry : PlayerInfo.ProviderInfoData) {
FHiveProviderInfo ProviderInfo = ProviderInfoEntry.Value;
FString Email = ProviderInfo.ProviderEmail;
}
} else if (Result.NeedExit()) {
// TODO: 实现应用程序退出功能
// 示例) UKismetSystemLibrary::QuitGame(GetWorld(), nullptr, EQuitPreference::Quit, false);
}
}));
API 参考: AuthV4::showSignIn
// Hive SDK AuthV4 authentication UI request
AuthV4::showSignIn([=](ResultAPI const & result, PlayerInfo const & playerInfo) {
if (result.isSuccess()) {
// Authentication successful
// playerInfo: Authenticated user information
// 获取电子邮件信息的示例
for(auto it = playerInfo.providerInfoData.begin(); it != playerInfo.providerInfoData.end(); ++it) {
hive::ProviderInfo providerInfo = it->second;
if(!providerInfo.providerEmail.empty()) {
std::string email = providerInfo.providerEmail;
break;
}
}
}
else if (result.needExit()) {
// TODO: 实现应用程序退出功能
// 对于 Cocos2d-x 引擎用户
// 示例) exit(0);
// 对于 Unreal 引擎用户
// 示例) UKismetSystemLibrary::QuitGame(GetWorld(), nullptr, EQuitPreference::Quit, false);
}
});
API 参考: com.hive.AuthV4.showSignIn
// Hive SDK AuthV4 认证 UI 请求
AuthV4.showSignIn(object : AuthV4.AuthV4SignInListener {
override fun onAuthV4SignIn(result: ResultAPI, playerInfo: AuthV4.PlayerInfo?) {
if (result.isSuccess) {
// 认证成功
// playerInfo: 认证用户信息
// 获取电子邮件信息的示例
playerInfo?.let {
for ((key, value) in it.providerInfoData) {
var providerInfo: AuthV4.ProviderInfo = value
if(providerInfo.providerEmail.isNotEmpty()) {
val email = providerInfo.providerEmail
break
}
}
}
} else if (result.needExit()) {
// TODO: 实现应用程序退出功能
// e.g.) exitProcess(0)
}
}
})
API 参考: com.hive.AuthV4.showSignIn
// Hive SDK AuthV4 authentication UI request
AuthV4.showSignIn(new AuthV4.AuthV4SignInListener() {
@Override
public void onAuthV4SignIn(ResultAPI result, AuthV4.PlayerInfo playerInfo) {
if (result.isSuccess()) {
// 认证成功
// playerInfo: 认证用户信息
// 获取电子邮件信息的示例
if(playerInfo != null) {
for (Map.Entry<AuthV4.ProviderType, AuthV4.ProviderInfo> entry : playerInfo.getProviderInfoData().entrySet()) {
AuthV4.ProviderInfo providerInfo = entry.getValue();
if (providerInfo.getProviderEmail() != "") {
String email = providerInfo.getProviderEmail();
break;
}
}
}
}
else if (result.needExit()) {
// TODO: 实现应用程序退出功能
// e.g.) System.exit(0);
}
}
});
API 参考: HIVEAuthV4:showSignIn
var email = String()
// Hive SDK AuthV4 认证 UI 请求
AuthV4Interface.showSignIn { (result, playerInfo) in
if result.isSuccess() {
// 认证成功
// playerInfo: 认证用户信息
// 获取电子邮件信息的示例
if let playerInfo = playerInfo {
// 使用现有的 providerEmail(当前登录的提供者)搜索 providerInfo
for key in playerInfo.providerInfoData.keys {
if let providerInfo = playerInfo.providerInfoData[key],
providerInfo.providerEmail.count > 0 {
// providerEmail != ""
email = providerInfo.providerEmail
break
}
}
}
} else if result.needExit() {
// TODO: 实现应用程序退出功能
// e.g.) exit(0)
}
}
API 参考: HIVEAuthV4:showSignIn
__block NSString* email = @"";
// Hive SDK AuthV4 认证 UI 请求
[HIVEAuthV4 showSignIn:^(HIVEResultAPI *result, HIVEPlayerInfo *playerInfo) {
if([result isSuccess]){
// 认证成功
// playerInfo: 经过认证的用户信息
// 获取电子邮件信息的示例
if(playerInfo != nil) {
// 使用 providerEmail(当前登录的提供者)搜索 providerInfo
for (NSString* key in playerInfo.providerInfoData.allKeys) {
HIVEProviderInfo* providerInfo = playerInfo.providerInfoData[key];
if (providerInfo != nil && providerInfo.providerEmail.length > 0) {
// providerEmail != ""
email = providerInfo.providerEmail;
break;
}
}
}
} else if ([result needExit]) {
// TODO: 实现应用程序退出功能
// 例如:exit(0);
}
}];
明确登录自定义¶
可自定义的显式登录 UI 可以通过 providerTypeList
实现。providerTypeList
是在调用 AuthV4.setup()
方法初始化 Hive SDK 时返回的响应回调处理程序,或者在初始化后调用 AuthV4.Helper.getIDPList()
方法时返回的。此功能用于当您想根据游戏 UI 显示登录屏幕或主要暴露与特定 IdP 的集成时。在实现可自定义的 UI 后,根据用户的操作,通过调用 signIn()
方法并传入所需的 ProviderType 来实现登录。
Note
- 创建登录按钮时,应参考每个身份提供者提供的设计指南。
- 游戏中心:没有具体规定
- Google Play 游戏:品牌指南
- Google:品牌指南
- Hive 会员:Hive BI 指南
- Facebook:品牌资源中心
- QQ:政策和规定
- 微信:主要品牌和指南
- VK:VK 品牌手册
- 苹果:人机界面指南
- LINE:LINE 登录按钮设计指南
- 华为:HUAWEI ID 图标规范
- Steam:Steam 品牌指南
- X:X 品牌工具包
- Telegram:Telegram 徽标和应用截图
- 遵守 Google Featured 的 Google 登录按钮指南非常重要。
- 有关应用于 Hive 身份验证的多语言登录按钮名称,请参阅这里。
- 用户界面示例截图,仅显示登录屏幕上的Facebook集成按钮
以下是一个示例源代码,假设用户在自定义的显式登录用户界面中选择了 Google 登录。
API 参考: hive.AuthV4.signIn
using hive;
AuthV4.signIn(AuthV4.ProviderType.GOOGLE, (ResultAPI result, AuthV4.PlayerInfo playerInfo) => {
if (result.isSuccess()) {
// 调用成功
// playerInfo : 认证用户信息。
// 获取ProviderType.GOOGLE的电子邮件信息示例
Dictionary<AuthV4.ProviderType, AuthV4.ProviderInfo> providerInfoData = playerInfo.providerInfoData;
AuthV4.ProviderInfo providerInfo = providerInfoData[AuthV4.ProviderType.GOOGLE];
string email = providerInfo.providerEmail;
}
});
#include "HiveAuthV4.h"
FHiveAuthV4::SignIn(EHiveProviderType::GOOGLE,
FHiveAuthV4OnSignInDelegate::CreateLambda([this](const FHiveResultAPI& Result, const FHivePlayerInfo& PlayerInfo) {
if (Result.IsSuccess()) {
// 调用成功 (PlayerInfo: 认证用户信息)
// 示例:检索 EHiveProviderType::GOOGLE 的电子邮件信息
TMap<EHiveProviderType, FHiveProviderInfo> ProviderInfoData = PlayerInfo.ProviderInfoData;
if (const FHiveProviderInfo* ProviderInfo = ProviderInfoData.Find(EHiveProviderType::GOOGLE)) {
FString Email = ProviderInfo->ProviderEmail;
}
}
}));
API 参考: Auth4::signIn
#include <HIVE_SDK_Plugin/HIVE_CPP.h>
AuthV4::signIn(ProviderType::GOOGLE, [=](ResultAPI const & result, PlayerInfo const & playerInfo) {
if (result.isSuccess()) {
// 调用成功
// playerInfo : 已认证的用户信息。
// 获取 ProviderType::GOOGLE 的电子邮件信息示例
map<ProviderType, ProviderInfo> providerInfoData = playerInfo.providerInfoData;
ProviderInfo providerInfo = providerInfoData[ProviderType::GOOGLE];
string email = providerInfo.providerEmail;
}
});
API 参考: AuthV4.signIn
import com.hive.AuthV4
import com.hive.ResultAPI
AuthV4.signIn(AuthV4.ProviderType.GOOGLE, object : AuthV4.AuthV4SignInListener {
override fun onAuthV4SignIn(result: ResultAPI, playerInfo: AuthV4.PlayerInfo?) {
if (result.isSuccess) {
// 调用成功
// playerInfo: 经过身份验证的用户信息
// 获取ProviderType.GOOGLE的电子邮件信息示例
if (playerInfo != null) {
val providerInfoData = playerInfo.providerInfoData
val providerInfo = providerInfoData[AuthV4.ProviderType.GOOGLE]
if (providerInfo != null) {
val email = providerInfo.providerEmail
}
}
}
}
})
API 参考: com.hive.Auth4.signIn
import com.hive.AuthV4;
import com.hive.ResultAPI;
AuthV4.signIn(AuthV4.ProviderType.GOOGLE, (result, playerInfo) -> {
if (result.isSuccess()) {
// 调用成功
// playerInfo: 经过身份验证的用户信息
// 获取ProviderType.GOOGLE的电子邮件信息的示例
if (playerInfo != null) {
HashMap<AuthV4.ProviderType, AuthV4.ProviderInfo> providerInfoData = playerInfo.getProviderInfoData();
AuthV4.ProviderInfo providerInfo = providerInfoData.get(AuthV4.ProviderType.GOOGLE);
if (providerInfo != null) {
String email = providerInfo.getProviderEmail();
}
}
}
});
API 参考: AuthV4Interface.signIn
API 参考: HIVEAuth4:signIn
#import <HIVEService/HIVEService-Swift.h>
[HIVEAuthV4 signIn:HIVEProviderTypeGoogle handler:^(HIVEResultAPI *result, HIVEPlayerInfo *playerInfo) {
if ([result isSuccess]){
// 调用成功
// playerInfo: 经过身份验证的用户信息。
// 获取HIVEProviderTypeGoogle的电子邮件信息示例
if(playerInfo != nil) {
HIVEProviderInfo *providerInfo = playerInfo.providerInfoData[@"GOOGLE"];
if(providerInfo != nil){
NSString *email = providerInfo.providerEmail;
}
}
}
}];
检查设备上登录的 IdP 账户¶
自动登录仅使用保存的 PlayerID 的身份验证令牌密钥进行登录,而显式登录则登录到与多个 IdP 关联的帐户。在这两种情况下,登录的 PlayerID 的 IdP 帐户可能与实际设备 (DevicePlayer) 登录的 IdP 帐户不同。我们提供指导以统一这两个帐户,为未来的成就或排行榜使用做好准备。
以下是检查 IdP 信息的示例代码。
API 参考: AuthV4.Helper.syncAccount
using hive;
AuthV4.ProviderType providerType = AuthV4.ProviderType.GOOGLE;
AuthV4.Helper.syncAccount (providerType, delegate (ResultAPI result, AuthV4.PlayerInfo playerInfo) {
switch (result.code) {
case ResultAPI.Code.Success:
// 正常
break;
case ResultAPI.Code.AuthV4ConflictPlayer:
// 账户冲突
// 例如) 使用 Hive UI 时
// AuthV4.Helper.showConflict(...);
// 或者
// 例如) 实现 GameUI 时
// AuthV4.Helper.resolverConflict(...);// 选择当前用户时
// AuthV4.Helper.switchAccount(...);// 选择用户切换时
break;
default:
// 其他异常
break;
}
});
#include "HiveAuthV4.h"
FHiveAuthV4::Helper::SyncAccount(ProviderType,
FHiveAuthV4HelperDelegate::CreateLambda([this](const FHiveResultAPI& Result,
const TOptional<FHivePlayerInfo>& PlayerInfo) {
switch (Result.Code) {
case FHiveResultAPI::ECode::Success:
// 正常响应
break;
case FHiveResultAPI::ECode::AuthV4ConflictPlayer:
// 账户冲突
// 例如) 使用 Hive UI 时
// FHiveAuthV4::Helper::ShowConflict()
// 例如) 实现游戏 UI 时
// FHiveAuthV4::Helper::ResolveConflict() // 当前用户选择
// FHiveAuthV4::Helper::SwitchAccount() // 用户切换选择
break;
default:
// 其他异常情况
break;
}
}));
API 参考: AuthV4::Helper::syncAccount
#include <HIVE_SDK_Plugin/HIVE_CPP.h>
using namespace std;
using namespace hive;
ProviderType providerType = ProviderType::GOOGLE;
AuthV4::Helper::syncAccount(providerType, [=](ResultAPI const & result, shared_ptr<PlayerInfo> playerInfo) {
switch (result.code) {
case ResultAPI::Success:
// Normal
break;
case ResultAPI::AuthV4ConflictPlayer:
// 账户冲突
// 例如) 当使用 Hive UI 时
// AuthV4::Helper::showConflict(...);
// 或
// 例如) 当实现 GameUI 时
// AuthV4::Helper::resolverConflict(...);// 选择当前用户时
// AuthV4::Helper::switchAccount(...);// 选择切换用户时
break;
default:
// 其他异常
break;
}
});
API 参考: AuthV4.Helper.syncAccount
import com.hive.AuthV4
import com.hive.ResultAPI
val providerType = AuthV4.ProviderType.GOOGLE
AuthV4.Helper.syncAccount(providerType, object : AuthV4.Helper.AuthV4HelperListener {
override fun onAuthV4Helper(result: ResultAPI, playerInfo: AuthV4.PlayerInfo?) {
when (result.code) {
ResultAPI.Code.Success -> {
// 成功
}
ResultAPI.Code.AuthV4ConflictPlayer -> {
// 账户冲突
// 例如) 使用 Hive UI 时
// AuthV4.Helper.showConflict(...);
// 或
// 例如) 实现 GameUI 时
// AuthV4.Helper.resolverConflict(...);// 选择当前用户时
// AuthV4.Helper.switchAccount(...);// 选择用户切换时
}
else -> {
// 其他异常
}
}
}
})
API 参考: AuthV4.Helper.syncAccount
import com.hive.AuthV4;
import com.hive.ResultAPI;
AuthV4.ProviderType providerType = AuthV4.ProviderType.GOOGLE;
AuthV4.Helper.syncAccount(providerType, (result, playerInfo) -> {
switch (result.getCode()) {
case Success:
// 正常
case AuthV4ConflictPlayer:
break;
// 账户冲突
// 例如) 使用 Hive UI 时
// AuthV4.Helper.showConflict(...);
// 或
// 例如) 实现 GameUI 时
// AuthV4.Helper.resolverConflict(...);// 选择当前用户时
// AuthV4.Helper.switchAccount(...);// 选择用户切换时
break;
default:
// 其他异常情况
break;
}
});
API 参考: AuthV4Interface.helper().syncAccount
import HIVEService
let providerType: ProviderType = .Google
AuthV4Interface.helper().syncAccount(providerType) { result, playerInfo in
switch result.getCode() {
case .success:
// 正常
case .authV4ConflictPlayer:
// 账户冲突
// 例如) 使用 Hive UI 时
// AuthV4Interface.helper().showConflict(...);
// 或者
// 例如) 实现 GameUI 时
// AuthV4Interface.helper().resolverConflict(...);// 选择当前用户时
// AuthV4Interface.helper().switchAccount(...);// 选择用户切换时
default:
// 其他异常情况
break
}
}
API 参考: [HIVEAuthV4 helper] syncAccount
#import <HIVEService/HIVEService-Swift.h>
HIVEProviderType providerType = HIVEProviderTypeGoogle
[[HIVEAuthV4 helper] syncAccount: providerType handler: ^(HIVEResultAPI *result, HIVEPlayerInfo *playerInfo) {
switch ([result getCode]) {
case HIVEResultAPICodeSuccess:
// 正常
break;
case HIVEResultAPICodeAuthV4ConflictPlayer:
// 账户冲突
// 例如) 当使用 Hive UI 时
// [[HIVEAuthV4 helper] showConflict: ...];
// 或
// 例如) 当实现 GameUI 时
// [[HIVEAuthV4 helper] resolverConflict:...];// 当当前用户被选中
// [[HIVEAuthV4 helper] switchAccount:...];// 当用户切换被选中
break;
default:
// 其他异常
break;
}
}];
客户登录¶
访客登录功能允许用户在不选择 IdP 的情况下以访客模式玩游戏。您可以从 Hive SDK 提供的显式登录 UI 中选择访客登录,或通过自定义直接在游戏中实现访客登录。Windows 环境不支持访客登录。
作为访客登录时,您必须遵守以下政策。
客户登录政策¶
- 实现游戏,使得 IdP 认证用户和访客用户可以以相同的方式使用它。 即使以访客身份登录,Hive 平台的大多数功能也可以使用。因此,请实现您的游戏,以便以访客身份登录的用户可以与 IdP 关联的用户以相同的方式使用游戏。例如,访客用户也应该能够在游戏中购买物品和进行支付。
- 不要为访客用户提供注销功能。 如果用户在以访客身份登录后注销,他们将无法使用相同的 PlayerID 再次登录。因此,当用户以访客身份登录时,请不要提供注销按钮,以防止他们注销。
- 中国访客登录禁止政策 使用中国 IP 时,只有经过实名认证的用户才能充值和消费资源(自 2017 年 5 月 1 日起生效),因此访客登录不包括在可以使用中国 IP 登录的 IdP 列表中。
要执行访客登录,请调用signIn()
方法,并将ProviderType.GUEST
作为参数。
以下是执行访客登录的示例代码。
Note
在没有任何 IdP 认证的访客状态下,PlayerID 的 playerInfo 中没有 providerInfoData。
API 参考: hive.AuthV4.signIn
API 参考: Auth4::signIn
API 参考: AuthV4.signIn
API 参考: com.hive.Auth4.signIn
API 参考: AuthV4Interface.signIn
API 参考: HIVEAuth4:signIn
自定义登录¶
自定义登录 是一个功能,允许您使用与游戏本身集成的身份提供者(IdP)实现登录,除了Hive提供的IdP之外。尝试创建一个身份验证密钥(authKey),以便在调用自定义登录API时使用,具体请参阅 Authenticate v4 Custom Authentication。
在调用自定义登录 API 之后,您可以通过回调中接收到的 PlayerInfo 类实例访问 customProviderInfoData
数据,以检查自定义登录用户的信息。 customProviderInfoData
的 ProviderType (enum) 统一设置为 CUSTOM
,并可以通过 ProviderName (String) 进行详细区分。
在游戏中实现自定义登录的 IdP 的信息不包含在 AuthV4
类的 setup()
和 showSignIn()
方法调用的结果中。
如果您在第一次执行自定义登录后收到了 playerId 和 playerToken,则在重新调用自定义登录 API 时,authV4SessionExist(code)
的结果 API 将作为回调返回。在这种情况下,您应该使用参数 ProviderType.Auto
调用 signIn()
,以使用先前登录的帐户进行自动登录。请参阅下面的示例代码。
AuthV4
类的 connect()
和 disconnect()
方法不支持自定义登录 IdP 的额外集成和断开。connectWithAuthKey()
和 disconnectWithName()
方法支持自定义登录 IdP 的额外集成和断开。
这是一个实现自定义登录的示例代码。
API 参考: hive.AuthV4.signIn
// Twitter 登录直接在游戏中实现
Game.Login("CUSTOM_TWITTER", (string authKey) => {
AuthV4.signInWithAuthKey(authKey, (ResultAPI result, PlayerInfo playerInfo) => {
if (result.isSuccess()) {
Dictionary<string, ProviderInfo> customProviderInfoData = playerInfo.customProviderInfoData;
ProviderInfo providerInfo = customProviderInfoData["CUSTOM_TWITTER"];
// 检查以下用户链接信息
providerInfo.providerType; // ProviderType.CUSTOM,自定义类型是固定的,因此需要通过 providerName 区分
providerInfo.providerName; // "CUSTOM_TWITTER"
providerInfo.providerUserId; // 用于自定义 Twitter 登录的用户 ID
return;
}
else if (result.code == ResultAPI.Code.AuthV4SessionExist) {
// 如果 playerId 和 playerToken 已经被发放并且需要自动登录
// TODO: AuthV4.signIn(ProviderType.AUTO, (ResultAPI _result, PlayerInfo playerInfo) => {});
}
else if (result.code == ResultAPI.Code.AuthV4NotInitialized) {
// TODO: 需要 SDK 初始化
}
else if (result.code == ResultAPI.Code.AuthV4InvalidParam) {
// TODO: 检查提供的 authKey 的值是否为 NULL 或空
}
else if (result.needExit()) {
// TODO: 实现应用退出功能
// 示例) Application.Quit();
}
});
});
#include "HiveAuthV4.h"
// 在游戏中直接实现了 "CUSTOM_TWITTER" 类型的 Twitter 登录
void GameLogin(const FString& AuthKey)
{
FHiveAuthV4::SignInWithAuthKey(AuthKey, FHiveAuthV4OnSignInDelegate::CreateLambda([this](const FHiveResultAPI& Result, const FHivePlayerInfo& PlayerInfo) {
if (Result.IsSuccess()) {
TMap<FString, FHiveProviderInfo> CustomProviderInfoData = PlayerInfo.CustomProviderInfoData;
if (const FHiveProviderInfo* ProviderInfo = CustomProviderInfoData.Find(TEXT("CUSTOM_TWITTER"))) {
EHiveProviderType ProviderType = ProviderInfo->ProviderType; // EHiveProviderType::CUSTOM, custom types are fixed
FString ProviderName = ProviderInfo->ProviderName; // Need to distinguish by ProviderName
FString ProviderUserId = ProviderInfo->ProviderUserId; // User id used in the custom Twitter login
}
} else if (Result.NeedExit()) {
// TODO: 实现应用退出功能
// e.g.) UKismetSystemLibrary::QuitGame(GetWorld(), nullptr, EQuitPreference::Quit, false);
} else if (Result.Code == FHiveResultAPI::ECode::AuthV4SessionExist) {
// 如果 playerId 和 playerToken 已经被发放并且需要自动登录
// TODO: FHiveAuthV4.SignIn(EHiveProviderType::GUEST, Delegate);
} else if (Result.Code == FHiveResultAPI::ECode::AuthV4NotInitialized) {
// TODO: 需要 SDK 初始化
} else if (Result.Code == FHiveResultAPI::ECode::AuthV4InvalidParam) {
// TODO: 检查提供的 authKey 的值是否为空
}
}));
}
API 参考: Auth4::signIn
using namespace std;
using namespace hive;
// Twitter 登录直接在游戏中实现
Game::Login("CUSTOM_TWITTER", [=](string authKey) {
AuthV4::signInWithAuthKey(authKey, [=](ResultAPI const & result, PlayerInfo const & playerInfo) {
if (result.isSuccess()) {
map<string, ProviderInfo> customProviderInfoData = playerInfo.customProviderInfoData;
ProviderInfo providerInfo = customProviderInfoData["CUSTOM_TWITTER"];
// 检查以下用户链接信息
providerInfo.providerType; // ProviderType::CUSTOM, 自定义类型是固定的,因此需要通过 providerName 区分
providerInfo.providerName; // "CUSTOM_TWITTER"
providerInfo.providerUserId; // 用于自定义 Twitter 登录的用户 ID
return;
}
else if (result.code == ResultAPI::Code::AuthV4SessionExist) {
// 如果 playerId 和 playerToken 已经被发放并且需要自动登录
// TODO: AuthV4.signIn(ProviderType::AUTO, [=](ResultAPI const & _result, PlayerInfo const & playerInfo) {});
}
else if (result.code == ResultAPI::Code::AuthV4NotInitialized) {
// TODO: 需要 SDK 初始化
}
else if (result.code == ResultAPI::Code::AuthV4InvalidParam) {
// TODO: 检查提供的 authKey 的值是否为 NULL 或空
}
else if (result.needExit()) {
// TODO: 实现应用退出功能
// 对于 Cocos2d-x 引擎用户
// e.g.) exit(0);
// 对于 Unreal 引擎用户
// e.g.) UKismetSystemLibrary::QuitGame(GetWorld(), nullptr, EQuitPreference::Quit, false);
}
});
});
API 参考: com.hive.Auth4.signIn
// 直接在游戏中实现Twitter登录
Game.Login("CUSTOM_TWITTER") { authKey: String ->
AuthV4.signInWithAuthKey(authKey, object : AuthV4.AuthV4SignInListener {
override fun onAuthV4SignIn(result: ResultAPI, playerInfo: AuthV4.PlayerInfo?) {
if (result.isSuccess && playerInfo != null) {
playerInfo.customProviderInfoData["CUSTOM_TWITTER"]?.let { providerInfo ->
providerInfo.providerType // ProviderType.CUSTOM, custom types are fixed by Type, so need to distinguish by providerName
providerInfo.providerName // "CUSTOM_TWITTER"
providerInfo.providerUserId // User id used for the custom Twitter login
}
}
else if (result.needExit()) {
// TODO: 实现应用退出功能
// e.g.) exitProcess(0)
}
else if (result.code == ResultAPI.Code.AuthV4SessionExist) {
// 如果 playerId 和 playerToken 已经发放并且需要自动登录
// TODO: AuthV4.signIn(AuthV4.ProviderType.AUTO, authV4SignInListener)
}
else if (result.code == ResultAPI.Code.AuthV4NotInitialized) {
// TODO: 需要 SDK 初始化
}
else if (result.code == ResultAPI.Code.AuthV4InvalidParam) {
// TODO: 检查提供的 authKey 的值是否为 NULL 或空
}
}
})
}
API 参考: com.hive.Auth4.signIn
// 在游戏中直接实现Twitter登录
Game.Login("CUSTOM_TWITTER") { authKey: String ->
AuthV4.signInWithAuthKey(authKey, new AuthV4.AuthV4SignInListener() {
@Override
public void onAuthV4SignIn(@NonNull ResultAPI result, @Nullable AuthV4.PlayerInfo playerInfo) {
if(result.isSuccess() && playerInfo != null) {
HashMap<String, AuthV4.ProviderInfo> customProviderInfoData = playerInfo.getCustomProviderInfoData();
AuthV4.ProviderInfo providerInfo = customProviderInfoData.get("CUSTOM_TWITTER");
// 检查以下用户链接信息
if (providerInfo != null){
providerInfo.getProviderType(); // AuthV4.ProviderType.CUSTOM,自定义类型由类型固定,因此需要通过providerName区分
providerInfo.getProviderName(); // "CUSTOM_TWITTER"
providerInfo.getProviderUserId(); // 用于自定义Twitter登录的用户ID
}
} else if (result.needExit()) {
// TODO: 实现应用退出功能
// e.g.) System.exit(0);
} else if (result.getCode() == ResultAPI.Code.AuthV4SessionExist) {
// 如果playerId和playerToken已经被发放并且需要自动登录
// TODO: AuthV4.signIn(AuthV4.ProviderType.AUTO, authV4SignInListener)
} else if (result.getCode() == ResultAPI.Code.AuthV4NotInitialized) {
// TODO: 需要SDK初始化
} else if (result.getCode() == ResultAPI.Code.AuthV4InvalidParam) {
// TODO: 检查提供的authKey的值是否为NULL或空
}
}
});
}
API 参考: HIVEAuth4:signIn
// 在游戏中直接实现Twitter登录
Game.login("CUSTOM_TWITTER") { (authKey) in
AuthV4Interface.signInWithAuthKey(authKey) { (result, playerInfo) in
if result.isSuccess() {
let customProviderInfoData = playerInfo?.customProviderInfoData;
let providerInfo = customProviderInfoData?["CUSTOM_TWITTER"]
// 检查以下用户链接信息
providerInfo?.providerType; // AuthProviderType,自定义类型由Type固定,因此需要通过providerName区分
providerInfo?.providerName; // "CUSTOM_TWITTER"
providerInfo?.providerUserId; // 用于自定义Twitter登录的用户ID
return
}
else if result.getCode() == .authV4SessionExist {
// 如果playerId和playerToken已经发放并且需要自动登录
// TODO: AuthV4Interface.signIn(.auto) { (result, playerInfo) in }
}
else if result.getCode() == .authV4NotInitialized {
// TODO: 需要SDK初始化
}
else if result.getCode() == .authV4invalidParam {
// TODO: 检查提供的authKey的值是否为nil或空
}
else if result.needExit() {
// TODO: 实现应用退出功能。
// 例如)exit(0)
}
}
}
API 参考: HIVEAuth4:signIn
// 在游戏中直接实现Twitter登录
[Game login:@"CUSTOM_TWITTER" handler:^(NSString* authKey) {
[HIVEAuthV4 signInWithAuthKey:authKey handler:^(HIVEResultAPI* result, HIVEPlayerInfo* playerInfo) {
if (result.isSuccess) {
NSDictionary<NSString*, HIVEProviderInfo*>* customProviderInfoData = playerInfo.customProviderInfoData;
ProviderInfo* providerInfo = [customProviderInfoData objectForKey:@"CUSTOM_TWITTER"];
// 检查以下用户链接信息
providerInfo.providerType; // HIVEProviderTypeCustom,因为自定义类型是固定的,需要通过providerName区分
providerInfo.providerName; // "CUSTOM_TWITTER"
providerInfo.providerUserId; // 在自定义Twitter登录中使用的用户ID
return;
}
else if (result.getCode == HIVEResultAPICodeAuthV4SessionExist) {
// 如果playerId和playerToken已经被发放,并且需要自动登录
// TODO: [HIVEAuthV4 signIn:HIVEProviderTypeAuto, handler:^(HIVEResultAPI* _result, HIVEPlayerInfo* playerInfo) {}];
}
else if (result.getCode == HIVEResultAPICodeAuthV4NotInitialized) {
// TODO: 需要SDK初始化
}
else if (result.getCode == HIVEResultAPICodeAuthV4InvalidParam) {
// TODO: 检查提供的authKey的值是否为NULL或空
}
else if (result.needExit) {
// TODO: 实现应用退出功能。
// 示例) exit(0);
}
}];
}];
用户名¶
由于美国的COPPA等问题,当您从美国及其领土访问并以IdP身份登录时,必须输入用户名以启用额外的用户身份验证处理。作为参考,包含在美国领土中的国家有美属萨摩亚(AS)、关岛(GU)、北马里亚纳群岛(MP)、波多黎各(PR)、美国小离岛(UM)和美属维尔京群岛(VI)。用户身份识别的用户名输入界面如下。
- 用户名输入屏幕仅用于用户识别目的,并且仅在初始 IdP 集成期间显示一次;此后将不再显示。
- 在访客登录期间不显示用户名输入屏幕。
身份验证令牌密钥验证¶
游戏服务器可以使用成功登录后返回的Token、playerId和DID信息验证令牌密钥的真实性。Hive 认证允许多设备登录和并发访问。
如果不允许使用相同账户重复访问,游戏服务器将在首次连接的设备上显示通知消息,然后终止游戏,允许游戏在后连接的设备上保持。在这种情况下,如果您尝试在不终止游戏的情况下再次访问,您的游戏记录可能无法正确反映。要实现此功能,您需要管理一个经过验证的令牌密钥或使用它管理游戏本身的会话密钥。
请参考身份验证令牌密钥验证服务器 API来实现此功能。
在后台检测 IdP 账户变更¶
用户可以在游戏运行时通过进入设备设置来更改他们的 Apple Game Center 或 Google Play 游戏账户。如果您需要检查游戏过程中 IdP 账户是否与当前 PlayerID 关联的 IdP 账户不同,请在初始化 SDK 后调用 setProviderChangedListener()
。通过调用此 API,当游戏恢复时,您将收到一个事件,指示设备上设置的 IdP 账户已更改。
iOS在Apple Game Center账户更改时运行,Android在Google Play Games账户更改时运行,只有当当前登录的PlayerID与该身份提供者(IdP)关联时,才会发送响应。当接收到IdP账户更改事件时,用户界面被配置为允许用户选择是否使用登录到设备的IdP账户。如果用户选择登录到设备的IdP账户,则调用signOut
进行注销,然后执行隐式登录。
Warning
由于Google Play游戏的操作问题,2021年7月后发布的安装了Google Play游戏的设备无法在后台更改IdP帐户。
Note
此功能可能会导致游戏中断和请求更改帐户,并且只能在需要帐户同步的情况下限制使用,例如进入大厅或商店时。
以下是一个示例代码,用于在用户重新启动游戏并且设备上设置的 IdP 账户已更改时接收事件。
API 参考: AuthV4::setProviderChangedListener
#include <HIVE_SDK_Plugin/HIVE_CPP.h>
using namespace std;
using namespace hive;
AuthV4::setProviderChangedListener([=](ResultAPI const & result, ProviderInfo const & providerInfo) {
if (!result.isSuccess()) {
return;
}
if (providerInfo != null && providerInfo.providerType == ProviderType::GOOGLE) {
// 更改 Google Play 游戏服务账户
}
});
API 参考: AuthV4.setProviderChangedListener
import com.hive.AuthV4
import com.hive.ResultAPI
AuthV4.setProviderChangedListener(object : AuthV4.AuthV4CheckProviderListener {
override fun onDeviceProviderInfo(result: ResultAPI, providerInfo: AuthV4.ProviderInfo?) {
if (!result.isSuccess) {
return
}
if (providerInfo != null && providerInfo.providerType == AuthV4.ProviderType.GOOGLE) {
// 更改 Google Play 游戏服务帐户
}
}
})
游戏数据初始化¶
在初始化游戏数据时不要调用注销。由于PlayerID没有被删除,可能会出现账户之间的冲突。您应该实现注销在用户明确请求之前不被调用,因为他们应该能够继续使用当前登录的账户进行游戏。
登出¶
Warning
- 登出时,身份验证信息 PlayerId 和会话信息 PlayerToken,以及所有 IDP 会话信息,将被删除。
- 所有以 set 开头的 API 设置的值将不会被初始化或删除。
- Configuration、Auth、Auth v4、Promotion 和 Push 类中所有以 set 开头的方法
- 以下是代表性的示例。 ex> Configuration.setServer, Configuration.setUseLog, Configuration.setGameLanguage, Configuration.setHiveCertificationKey, Auth.setEmergencyMode, AuthV4.setProviderChangedListener, Promotion.setUserEngagementReady, Promotion.setAddtionalInfo, Push.setRemotePush, Push.setForegroundPush 等等。所有以 set 开头的方法都属于此类别。
- 从 Hive SDK v4 24.3.0 开始,当游客用户登出时,将返回错误代码。之后,客户端和服务器会话将保持。
- 通过 SDK 中以 set 开头的方法设置的值的有效范围在应用程序的生命周期内保持,无论登录或登出状态如何。
如果您已登录Hive,则已发放PlayerID和身份验证令牌密钥。注销将执行重置PlayerID和身份验证令牌密钥的功能。当您调用signOut()
方法完成注销时,您将返回到游戏标题,并在点击标题时执行显式登录。
Note
- 在访客登录状态下注销时,无法再找到相同的 PlayerID,因此请实现使访客状态下不提供注销功能。
- PlayerID 的 IdP 关联状态在注销后不会改变。
- 一旦注销完成,将转到游戏标题,点击标题时将执行显式登录。
- 注销后,重新启动应用时将首先执行隐式登录。
这是一个执行注销的示例代码。
API 参考: hive.AuthV4.signOut
#include "HiveAuthV4.h"
FHiveAuthV4::Helper::SignOut(FHiveAuthV4HelperDelegate::CreateLambda([this](const FHiveResultAPI& Result, const TOptional<FHivePlayerInfo>& PlayerInfo) {
AHIVESDKV4TesterGameMode::getGameModeInstance()->appendLogString(ELogType::AuthV4Helper ,TEXT("Helper::SignOut Result = %s"), *(Result.ToString()));
switch (Result.Code) {
case FHiveResultAPI::ECode::Success:
// 登出成功
break;
default:
// 其他异常
break;
}
}));
API 参考: AuthV4::signOut
API 参考: AuthV4.Helper.signOut
API 参考: AuthV4.Helper.signOut
API 参考: [HIVEAuthV4 helper] 登出
游戏中心取消通知文本¶
语言 | 短语 |
---|---|
韩语 | Apple Game Center 登录已被取消。 请在 [设置 > Game Center] 登录以与您的 Game Center 账户同步并重试。 |
英语 | 您对 Game Center 的登录已被取消。 请在 [设置 > Game Center] 登录以与 Game Center 账户同步并重试。 |
日语 | Apple Game Center 登录已被取消。 请在 [设置 > Game Center] 登录以重试。 |
简体中文 | Apple Game Center 已注销。 如果您想与 Game Center 账户同步,请在 [设置 > Game Center] 重新登录并重试。 |
繁体中文 | Apple Game Center 登录已被取消。 如果您想链接 Game Center 账户,请在 [设置 > Game Center] 登录并重试。 |
法语 | 您与 Game Center 的连接已被取消。 请在 [设置 > Game Center] 登录以同步您的 Game Center 账户并重试。 |
德语 | 登录 Apple Game Center 已被取消。 通过 [设置 > Game Center] 与 Game Center 账户同步。登录并重试。 |
俄语 | 您对 Game Center 的登录已被取消。 请通过 [设置 > Game Center] 登录 Game Center 并重试。 |
西班牙语 | 您对 Game Center 的登录已被取消。 请在 [设置 > Game Center] 登录以与 Game Center 账户同步并重试。 |
葡萄牙语 | 您对 Game Center 的登录已被取消。 请在 [设置 > Game Center] 登录以与 Game Center 账户同步并重试。 |
印尼语 | Apple Game Center 登录已被取消。 通过在 [设置 > Game Center] 登录连接您的 Game Center 账户并重试。 |
马来语 | 您对 Game Center 的登录已被取消。 请在 [设置 > Game Center] 登录以与 Game Center 账户同步并重试。 |
越南语 | Apple Game Center 登录已被取消。 请在 [设置 > Game Center] 登录以与您的 Game Center 账户同步并重试。 |
泰语 | 您对 Game Center 的登录已被取消。 请在 [设置 > Game Center] 登录以连接到您的 Game Center 账户并重试。 |
意大利语 | 您对 Apple Game Center 的登录已被取消。 请在 [设置 > Game Center] 登录以与 Game Center 同步您的账户并重试。 |
土耳其语 | 您对 Apple Game Center 的登录已被取消。 请在 [设置 > Game Center] 登录以访问您的 Game Center 账户并重试。 |
阿拉伯语 | 您对 Game Center 的登录已被取消。 请在 [设置 > Game Center] 登录以与您的 Game Center 账户同步并重试。 |