跳转至

多账户登录管理

**多账户登录管理**是一项在登录或注销时保存账户信息的功能,允许用户重新加载保存的账户信息以便未来登录。通过利用先前经过身份验证的账户信息,这提供了更快、更便捷的登录体验。


操作流程和限制

在实施多账户登录管理功能之前,让我们解释一下操作流程和限制。

以下每个功能的操作流程是实现多账户登录管理时的示例场景供参考。根据您的开发环境,流程的顺序或保存账户信息的方法可能与这些场景不同。

在登录状态下保存账户信息

此场景描述了在用户完成显式登录后,保存账户信息的过程。

因此,在这种情况下,您可以稍后实现使用保存的帐户信息重新登录或删除帐户

※ 保存和处理账户信息的方法可能会因游戏客户端的实现而有所不同。


登出时保存账户信息

此场景描述了当已登录用户登出时保存账户信息。

因此,在这种情况下,您可以稍后使用保存的帐户信息实现重新登录或帐户删除

※ 保存和处理账户信息的方法可能会因游戏客户端的实现而有所不同。


使用保存的账户信息重新登录或删除

这是一个使用保存的账户信息重新登录或从检索到的列表中删除特定账户信息的流程,这是多账户登录管理的实际实施场景。

在用户从游戏中实现的 PlayerID 列表 UI 中选择账户的步骤中,行为会根据用户当前是否登录而有所不同。

※ 游戏客户端中实现的 PlayerID 列表的 UI 配置方法可能会根据游戏开发环境的不同而有所变化。

操作限制

实施多账户登录管理之前,请考虑以下操作限制。

  • 账户信息**仅在登录时**可以保存。
  • 使用保存的账户信息查看PlayerID列表或删除保存的账户信息可以在任何登录状态下进行。
  • 在查看PlayerID列表后,使用保存的账户信息重新登录**仅在注销时**可能。

实施指南

本指南解释了如何使用SDK实现多账户登录管理功能。

按照以下顺序逐步实现该功能,调用SDK提供的API:

  1. 登录完成后,保存当前登录的账户信息
  2. 要使用保存的账户登录或删除保存的账户信息,检索保存的账户信息(PlayerID 列表)
  3. 使用检索到的保存账户信息,实现当用户点击**多账户登录管理**时显示 PlayerID 列表 UI 的功能
  4. 在 PlayerID 列表 UI 中,实现使用保存的账户登录(PlayerID)删除保存的账户(PlayerID)

1. 保存当前登录的账户信息

保存当前登录的帐户信息。通过使用保存的帐户信息,您可以**在随后的登录过程中更快地登录,而无需单独的身份验证过程。**

在游戏客户端,如果用户已登录,请在账户设置菜单中提供一个UI元素,以允许用户随时保存当前登录的账户,并在用户激活账户保存功能时调用账户保存API。有关相关流程,请参阅上面的登录时保存账户信息场景。

当前登录账户保存的UI实现示例如下。

图 1. 实现当前登录账户保存的示例

此外,当用户注销时,您可以实现一个流程,如果用户已登录并选择注销,则会弹出一个提示框,询问是否保存帐户。如果用户点击**保存并注销**,则调用帐户保存 API 来保存当前登录的帐户信息,然后注销。有关相关流程,请参阅上面的注销时保存帐户信息场景。

图 2. 登出时保存当前登录账户的实现示例

调用API以保存当前登录帐户的示例代码如下。

