登录注销
登录登出¶
Note
- 帮助程序提供了 SDK v4.7.0。要使用早于 SDK 4.7.0 的版本,请参阅此页面。
- 有关 AuthV4.Helper 的更多描述,请参阅 Authentication 页面。
登录¶
登录认证由以下步骤组成。
Authv4Helper 执行登录过程的某些部分,并根据响应指示正确的页面。
请参考以下说明以实现登录功能。
Note
苹果不支持 iOS 企业版的 Apple Game Center 和应用内购买。因此,在 iOS 企业版中无法使用 Apple Game Center 账户进行隐式登录,也无法在显式登录状态下使用 Apple Game Center。
Note
-
如果您的游戏的目标是13岁以下的儿童,则Google Build的隐式登录不可用,因为无法应用Google Play游戏服务。有关更多信息,请参阅Google Play游戏服务质量检查清单。
-
确保仅在用户第一次登录您的游戏时处理 Google Play 游戏的隐式登录。有关更多信息,请参见 Google 开发者指南中的 1.5 记住玩家是否拒绝登录。
Note
- 在中国,隐式登录在Android上不可用,因为Google Play游戏在该国被禁止。
- Facebook不在身份提供者(IdP)列表中,因为Facebook在中国不可用。
- 如果用户使用中国IP访问游戏,只有授权成员可以充值游戏币或购买物品(自2017年5月1日起)。因此,在中国IP中,游客登录被排除在可以登录的IdP列表之外。
Note
当取消登录 Apple Game Center 时,iOS 不会显示登录屏幕。因此,可以通过在 SDK 或游戏工作室中直接实现 AuthV4Helper
类中的 showGameCenterLoginCancelDialog()
方法来显示通知短语。如果 AuthV4.signIn(AuthV4.ProviderType.APPLE, ...)
和 AuthV4.connect(AuthV4.ProviderType.APPLE, ...)
的回调结果为取消,则可以使用 Game Center 登录禁用的通知短语。提供短语以指导用户如何再次与 Game Center 账户同步。
Note
如果在用户设备上没有使用 Apple ID 登录尝试使用 Apple 登录,调用 AuthV4Helper 类中的 connect()
和 signIn()
方法时会发生 AuthV4SignInAppleUnknown 错误。在这种情况下,会自动弹出一个用于 Apple ID 登录的通知弹窗,因此游戏工作室没有任何可以调用的内容。
自动登录和隐式登录¶
自动登录¶
隐式登录是一种用户不选择登录方式,而是自动登录iOS上的Apple Game Center账户或Android上的Google Play Games账户的方法。在自动登录失败后执行隐式登录。
离线模式¶
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中,仅当用户启用“保持我登录”复选框(在登录UI中的IdP列表下方显示)时,才会保持登录状态。在其他情况下,登录状态不会持续。
- 在移动环境中,当您执行 AuthV4Helper.Connect 并切换到另一个帐户时,新登录的帐户也通过自动登录保持登录状态,但在Windows中则不会。
隐式登录¶
AuthV4.Helper.signIn
尝试通过使用 PlayerID 的认证令牌密钥进行自动登录。如果之前登录生成的令牌密钥不存在,游戏将自动为 iOS 登录 Apple Game Center,为 Android 登录 Google Play Games。如果登录失败,它会根据响应显示适当的登录页面。
Note
在实现AuthV4Helper类的情况下,
- 如果用户在加载游戏时取消了对PGS的隐式登录,系统会记住该状态,并不会再次尝试隐式登录。即使在玩家会话有效时可以自动登录,系统也会记住被拒绝的状态。
这些内容符合 Google Play 游戏服务指南。
以下是执行自动登录的示例代码。
API Reference: 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"
// 尝试 Hive SDK 登录 (signIn)
FHiveAuthV4::Helper::SignIn(FHiveAuthV4HelperDelegate::CreateLambda([this](const FHiveResultAPI& Result, const TOptional<FHivePlayerInfo>& 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 FHiveResultAPI::ECode::AuthV4ConflictPlayer:
// 账户冲突
break;
case FHiveResultAPI::ECode::AuthV4HelperImplifiedLoginFail:
// 隐式登录失败
// 例如) AuthV4.showSignIn(...);)
break;
default:
// 其他异常
break;
}
}
}));
API 参考: Auth4::signIn
// 尝试 Hive SDK 登录 (signIn)
AuthV4::Helper::signIn([=](ResultAPI const & result, std::shared\_ptr playerInfo) {
if (result.isSuccess()) {
// log-in succeed
} else if (result.needExit()) {
// TODO: implement app exit functionality
// Users of the Cocos2d-x engine
// ex) exit(0);
// Unreal engine users
// Example) UKismetSystemLibrary::QuitGame(GetWorld(), nullptr, EQuitPreference::Quit, false);
} else {
switch(result.code) {
case ResultAPI::AuthV4ConflictPlayer:
// account conflict
break;
case ResultAPI::AuthV4HelperImplifiedLoginFail:
// implicit login failed
// ex) AuthV4.showSignIn(...);
break;
default:
break;
}
}
});
API 参考: com.hive.Auth4.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: 实现应用退出功能
// ex) exitProcess(0)
} else {
when (result.code) {
ResultAPI.Code.AuthV4ConflictPlayer -> {
// 账户冲突
}
ResultAPI.Code.AuthV4HelperImplifiedLoginFail -> {
// 隐式登录失败
// ex) AuthV4.showSignIn(...);
}
else -> {
// 其他异常
}
}
}
}
})
API 参考: com.hive.Auth4.signIn
// 尝试 Hive SDK 登录 (signIn)
AuthV4.Helper.signIn(new AuthV4.Helper.AuthV4HelperListener() {
@Override
public void onAuthV4Helper(ResultAPI result, AuthV4.PlayerInfo playerInfo) {
if (result.isSuccess()) {
// 登录成功
} else if (result.needExit()) {
// TODO: 实现应用退出功能
// ex) System.exit(0);
} else {
switch(result.code) {
case AuthV4ConflictPlayer:
// 账户冲突
break;
case AuthV4HelperImplifiedLoginFail:
// 隐式登录失败
// ex) AuthV4.showSignIn(...);
break;
default:
// 其他异常
break;
}
}
}
});
API 参考: AuthV4Interface.signIn
// 尝试 Hive SDK 登录 (signIn)
AuthV4Interface.helper().signIn() { (result, playerInfo) in
if result.isSuccess() {
// 登录成功
}
else if result.needExit() {
// TODO: 实现应用退出功能
// ex) exit(0)
}
else {
switch result.getCode() {
case .authV4ConflictPlayer:
// 账户冲突
case .authV4HelperImplifiedLoginFail:
// 隐式登录失败
// ex) AuthV4Interface.showSignIn() { (result, playerInfo)
// // 做一些事情...
// }
default:
// 其他异常
break
}
}
}
API 参考: HIVEAuth4:signIn
// 尝试 Hive SDK 登录 (signIn)
[[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 Windows等,Windows)上,隐式登录(AuthV4.Helper.signIn
)在初始登录后会自动使用上次登录的账户进行登录,而不会导致任何账户冲突。
显式登录¶
显式登录是指用户选择身份提供者(IdP)进行身份验证的过程。如果玩家未能执行自动登录和隐式登录,则应实现游戏,使玩家在点击标题时转到游戏标题屏幕并执行显式登录。
显式登录由Hive SDK提供的用户界面或在使用身份提供者(IdP)列表初始化Hive SDK后在游戏中自定义的用户界面组成。如果您自定义用户界面,请参阅自定义显式登录用户界面。
Hive 平台根据各国的政策控制并提供 IdP 列表。例如,Google Play 游戏、Facebook 和游客登录在中国不可用。
显式登录的示例屏幕¶
在使用 Hive SDK 提供的 UI 实现功能时¶
要使用 Hive SDK 提供的 UI 实现显式登录,您可以通过调用 showSignIn()
方法来显示 IdP 列表 UI。
Note
确保在用户点击SDK提供的IdP选择UI中的X按钮关闭后,提供再次登录的方法。因为用户尚未登录。
Note
如果您想自定义显式登录,请参见这里。
API 参考: hive.AuthV4.showSignIn
<code>
// 请求 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: Implement the termination of the app
// Example) Application.Quit();
}
});
#include "HiveAuthV4.h"
// 请求 Hive SDK AuthV4 认证 UI
FHiveAuthV4::ShowSignIn(FHiveAuthV4OnSignInDelegate::CreateLambda([this](const FHiveResultAPI& Result, const FHivePlayerInfo& PlayerInfo) {
if (Result.IsSuccess()) {
// 认证成功
// 获取电子邮件信息的示例
for (const auto& ProviderInfoEntry : PlayerInfo.ProviderInfoData) {
FHiveProviderInfo ProviderInfo = ProviderInfoEntry.Value;
FString Email = ProviderInfo.ProviderEmail;
}
} else if (Result.NeedExit()) {
// TODO: 实现应用程序的终止
// Cocos2d-x 引擎的用户
// 例如) exit(0);
// Unreal 引擎用户
// 示例) UKismetSystemLibrary::QuitGame(GetWorld(), nullptr, EQuitPreference::Quit, false);
}
}));
API 参考: AuthV4::showSignIn
// 请求 Hive SDK AuthV4 认证 UI
AuthV4::showSignIn([=](ResultAPI const & result, PlayerInfo const & playerInfo) {
if (result.isSuccess()) {
// 认证成功
// playerInfo: 认证用户信息
// 获取电子邮件信息的示例
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: 实现应用程序的终止
// 例如) exitProcess(0)
}
}
})
API 参考: com.hive.AuthV4.showSignIn
// 请求 Hive SDK AuthV4 认证 UI
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: 实现应用程序的终止
// 示例) 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: 实现应用程序的终止
// 例如) 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) {
// 查找提供商信息,提供商电子邮件存在(当前登录的提供商)
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
实现自定义的显式登录 UI,该列表作为 AuthV4.setup()
方法的回调处理程序返回,该方法在 Hive SDK 初始化时调用,或者在 Hive SDK 初始化后调用 AuthV4.Helper.getIDPList()
方法。当您希望根据游戏 UI 显示登录屏幕,或仅显示与特定 IdP 的链接选项时,可以自定义显式登录 UI。设计完 UI 后,根据用户的操作调用 signIn()
方法并传入所需的 ProviderType。
Note
- 创建登录按钮时,必须参考每个 IdP 提供的设计指南。
- 游戏中心:没有额外的指南
- Google Play 游戏: 品牌指南
- Google: 品牌指南
- Hive 会员: Hive BI 指南
- Facebook: 品牌资源中心
- QQ: 政策和规定
- 微信: 主要品牌和指南
- VK: VK 品牌手册
- 苹果: 人机界面指南
- LINE: LINE 登录按钮设计指南
- 华为: HUAWEI ID 图标规范
- 您必须遵守 Google 登录按钮指南,以便在 Google Play 商店中展示您的游戏。
- 有关在身份验证中应用的多语言登录按钮名称,请点击 这里。
- 示例 UI 仅在登录页面上显示 Facebook 同步的按钮
以下是用户在自定义显式登录 UI 上选择 Google 登录时的示例代码。
API 参考: hive.AuthV4.signIn
using hive;
AuthV4.signIn(AuthV4.ProviderType.GOOGLE, (ResultAPI result, AuthV4.PlayerInfo playerInfo) => {
if (result.isSuccess()) {
// call successful
// playerInfo: Authenticated user information.
// Example of email information search for 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: 已验证的用户信息。
// 示例:搜索 ProviderType::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()) {
// call successful
// playerInfo: Authenticated user information.
// 示例:搜索 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) {
// call successful
// playerInfo: Authenticated user information
// Example of email information search for 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.INSTANCE.signIn(AuthV4.ProviderType.GOOGLE, (result, playerInfo) -> {
if (result.isSuccess()) {
// call successful
// playerInfo: Authenticated user information
// Example of email information search for 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
import HIVEService
AuthV4Interface.signIn(.Google) { result, playerInfo in
if result.isSuccess() {
// call successful
// playerInfo: Authenticated user information
// 示例:搜索 ProviderType::GOOGLE 的电子邮件信息
if
let playerInfo = playerInfo,
let providerInfo = playerInfo.providerInfoData["GOOGLE"] {
let email = providerInfo.providerEmail
}
}
}
API 参考: HIVEAuth4:signIn
#import <HIVEService/HIVEService-Swift.h>
[HIVEAuthV4 signIn:HIVEProviderTypeGoogle handler:^(HIVEResultAPI *result, HIVEPlayerInfo *playerInfo) {
if ([result isSuccess]){
// call successful
// playerInfo: Authenticated user information.
// HIVEProviderTypeGoogle 的电子邮件信息搜索示例
if(playerInfo != nil) {
HIVEProviderInfo *providerInfo = playerInfo.providerInfoData[@"GOOGLE"];
if(providerInfo != nil){
NSString *email = providerInfo.providerEmail;
}
}
}
}];
检查设备上的已登录 IdP 账户¶
自动登录可使用注册的 playerId
的令牌密钥进行登录,同时也支持与各种 IdP 的显式登录。在这两种情况下,用户设备上登录的 IdP 账户(DevicePlayer)可能与用户登录的 PlayerID 的 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
// AuthV4::Helper::showConflict(...);
// 或者
// 例如) 当实现 GameUI
// AuthV4::Helper::resolverConflict(...);// 当选择当前用户时
// AuthV4::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 -> {
// normal
}
ResultAPI.Code.AuthV4ConflictPlayer -> {
// 账户冲突
// 例如) 当使用 Hive UI
// AuthV4.Helper.showConflict(...);
//或者
// 例如) 当实现 GameUI
// AuthV4.Helper.resolverConflict(...);// 选择当前用户时
// AuthV4.Helper.switchAccount(...);// 选择用户切换时
}
else -> {
// 其他异常情况
}
}
}
})
API 参考: AuthV4.Helper.INSTANCE.syncAccount
import com.hive.AuthV4;
import com.hive.ResultAPI;
AuthV4.ProviderType providerType = AuthV4.ProviderType.GOOGLE;
AuthV4.Helper.INSTANCE.syncAccount(providerType, (result, playerInfo) -> {
switch (result.getCode()) {
case Success:
// normal
break;
case AuthV4ConflictPlayer:
// 账户冲突
// 例如) 使用 Hive UI 时
// AuthV4.Helper.INSTANCE.showConflict(...);
//或者
// 例如) 实现 GameUI 时
// AuthV4.Helper.INSTANCE.resolverConflict(...);// 选择当前用户时
// AuthV4.Helper.INSTANCE.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:
// normal
case .authV4ConflictPlayer:
// account conflict
// ex) When using Hive UI
// AuthV4Interface.helper().showConflict(...);
//or
// ex) When implementing GameUI
// AuthV4Interface.helper().resolverConflict(...);// When selecting the current user
// AuthV4Interface.helper().switchAccount(...);// When selecting user switch
default:
// other exception situations
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;
}
}];
客户登录¶
Hive SDK 支持访客登录,允许用户在不选择 IdP 的情况下以访客身份使用游戏。您可以通过 Hive SDK 提供的显式登录 UI,或通过游戏的自定义 UI 实现此功能,以便用户选择访客。Windows 环境不支持访客登录。
确保在以访客身份登录时遵守以下政策。
客户登录政策¶
-
构建一个对访客用户和 Hive 会员同样可用的游戏。
Hive 平台的大多数功能对访客用户开放。因此,请为访客用户和 IdP 连接用户实现相同的游戏。例如,访客用户也可以购买物品并在游戏中付款。
-
不要允许访客用户注销。
如果用户以访客身份登录,然后注销,则该用户将无法使用相同的 PlayerID 重新登录。因此,请不要提供注销按钮,以防止用户在其状态为访客时注销。
-
中国IP的访客登录政策。
如果用户使用中国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 SDK 不支持此功能。请遵循 Auth V4 自定义身份验证 指南创建一个 authKey,用于调用自定义登录 API。 您可以通过访问 customProviderInfoData
来确认使用自定义登录的用户信息,该信息与作为自定义登录 API 回调传递的 PlayerInfo 对象一起使用。 customProviderInfoData
的 ProviderType(enum) 均设置为 CUSTOM
,并可以通过 ProviderName(String) 进行详细识别。
- 实现自定义登录的 IdP 的信息不包括在调用
setup()
和showSignIn()
方法的 AuthV4 类的结果中。- 如果在第一次执行自定义登录后获取到 playerId 和 playerToken,则在重新调用自定义登录 API 时,
authV4SessionExist(code)
的结果 API 将作为回调传递。在这种情况下,使用参数ProviderType.Auto
实现signIn()
方法,以使用先前的登录帐户执行自动登录。- AuthV4 类的
connect()
和disconnect()
方法目前不支持自定义登录 IdP 的额外连接和断开。- 自定义登录的 IdP 的额外同步或断开通过
connectWithAuthKey()
和disconnectWithName()
方法支持。
以下是实现自定义登录的示例代码。
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"
// 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, ProviderType::CUSTOM, customs have a fixed type, so you need to distinguish them by providerName
FString ProviderName = ProviderInfo->ProviderName; // "CUSTOM_TWITTER"
FString ProviderUserId = ProviderInfo->ProviderUserId; // user id used for self-implemented twitter login
}
} else if (Result.NeedExit()) {
// 例如) UKismetSystemLibrary::QuitGame(GetWorld(), nullptr, EQuitPreference::Quit, false);
} else if (Result.Code == FHiveResultAPI::ECode::AuthV4SessionExist) {
// 如果您需要在已经发出 playerId 和 playerToken 后自动登录
// TODO: AuthV4.signIn(ProviderType::AUTO, [=](ResultAPI const & _result, PlayerInfo const & playerInfo) {});
} else if (Result.Code == FHiveResultAPI::ECode::AuthV4NotInitialized) {
// TODO: 需要初始化 SDK
} else if (Result.Code == FHiveResultAPI::ECode::AuthV4InvalidParam) {
// TODO: 需要检查传递的 authKey 值是否为 NULL 或为空
}
}));
}
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 引擎的用户
// ex) exit(0);
// Unreal 引擎用户
// 示例) 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, since custom types are fixed, it is necessary to distinguish them by providerName
providerInfo.providerName // "CUSTOM_TWITTER"
providerInfo.providerUserId // user id used for Twitter login
}
}
else if (result. needExit()) {
// TODO: implement app exit functionality
// ex) exitProcess(0)
}
else if (result.code == ResultAPI.Code.AuthV4SessionExist) {
// If you need to log in automatically after having already issued playerId and playerToken
// TODO: AuthV4.signIn(AuthV4.ProviderType.AUTO, authV4SignInListener)
}
else if (result.code == ResultAPI.Code.AuthV4NotInitialized) {
// TODO: need to initialize SDK
}
else if (result.code == ResultAPI.Code.AuthV4InvalidParam) {
// TODO: Need to check whether the passed authKey value is NULL or empty
}
}
})
}
API 参考: com.hive.Auth4.signIn
// Twitter 登录直接在游戏中实现
Game.Login("CUSTOM_TWITTER") { authKey: String ->
AuthV4.INSTANCE.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: 实现应用退出功能
// ex) 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
swift // 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,由于自定义类型是固定的,因此需要通过 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: 实现应用程序关闭功能。 // ex) 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: 实现应用程序关闭功能。
// ex) exit(0);
}
}];
}];
用户名¶
由于美国COPPA等问题,当您从美国或其领土访问并使用IdP登录时,必须输入您的用户名以启用额外用户身份验证。作为参考,包含在美国领土中的国家有美属萨摩亚(AS)、关岛(GU)、北马里亚纳群岛(MP)、波多黎各(PR)、美国小岛屿(UM)和美属维尔京群岛(VI)。用户身份识别的用户名输入屏幕如下。
- 用户名输入界面仅用于用户识别,因此仅在首次与身份提供者(IdP)链接时显示一次,之后不再显示。
- 以访客身份登录时,用户名输入界面不会显示。
验证身份验证令牌密钥¶
游戏服务器可以通过使用返回的令牌、playerId 和 DID 信息在成功登录后验证身份验证令牌密钥。身份验证允许多设备登录和重复连接。
除非您的游戏允许使用一个 ID 进行重复访问,否则游戏服务器会在已登录设备上显示通知并终止游戏。然后,第二个已登录设备保持其游戏状态。如果用户在一个设备上不终止游戏而保持重复连接,则游戏过程可能无法被准确记录。因此,请确保管理已验证的令牌密钥,或通过管理游戏本身的会话密钥来实现此功能,使用令牌密钥来处理此功能。
通过参考Hive 服务器 API > 验证身份 v4 令牌来实现该功能。
获取 TalkPlus 登录令牌¶
要登录TalkPlus,您需要通过Auth v4接口在登录(signIn())后调用AuthV4.getHiveTalkPlusLoginToken API获得的登录令牌。(请参阅TalkPlus登录指南)
在后台检测 IdP 账户的变化¶
用户可以在玩游戏时通过设备设置更改他们的 Apple Game Center 或 Google Play 游戏账户。如果您需要检查 IdP 账户是否与当前 PlayerID 连接的账户匹配,请在初始化 Hive SDK 后实现 setProviderChangedListener()
。如果您实现了该 API,用户在游戏恢复时可以接收到通知用户设备上链接的 IdP 账户更改的事件。
当Apple Game Center中的账户更改时,iOS可以正常工作;当Google Play Games中的账户更改时,Android可以正常工作。只有当当前登录的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) {
// Change Google Play Game Service account
}
}
})
API 参考 : : com.hive.authv4.SetproviderChangeDlistener
初始化游戏数据¶
确保在初始化游戏数据时不要实现注销。PlayerID不会通过初始化被删除,因此可能会导致账户之间的崩溃。让用户使用当前登录的账户玩游戏,并且在用户明确请求点击注销按钮之前,不要实现注销功能。
登出¶
Warning
- 登出时,PlayerId(认证信息)、PlayerToken(会话信息)以及所有 IDP 会话信息将被删除。
- 登出时,通过 setter API(
set
API 系列)设置的值不会被初始化或删除。- Configuration、Auth、Auth v4、Promotion 和 Push 类中的每个 setter 方法
- 示例:Configuration.setServer,Configuration.setUseLog, Configuration.setGameLanguage,Configuration.setHiveCertificationKey, Auth.setEmergencyMode,AuthV4.setProviderChangedListener, Promotion.setUserEngagementReady,Promotion.setAddtionalInfo, Push.setRemotePush,Push.setForegroundPush 等等。
- 从 Hive SDK v4 24.3.0 开始,当访客用户登出时,将返回错误代码。此后客户端和服务器会话将保持。
- setter 方法设置的值的有效范围在应用程序的生命周期内维护,而不是在登录或登出状态下。
如果已执行登录,则已发放 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.INSTANCE.signOut
API 参考: [HIVEAuthV4 helper] signOut
游戏中心登录禁用的通知短语¶
语言 | 短语 |
---|---|
韩语 | Apple Game Center 로그인이 취소되었습니다. Game Center 계정과 연동하려면 [설정 >; Game Center]에서 로그인한 후 다시 시도해주세요. |
英语 | Your login to the Game Center has been canceled. Log in at [Settings >; Game Center] to sync to the Game Center Account and try again. |
日语 | Apple Game Center ログインがキャンセルされました。 Game Center アカウントと連動するには [設定 >; Game Center] にログインした後、再度お試しください。 |
简体中文 | Apple Game Center已退出登录。 若想与Game Center账号同步,请在设备[设置 >; Game Center]中重新登录后再试。 |
繁体中文 | 登入Apple Game Center已取消。 若想連動Game Center帳號,請至[設定 >; Game Center]登入後,再試一次。 |
法语 | Ta connexion au Game Center a été annulée. Connecte-toi dans [Réglages >; Game Center] pour synchroniser ton compte Game Center et essaie de nouveau. |
德语 | Das Einloggen ins Apple Game Center wurde abgebrochen. Die Synchronisation mit dem Game Center-Konto läuft über [Einstellungen >; Game Center]. Logge dich ein und versuche es erneut. |
俄语 | Ваш авторизация в Game Center была отменена. Авторизуйтесь в Game Center через [Настройки >; Game Center] и повторите попытку. |
西班牙语 | Tu Inicio de Sesión en Game Center ha sido cancelado. Inicia Sesión en [Configuración >; Game Center] para sincronizar a la Cuenta de Game Center, e inténtalo de nuevo. |
葡萄牙语 | O seu login no Game Center foi cancelado. Faça o login em [Configurações >; Game Center] para sincronizar com a Conta do Game Center e tente novamente. |
印尼语 | Login ke Apple Game Center telah dibatalkan. Hubungkan akun Game Center dengan login di [Pengaturan >; Game Center] dan coba lagi. |
马来语 | Log masuk ke Game Center anda telah dibatalkan. Log masuk di [Tetapan >; Game Center] untuk disegerakkan ke Akaun Game Center dan cuba lagi. |
越南语 | Đã hủy bỏ đăng nhập vào Apple Game Center. Đăng nhập tại [Cài đặt >; Game Center] để đồng bộ với tài khoản Game Center và thử lại. |
泰语 | การล็อกอินเข้า Game Center ของคุณถูกยกเลิก ล็อกอินที่ [การตั้งค่า >; Game Center] เพื่อเชื่อมต่อบัญชี Game Center และโปรดลองอีกครั้ง |
意大利语 | L'accesso all'Apple Game Center è stato annullato. Fai log-in su [Impostazioni >; Game Center] per sincronizzare il tuo account con il Game Center e riprova. |
土耳其语 | Apple Oyun Merkezine girişiniz iptal edilmiştir. Oyun Merkezi Hesabına ulaşmak için [Ayarlar >; Oyun Merkezi]'nden giriş yapın ve tekrar deneyin. |
阿拉伯语 | تم إلغاء تسجيل الدخول إلى مركز الألعاب. سجل الدخول إلى [الإعدادات >; مركز الألعاب] للمزامنة مع حساب مركز الألعاب وحاول مرة أخرى。 |