AuthV4.storeCurrentPlayerId((ResultAPI result)=>{
    if (result.isSuccess()) {
        // API call succeeded
    }
});
FHiveAuthV4::StoreCurrentPlayerId(FHiveAuthV4OnStoreCurrentPlayerIdDelegate::CreateLambda([this](const FHiveResultAPI& Result) {
    if (Result.IsSuccess()) {
        // API call succeeded
    } 
}));
AuthV4::storeCurrentPlayerId([=](ResultAPI const & result) {
    if (result.isSuccess()) {
        // API call succeeded
    }
});
AuthV4.storeCurrentPlayerId(object : AuthV4.AuthV4StorePlayerIdListener {
    override fun onAuthV4StorePlayerId(result: ResultAPI) {
        if (result.isSuccess) {
            // API call succeeded
        }
    }
})
AuthV4.storeCurrentPlayerId(new AuthV4.AuthV4StorePlayerIdListener() {
    @Override
    public void onAuthV4StorePlayerId(ResultAPI result) {
        if (result.isSuccess()) {
            // API call succeeded
        }
    }
});
AuthV4Interface.storeCurrentPlayerId { (result) in
    if result.isSuccess() {
        // API call succeeded
    }
}
[HIVEAuthV4 storeCurrentPlayerId: ^(HIVEResultAPI * result) {
    if([result isSuccess]){
        // API call succeeded
    }
}];


2. 检索保存的账户信息(PlayerID 列表)

从SDK和身份验证服务器检索保存的帐户信息(PlayerID列表)。游戏客户端可以使用检索到的PlayerID列表来实现单独的PlayerID列表UI。

调用API以检索保存的账户信息(PlayerID列表)的示例代码如下。

AuthV4.getStoredPlayerIdList((ResultAPI result, List<long> playerIdList) =>
{
    if (result.isSuccess())
    {
        foreach (long playerId in playerIdList) {
            // API 调用成功
            // playerId: 玩家 ID
        }
    }
});
FHiveAuthV4::GetStoredPlayerIdList(FHiveAuthV4OnGetStoredPlayerIdListDelegate::CreateLambda([this](const FHiveResultAPI& Result, const TArray<int64>& PlayerIdList) {
    if (Result.IsSuccess()) {
        for (int64 PlayerId : PlayerIdList) {
            // API调用成功
            // playerId: 玩家ID
        }
    }
}));
AuthV4::getStoredPlayerIdList([=](ResultAPI const & result, std::vector<PlayerID> const& playerIdList) {
    if (result.isSuccess()) {
        for (auto playerId : playerIdList) {
            // API call succeeded
            // playerId: player ID
        }
    }
});
AuthV4.getStoredPlayerIdList(object : AuthV4.AuthV4PlayerIdListListener {
    override fun onAuthV4GetPlayerIdList(result: ResultAPI, playerIdList: ArrayList<Long>?) {
        if (result.isSuccess) {
            playerIdList?.let {
                for (playerId in it) {
                    // API call succeeded
                            // playerId: player ID
                }
            }
        }
    }
})
AuthV4.getStoredPlayerIdList(new AuthV4.AuthV4PlayerIdListListener() {
    @Override
    public void onAuthV4GetPlayerIdList(ResultAPI result, ArrayList<Long> playerIdList) {
        if (result.isSuccess()) {
            if(playerIdList != null) {
                for(Long playerId : playerIdList) {
                    // API call succeeded
                            // playerId: player ID
                }
            }
        }
    }
});
AuthV4Interface.getStoredPlayerIdList { (result, playerIdList) in
    if result.isSuccess() {
        for playerId in playerIdList {
                            // API 调用成功
                            // playerId: 玩家 ID
        }
    }
}
[HIVEAuthV4 getStoredPlayerIdList: ^(HIVEResultAPI * result, NSArray<NSNumber *> * playerIdList) {
    if([result isSuccess]){
        for (NSNumber* playerId in playerIdList) {
            // API call succeeded
            // playerId: player ID
        }
    }
}];


3. 使用保存的账户登录 (玩家ID)

通过多账户登录管理功能,快速使用已保存的账户(PlayerID)登录,且处于注销状态。

使用保存的帐户登录的实施步骤如下。

  1. 用户注销后再次尝试登录,在登录屏幕上,点击 多账户登录管理 → 调用 API 以检索保存的账户信息(PlayerID 列表)
  2. 显示在上一步中实现的 PlayerID 列表 UI
    图 3. 通过 多账户登录管理 使用保存的账户登录的示例

  3. 用户从 PlayerID 列表 UI 中选择一个特定账户并登录 → 调用 API 使用“保存的账户信息(PlayerID)”登录
    “调用 API 以使用保存的 PlayerID 登录的示例代码”如下:

    AuthV4.signInWithStoredPlayerId(playerId, useAutoSignIn, (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();
        }
    });
    
    FHiveAuthV4::SignInWithStoredPlayerId(playerId, useAutoSignIn, 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: 实现应用退出功能
            // e.g.) UKismetSystemLibrary::QuitGame(GetWorld(), nullptr, EQuitPreference::Quit, false);
        }
    }));
    
    AuthV4::signInWithStoredPlayerId(playerId, useAutoSignIn, [=](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);
        }
    });
    
        AuthV4.signInWithStoredPlayerId(playerId, useAutoSignInState, 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(
    

4. 删除保存的帐户 (PlayerID)

通过多帐户登录管理功能在注销状态下删除保存的帐户 (PlayerID)。

在显示的 PlayerID 列表 UI 中,用户可以选择删除保存的账户 (PlayerID),而不是登录。

图 4. 通过 多账户登录管理 删除已保存账户的示例


<

调用API以删除已保存账户(PlayerID)的示例代码如下。

AuthV4.deleteStoredPlayerId(playerId, (ResultAPI result)=>{
    if (result.isSuccess()) {
        // API call succeeded
    }
});
FHiveAuthV4::DeleteStoredPlayerId(playerId, FHiveAuthV4OnDeleteStoredPlayerIdDelegate::CreateLambda([this](const FHiveResultAPI& Result) {
    if (Result.IsSuccess()) {
        // API call succeeded
    } 
}));
AuthV4::deleteStoredPlayerId(playerId, [=](ResultAPI const & result) {
    if (result.isSuccess()) {
        // API call succeeded
    }
});
AuthV4.deleteStoredPlayerId(playerId, object : AuthV4.AuthV4DeletePlayerIdListener {
    override fun onAuthV4DeletePlayerId(result: ResultAPI) {
        if (result.isSuccess) {
            // API 调用成功
        }
    }
})
AuthV4.deleteStoredPlayerId(playerId, new AuthV4.AuthV4DeletePlayerIdListener() {
    @Override
    public void onAuthV4DeletePlayerId(ResultAPI result) {
        if (result.isSuccess()) {
            // API call succeeded
        }
    }
});
AuthV4Interface.deleteStoredPlayerId(playerId) { (result) in
    if result.isSuccess() {
        // API call succeeded
    }
}
[HIVEAuthV4 deleteStoredPlayerId: playerId handler:^(HIVEResultAPI *result) {
    if([result isSuccess]){
        // API call succeeded
    }
}];


错误代码

本节解释了在实现多账户登录管理功能时,SDK发送的错误代码。

错误代码 消息 描述
NEED_INITIALIZE AuthV4NotInitialized 如果SDK设置尚未完成(AuthV4.setup)
IN_PROGRESS AuthV4InProgress 如果在收到响应之前再次调用API
INVALID_SESSION AuthV4SessionNotExist 如果请求的PlayerID在列表中不存在
INVALID_SESSION AuthV4SessionProcessingFail 保存/删除会话失败

 


实施说明

请注意在实施多账户登录管理功能时的以下事项。

  • API连续调用限制

    如果在接口调用后未收到响应之前反复调用API,您可能无法收到正常的响应。请确保在调用下一个API之前等待响应。

  • 登录会话存储方法的注意事项

    登录会话是基于登录账户存储的,而不是设备。因此,根据实现方式,登录信息可能会暴露给使用同一设备的其他用户。在需要安全性的服务中使用登录会话存储功能时,请谨慎行事。

  • 禁止使用多账户登录管理功能以适应COPPA(ageGateU13 = true)

    多账户登录管理功能通过保存账户信息实现快速登录。然而,对于受COPPA约束的用户,请限制多账户登录管理功能,以便不保存账户信息且不提供基于会话的登录。

    SDK不会自动限制多账户登录管理功能的使用,因此需要单独应对。此外,COPPA限制对13岁以下用户的个人信息的收集、使用和共享,因此建议避免存储相关数据,包括会话信息。