콘텐츠로 이동

로그인 로그아웃

인증에서 로그인은 다음의 순서로 구성합니다.

Note
  • SDK 4.7.0 미만 버전에서는 Helper를 지원하지 않습니다. 기존 로그인 적용 방법은 [다음]을 참고하세요.
  • AuthV4.Helper에 대한 설명은 인증 페이지를 참고하세요.

로그인

인증에서 로그인은 다음의 순서로 구성합니다.

  1. 자동 로그인 및 묵시적 로그인
  2. 명시적 로그인
  3. 기기에 로그인된 IdP 계정 확인
  4. 게스트 로그인

Authv4Helper 는 로그인과 관련된 일련의 과정을 수행하며, 응답 값에 따라 적절한 화면으로 이동하도록 구성하는 클래스입니다. 로그인 구성 시 다음 사항을 참고하세요.

Note

Apple은 iOS 엔터프라이즈 빌드에 Apple Game Center와 인앱을 지원하지 않습니다. 따라서 iOS 엔터프라이즈 빌드에서는 Apple Game Center 계정을 이용하는 묵시적 로그인을 사용할 수 없으며 명시적 로그인에서도 Apple Game Center를 이용할 수 없습니다.

Note
  • 게임이 주로 13 세 미만 어린이를 대상으로하는 경우 Google Play 게임 서비스를 적용할 수 없으므로 Google 빌드에서 묵시적 로그인을 사용할 수 없습니다. 자세한 내용은 Quality Checklist for Google Play Games Services를 참조하세요.
  • 최초 로그인 시에만 Google Play 게임 묵시적 로그인을 시도해야 합니다. 자세한 내용은 Google 개발 가이드 1.5 Remember if players declined signing-in을 참조하세요.
Note
  • 중국에서는 Google Play 게임을 이용할 수 없기 때문에 Android에서 묵시적 로그인을 사용할 수 없습니다.
  • 중국에서는 Facebook을 이용할 수 없기 때문에 IdP 목록에 Facebook이 포함되지 않습니다.
  • 중국 IP에서는 실명 인증된 유저만 재화를 충전 혹은 소비하는 서비스가 가능(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, ...)의 콜백 결과가 Cancel인 경우에 Game Center 취소 안내 문구를 사용하세요.

Note

만약 유저 기기가 Apple ID로 로그인되지 않은 상태에서 Apple로 로그인을 시도하면 AuthV4Helper 클래스의 connect(), signIn() 메서드를 호출하는 과정에 AuthV4SignInAppleUnknown 에러가 발생합니다. Apple ID 로그인 안내 팝업은 자동 노출되므로 게임 스튜디오에서 안내 팝업을 별도로 노출하지 않아도 됩니다.

만약 유저 기기가 Apple ID로 로그인되지 않은 상태에서 Apple로 로그인을 시도하면 AuthV4Helper 클래스의 connect(), signIn() 메서드를 호출하는 과정에 AuthV4SignInAppleUnknown 에러가 발생합니다. Apple ID 로그인 안내 팝업은 자동 노출되므로 게임 스튜디오에서 안내 팝업 을 별도로 노출하지 않아도 됩니다.

자동 로그인 및 묵시적 로그인

자동 로그인

유저가 로그인 수단을 선택하지 않고 iOS에서는 Apple Game Center 계정을, Android에서는 Google Play 게임 계정을 자동 연동하여 로그인하는 방식을 의미합니다. 자동 로그인을 구현하고, 자동 로그인에 실패했을 경우 묵시적 로그인을 수행합니다.

iOS 환경에서 자동 로그인을 사용하려면 Game Center Entitlement를 추가해야 하는데, Unity에서는 'Apple GameCenter' Dependency에 체크했다면 Unity PostProcess를 통해 자동으로 해당 Entitlement를 추가합니다. iOS Native에서는 Xcode가 자동으로 Game Center Entitlement를 추가합니다.

오프라인 모드

Hive SDK v4 23.1.0 이상에서는 유저 기기가 네트워크에 연결되지 않은 상태에서 앱을 실행했더라도 자동 로그인(ProviderType.AUTO를 사용하는 AuthV4.signIn, 또는 AuthV4.Helper.signIn) 기능을 제공할 수 있습니다. 오프라인 모드를 사용하려면 다음 안내를 따르세요.

  1. 온라인 상태에서 앱을 실행하여 명시적, 묵시적, 게스트, 또는 커스텀 로그인에 성공하고, playerIdplayerToken을 발급받은 적이 있어야 합니다.

    앱 개발사 입장에서는 온라인 상태에서 최소 한 번 이상 AuthV4.Helper.signIn, AuthV4.showSignIn, 또는 AuthV4.signInWithAuthKey 실행에 성공하여 콜백으로 playerIdplayerToken을 받은 적이 있어야 하며, 유저 입장에서는 유저 기기가 네트워크에 연결된 상태에서 최소 한 번 이상 앱에서 로그인에 성공했어야 합니다. 단, 유저가 온라인 상태에서 마지막으로 로그인을 시도했을 때 유저 계정이 이용 정지 또는 이용 제한 상태였다면, 유저는 오프라인 모드에서도 로그인할 수 없습니다.

  2. Hive 콘솔 앱센터 > 프로젝트 관리 > 게임 상세 > Hive 제품설정에서 오프라인 모드를 활성화합니다.

Windows 환경에서 자동 로그인

Windows 환경도 자동 로그인을 지원하며, Hive 콘솔 앱센터에서 활성화/비활성화할 수 있습니다. 단, Windows 자동 로그인은 모바일과 다르게 동작합니다. Windows에서 자동 로그인은 다음과 같은 차이가 있습니다.

  • 모바일에서는 로그인 이후에 무조건 자동 로그인으로 로그인 상태를 유지하지만, Windows에서는 유저가 로그인 유지 체크박스(로그인 UI상에서 IdP 목록 하단에 표시)를 활성화한 경우에만 로그인을 유지합니다. 그 외 상황에서는 로그인을 유지하지 않습니다.
  • AuthV4Helper.Connect 실행 시 모바일에서는 새로운 계정으로 계정을 전환할 경우 새 계정도 자동 로그인 상태를 유지하지만, Windows에서는 새로운 계정으로 계정을 전환할 경우 새 계정은 자동 로그인 상태를 유지하지 않습니다.

묵시적 로그인

  • 묵시적 로그인 플로우

AuthV4.Helper.signIn은 PlayerID의 인증 토큰 키를 이용해 자동 로그인을 시도합니다. 기존에 로그인 했던 인증 토큰 키가 없다면 iOS인 경우 Apple Game Center에, Android인 경우 Google Play 게임에 자동으로 로그인합니다. 로그인을 실패하면 응답 값에 따라 적절한 로그인 화면을 구성합니다.

Note

자동 로그인을 사용하려면 반드시 Game Center Entitlement를 추가해야 합니다. 'Apple GameCenter' Dependency에 체크한 경우 Unity PostProcess를 통해 자동으로 해당 Entitlement를 추가합니다.

Note

AuthV4Helper 클래스를 사용할 때

  • 게임을 실행한 유저가 PGS 묵시적 로그인 시도 중 로그인을 거절한 경우, 이를 기억하고 더이상 묵시적 로그인을 시도하지 않습니다. 플레이어 세션이 유지되는 상태에서 자동 로그인이 가능하더라도 묵시적 로그인이 거절된 상태를 계속 기억합니다. 이 내용은 Google Play Games Services 가이드를 기반으로 작성하였습니다.

다음은 자동 로그인을 수행하는 예제 코드입니다.

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:    
                // 묵시적 로그인에 실패                   
                // ex) 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: 앱 종료 기능을 구현하세요
                // 예) UKismetSystemLibrary::QuitGame(GetWorld(), nullptr, EQuitPreference::Quit, false);
        } else {
                switch (Result.Code) {
                        case FHiveResultAPI::ECode::AuthV4ConflictPlayer:
                                // 계정 충돌
                                break;
                        case FHiveResultAPI::ECode::AuthV4HelperImplifiedLoginFail:
                                // 묵시적 로그인에 실패
                                // ex) FHiveAuthV4::ShowSigIn()
                                break;
                        default:
                                // 기타 예외 상황
                                break;
                }
        }
}));

API Reference: Auth4::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:    
                // 묵시적 로그인에 실패    
                // ex) AuthV4.showSignIn(...);    
                break;    
            default:    
                break;    
        }    
    }    
});

API Reference: hive.AuthV4.showSignIn

// 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: 앱 종료 기능을 구현하세요
                    // 예) exitProcess(0)
            } else {
                    when (result.code) {
                            ResultAPI.Code.AuthV4ConflictPlayer -> {
                                    // 계정 충돌
                            }
                            ResultAPI.Code.AuthV4HelperImplifiedLoginFail -> {
                                    // 묵시적 로그인에 실패
                                    // ex) AuthV4.showSignIn(...);
                            }
                            else -> {
                                    // 기타 예외 상황
                            }
                    }
            }
    }
    })

API Reference: 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 Reference: HIVEAuthV4:signIn

var email = String()    
    // Hive SDK AuthV4 인증 UI 요청    
    AuthV4Interface.showSignIn { (result, playerInfo) in    

    if result.isSuccess() {    
        // 인증 성공    
        // playerInfo: 인증된 사용자 정보    
        // 이메일 정보 조회 예시    
        if let playerInfo = playerInfo {    
            // providerEmail이 존재하는 providerInfo 탐색 (현재 로그인 진행된 provider)    
            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 Reference: HIVEAuthV4:signIn

// Hive SDK 로그인(signIn) 시도    
[[HIVEAuthV4 helper] signIn:^(HIVEResultAPI *result, HIVEPlayerInfo *playerInfo) {

        if (result.isSuccess) {
                // 로그인 성공 
        }
        else if (result.needExit) {
                // TODO: 앱 종료 기능을 구현하세요
                // 예) exit(0);
        }
        else {
                switch (result.code) {
                        case kAuthV4ConflictPlayer:
                                // 계정 충돌
                                break;    
                        case kAuthV4HelperImplifiedLoginFail:
                                // 묵시적 로그인에 실패
                                // ex) [HIVEAuthV4 showSignIn:^(HIVEResultAPI *result, HIVEPlayerInfo *playerInfo) {
                                // // do something...
                                // }];
                                break;
                        default:
                                // 기타 예외 상황
                                break;   
                }
        }
        }];

묵시적 로그인 동작: 모바일

모바일(Hive SDK Unity Android 등 Android/iOS 플랫폼) 묵시적 로그인(AuthV4.Helper.signIn)은 최초 로그인 후에 다른 계정으로 로그인할 경우, 계정 충돌 상황이 발생하고 마지막으로 로그인한 계정으로 로그인할 지 사용자에게 묻는 창을 띄웁니다.

묵시적 로그인 동작: PC

PC(Hive SDK Unity Windows 등 Windows 플랫폼) 묵시적 로그인(AuthV4.Helper.signIn)은 최초 로그인 후에 다른 계정으로 로그인할 경우, 마지막으로 로그인한 계정으로 자동으로 로그인합니다. 계정 충돌 상황은 발생하지 않습니다.

명시적 로그인

명시적 로그인이란 유저가 인증을 진행할 IdP를 선택하여 진행하는 것을 의미합니다. 자동 로그인과 묵시적 로그인 모두 실패했다면, 게임 타이틀 화면으로 이동한 후 타이틀에서 클릭했을 때 명시적 로그인을 수행하도록 구현하세요.

명시적 로그인 UI는 Hive SDK에서 제공하는 UI를 사용할 수도 있고 Hive SDK 초기화가 완료 후 결과로 반환되는 인증에 사용할 IdP 리스트를 이용하여 게임 자체 구현으로 커스터마이징 할 수 있습니다. UI를 커스터마이징 하는 경우 명시적 로그인 커스터마이징 항목을 참고하세요.

IdP 리스트는 각 국가의 정책에 따라 Hive 플랫폼에서 제어하여 제공됩니다. 예를 들어, 중국에서는 Google Play 게임 및 Facebook, 게스트가 제공되지 않습니다.

명시적 로그인 스크린샷

SDK에서 제공하는 IdP 선택 UI

SDK에서 제공하는 UI를 사용하여 구현하는 경우

SDK에서 제공하는 UI를 사용하여 명시적 로그인을 구현하기 위해서는 showSignIn() 메서드를 호출하여 IdP 리스트 UI를 간단히 호출할 수 있습니다.

Note

유저가 SDK에서 제공하는 IdP 선택 UI에서 'X'버튼을 눌러 닫은 경우, 다시 로그인 할 수 있는 수단을 제공해야 합니다. 아직 유저는 로그인 하지 않은 상태입니다.

Note

명시적 로그인을 커스터마이징하려면 다음을 참고하세요.

API Reference: 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: 앱 종료 기능을 구현하세요
        // 예) 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 Reference: 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 Reference: 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 Reference: 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 Reference: HIVEAuthV4:showSignIn

var email = String()

// Hive SDK AuthV4 인증 UI 요청
AuthV4Interface.showSignIn { (result, playerInfo) in

if result.isSuccess() {
        // 인증 성공
        // playerInfo: 인증된 사용자 정보

        // 이메일 정보 조회 예시
        if let playerInfo = playerInfo {
                // providerEmail이 존재하는 providerInfo 탐색 (현재 로그인 진행된 provider)
                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 Reference: HIVEAuthV4:showSignIn

__block NSString* email = @"";

// Hive SDK AuthV4 인증 UI 요청
[HIVEAuthV4 showSignIn:^(HIVEResultAPI *result, HIVEPlayerInfo *playerInfo) {

if([result isSuccess]){
        // 인증 성공
        // playerInfo: 인증된 사용자 정보

        // 이메일 정보 조회 예시
        if(playerInfo != nil) {
                // providerEmail이 존재하는 providerInfo 탐색 (현재 로그인 진행된 provider)
                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는 Hive SDK를 초기화할 목적으로 AuthV4.setup() 메서드를 호출하거나, 초기화 이후 AuthV4.Helper.getIDPList() 메서드를 호출했을 때 반환되는 응답 콜백 핸들러입니다. 게임 UI에 맞추어서 로그인 화면을 노출하거나 특정 IdP와의 연동만을 주로 노출하고 싶을 때 이 기능을 사용합니다. 커스터마이징 UI를 구현한 후에는 유저의 액션에 따라 원하는 ProviderType으로 signIn() 메서드를 호출해 로그인을 구현하세요.

Note
  • 로그인 화면에 Facebook 연동 버튼만 노출하는 UI 예시 스크린샷

다음은 커스터마이징한 명시적 로그인 UI에서 유저가 Google 로그인을 선택한 상황을 가정한 예제 소스입니다.

API Reference: 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 Reference: 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 Reference: 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 Reference: com.hive.Auth4.signIn

import com.hive.AuthV4;    
    import com.hive.ResultAPI;    
    AuthV4.INSTANCE.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 Reference: AuthV4Interface.signIn

import HIVEService    
    AuthV4Interface.signIn(.Google) { result, playerInfo in    
        if result.isSuccess() {    
            // 호출 성공    
            // playerInfo: 인증된 사용자 정보.    

            // .Google의 이메일 정보 조회 예시    
            if     
                let playerInfo = playerInfo,    
                let providerInfo = playerInfo.providerInfoData["GOOGLE"] {    
                    let email = providerInfo.providerEmail    
            }    
        }    
}

API Reference: 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계정과 실제 단말에 로그인한 IdP 계정(DevicePlayer)이 다를 수 있습니다. 추후 업적이나 리더보드 사용에 대비해 두 계정을 통일할 수 있도록 안내 문구를 제공합니다.

  • SDK가 제공하는 DevicePlayer 사용 여부 확인 UI

다음은 IdP 정보를 확인하는 예제 코드입니다.

API Reference: 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:    
                // 계정 충돌    
                // ex) Hive UI 사용시     
                // AuthV4.Helper.showConflict(...);    
                // or    
                // ex) 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:
                        // 계정 충돌
                        // ex) Hive UI 사용시
                        // FHiveAuthV4::Helper::ShowConflict()
                        // ex) Game UI 구현시
                        // FHiveAuthV4::Helper::ResolveConflict() // 현재 사용자 선택
                        // FHiveAuthV4::Helper::SwitchAccount() // 사용자 전환 선택
                        break;
                default:
                        // 기타 예외 상황
                        break;
        }
}));

API Reference: 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:    
            // 정상    
            break;    
          case ResultAPI::AuthV4ConflictPlayer:    
            // 계정 충돌    
            // ex) Hive UI 사용시     
            // AuthV4::Helper::showConflict(...);    
            // or    
            // ex) GameUI 구현시    
            // AuthV4::Helper::resolverConflict(...);// 현재 사용자 선택시    
            // AuthV4::Helper::switchAccount(...);// 사용자 전환 선택시    
            break;    
          default:    
            // 기타 예외 상황    
            break;    
         }        
});

API Reference: 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 -> {    
                    // 계정 충돌    
                    // ex) Hive UI 사용시    
                    // AuthV4.Helper.showConflict(...);    
                    // or    
                    // ex) GameUI 구현시    
                    // AuthV4.Helper.resolverConflict(...);// 현재 사용자 선택시    
                    // AuthV4.Helper.switchAccount(...);// 사용자 전환 선택시    
                }    
                else -> {    
                    // 기타 예외 상황    
                }    
            }    
        }    
})

API Reference: 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:    
                // 정상    
                break;    
            case AuthV4ConflictPlayer:    
                // 계정 충돌    
                // ex) Hive UI 사용시    
                // AuthV4.Helper.INSTANCE.showConflict(...);    
                // or    
                // ex) GameUI 구현시    
                // AuthV4.Helper.INSTANCE.resolverConflict(...);// 현재 사용자 선택시    
                // AuthV4.Helper.INSTANCE.switchAccount(...);// 사용자 전환 선택시    
                break;    
            default:    
                // 기타 예외 상황    
                break;    
        }    
});

API Reference: AuthV4Interface.helper().syncAccount

import HIVEService    
    let providerType: ProviderType = .Google    
    AuthV4Interface.helper().syncAccount(providerType) { result, playerInfo in    
        switch result.getCode() {    
          case .success:    
            // 정상    
          case .authV4ConflictPlayer:    
            // 계정 충돌    
            // ex) Hive UI 사용시     
            // AuthV4Interface.helper().showConflict(...);    
            // or    
            // ex) GameUI 구현시    
            // AuthV4Interface.helper().resolverConflict(...);// 현재 사용자 선택시    
            // AuthV4Interface.helper().switchAccount(...);// 사용자 전환 선택시    
          default:    
            // 기타 예외 상황    
            break    
        }      
}

API Reference: [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:    
                // 계정 충돌    
                // ex) Hive UI 사용시     
                // [[HIVEAuthV4 helper] showConflict: ...];    
                // or    
                // ex) GameUI 구현시    
                // [[HIVEAuthV4 helper] resolverConflict:...];// 현재 사용자 선택시    
                // [[HIVEAuthV4 helper] switchAccount:...];// 사용자 전환 선택시     
                break;    
            default:    
                // 기타 예외 상황    
                break;    
        }    
}];

게스트 로그인

유저가 IdP를 선택하지 않고 게스트 상태로 게임을 이용할 수 있도록 게스트 로그인 기능을 지원합니다. Hive SDK가 제공하는 명시적 로그인 UI에서 게스트를 선택할 수도 있고, 게임에서 커스터마이징하여 직접 구현하는 경우에도 게스트 로그인을 구현할 수 있습니다. Windows 환경은 게스트 로그인을 지원하지 않습니다.

게스트 로그인 시에는 다음의 정책을 반드시 준수해야 합니다.

게스트 로그인 정책

  • IdP 인증 유저와 게스트 유저 모두 게임을 동일하게 이용할 수 있게 구현하세요. 게스트 로그인 시에도 Hive 플랫폼의 기능 대부분을 이용할 수 있습니다. 때문에 여러분의 게임에서도 게스트로 로그인한 유저가 IdP 연동 유저와 동일하게 게임을 이용할 수 있도록 구현해 주세요. 예를 들면 게스트 유저도 게임 내에서 아이템을 구매하고 결제할 수 있어야 합니다.
    • 게스트 유저에게 로그아웃 기능을 제공하지 마세요. 유저가 게스트로 로그인 한 후 로그아웃하면 더 이상 동일한 PlayerID로 로그인이 불가합니다. 따라서 유저가 게스트로 로그인 했을 때는 로그아웃을 못하도록 로그아웃 버튼을 제공하지 마세요.
    • 중국 게스트 로그인 금지 정책 중국 IP를 사용할 경우에는 실명 인증된 유저만 재화를 충전·소비하는 서비스가 가능(17. 5. 1시행)하므로 중국 IP로 로그인할 수 있는 IdP 목록에 게스트 로그인이 포함되지 않습니다.

게스트 로그인을 수행하기 위해서는 ProviderType.GUEST를 파라미터로 signIn() 메서드를 호출하세요. 다음은 게스트 로그인을 수행하는 예제 코드입니다.

Note

아무 IdP인증이 없는 게스트 상태의 PlayerID는 playerInfo의 providerInfoData가 없습니다.

API Reference: hive.AuthV4.signIn

using hive;    
    AuthV4.signIn(AuthV4.ProviderType.GUEST, (ResultAPI result, AuthV4.PlayerInfo playerInfo) => {    
        if (result.isSuccess()) {    
            // 인증 성공    
            // playerInfo: 인증된 사용자 정보    
        }    
});
#include "HiveAuthV4.h"

FHiveAuthV4::SignIn(EHiveProviderType::GUEST,
                                        FHiveAuthV4OnSignInDelegate::CreateLambda([this](const FHiveResultAPI& Result, const FHivePlayerInfo& PlayerInfo) {

        if (Result.IsSuccess()) {
                // 호출 성공 (PlayerInfo: 인증된 사용자 정보)
        }
}));

API Reference: Auth4::signIn

#include <HIVE_SDK_Plugin/HIVE_CPP.h>    
    using namespace std;     
    using namespace hive;    
    AuthV4::signIn(ProviderType::GUEST, [=](ResultAPI const & result, PlayerInfo const & playerInfo) {    
        if (result.isSuccess()) {    
            // 인증 성공    
            // playerInfo: 인증된 사용자 정보    
        }    
});

API Reference: AuthV4.signIn

import com.hive.AuthV4    
    import com.hive.ResultAPI    
    AuthV4.signIn(AuthV4.ProviderType.GUEST, object : AuthV4.AuthV4SignInListener {    
        override fun onAuthV4SignIn(result: ResultAPI, playerInfo: AuthV4.PlayerInfo?) {    
            if (result.isSuccess) {    
                // 인증 성공    
                // playerInfo: 인증된 사용자 정보    
            }    
        }    
})

API Reference: com.hive.Auth4.signIn

import com.hive.AuthV4;    
    import com.hive.ResultAPI;    
    AuthV4.INSTANCE.signIn(AuthV4.ProviderType.GUEST, (result, playerInfo) -> {    
        if (result.isSuccess()) {    
            // 인증 성공    
            // playerInfo: 인증된 사용자 정보    
        }    
});

API Reference: AuthV4Interface.signIn

import HIVEService    
    AuthV4Interface.signIn(.Guest) { result, playerInfo in    
        if result.isSuccess() {    
            // 인증 성공    
            // playerInfo: 인증된 사용자 정보    
        }    
}

API Reference: HIVEAuth4:signIn

#import <HIVEService/HIVEService-Swift.h>    
    [HIVEAuthV4 signIn: HIVEProviderTypeGuest handler: ^(ResultAPI *result, HIVEPlayerInfo *playerInfo) {    
        if ([result isSuccess]) {    
            // 인증 성공    
            // playerInfo: 인증된 사용자 정보    
        }    
}];

커스텀 로그인

커스텀 로그인맞춤형 로그인 기능으로, Hive에서 제공하는 IdP 외에 게임 자체에서 연동하는 IdP로 로그인을 구현할 수 있습니다. 인증 v4 커스텀 인증하기에 따라 커스텀 로그인 API 호출 시 사용할 인증 키(authKey)를 생성해 보세요.

커스텀 로그인 API 호출 후 콜백으로 전달 받는 PlayerInfo 클래스 인스턴스로 customProviderInfoData 데이터에 접근하여 커스텀 로그인된 유저 정보를 확인할 수 있습니다. customProviderInfoDataProviderType(enum) 은 모두 CUSTOM으로 동일하게 설정되며, ProviderName(String) 으로 상세히 구분할 수 있습니다.

게임에서 커스텀 로그인을 구현한 IdP의 정보는 AuthV4 클래스의 setup()showSignIn() 메서드 호출 결과에 포함되지 않습니다.

커스텀 로그인 최초 실행 후 playerId>와 playerToke을 발급받았다면, 커스텀 로그인 API 재호출 시 authV4SessionExist(code)의 Result API가 콜백으로 전달됩니다. 이 경우에는 ProviderType.Auto를 파라미터로 signIn()를 호출하여 기존에 로그인된 계정으로 자동 로그인을 진행해야 합니다. 아래의 예제 코드를 참조하세요.

AuthV4 클래스의 connect()disconnect() 메서드는 커스텀 로그인 IdP의 추가 연동 및 해제를 지원하지 않습니다. connectWithAuthKey()disconnectWithName() 메서드로 커스텀 로그인 IdP의 추가 연동 및 해제를 지원합니다.

커스텀 로그인을 구현하는 예제코드입니다.

API Reference: hive.AuthV4.signIn

// 게임에서 직접 구현한 트위터 로그인    
    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, 커스텀들은 Type 이 고정이니 providerName 으로 구분 필요    
            providerInfo.providerName;   // "CUSTOM_TWITTER"    
            providerInfo.providerUserId;  // 직접 구현한 트위터 로그인에 사용된 사용자 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" 타입으로 직접 구현한 트위터 로그인
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, 커스텀들은 Type 이 고정
                                FString ProviderName = ProviderInfo->ProviderName; // ProviderName으로 구분 필요
                                FString ProviderUserId = ProviderInfo->ProviderUserId; // 직접 구현한 트위터 로그인에 사용된 사용자 id
                        }
                } else if (Result.NeedExit()) {
                        // TODO: 앱 종료 기능을 구현하세요
                        // 예) 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 Reference: Auth4::signIn

using namespace std;    
    using namespace hive;    
    // 게임에서 직접 구현한 트위터 로그인    
    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, 커스텀들은 Type 이 고정이니 providerName 으로 구분 필요    
            providerInfo.providerName; // "CUSTOM_TWITTER"    
            providerInfo.providerUserId; // 직접 구현한 트위터 로그인에 사용된 사용자 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 엔진 사용자    
            // 예) exit(0);    
            // Unreal 엔진 사용자    
            // 예) UKismetSystemLibrary::QuitGame(GetWorld(), nullptr, EQuitPreference::Quit, false);      
        }    
    });    
});

API Reference: com.hive.Auth4.signIn

// 게임에서 직접 구현한 트위터 로그인
    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, 커스텀들은 Type 이 고정이니 providerName 으로 구분 필요
                                    providerInfo.providerName   // "CUSTOM_TWITTER"
                                    providerInfo.providerUserId // 직접 구현한 트위터 로그인에 사용된 사용자 id
                            }
                    }
                    else if (result.needExit()) {
                            // TODO: 앱 종료 기능을 구현하세요
                            // 예) 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 Reference: com.hive.Auth4.signIn

// 게임에서 직접 구현한 트위터 로그인
    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, 커스텀들은 Type 고정이니 providerName 으로 구분 필요
                                            providerInfo.getProviderName(); // "CUSTOM_TWITTER"
                                            providerInfo.getProviderUserId(); // 직접 구현한 트위터 로그인에 사용된 사용자 id
                                    }
                            } else if (result.needExit()) {
                                    // TODO: 앱 종료 기능을 구현하세요
                                    // 예) 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 Reference: HIVEAuth4:signIn

// 게임에서 직접 구현한 트위터 로그인
    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;   // 직접 구현한 트위터 로그인에 사용된 사용자 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 Reference: HIVEAuth4:signIn

// 게임에서 직접 구현한 트위터 로그인
    [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, 커스텀들은 Type 이 고정이니 providerName 으로 구분 필요
                            providerInfo.providerName;   // "CUSTOM_TWITTER"
                            providerInfo.providerUserId;  // 직접 구현한 트위터 로그인에 사용된 사용자 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 연동 시 1회만 노출되며 그 외에는 노출되지 않습니다.
  • 게스트 로그인 시에는 유저네임 입력화면이 노출되지 않습니다.

인증 토큰 키 유효성 검증

게임 서버에서는 로그인 성공 후 반환 된 Token, playerId, DID 정보를 이용하여 인증 토큰키의 유효성을 검증할 수 있습니다. Hive 인증에서는 멀티 디바이스 로그인과 중복 접속을 허용합니다.

동일한 계정으로 중복 접속을 허용하지 않을 경우, 게임 서버는 먼저 접속한 기기에 안내 메시지를 노출시킨 후 게임을 종료하고 나중에 접속한 기기에서 게임이 유지되도록 처리합니다. 이때 게임을 종료하지 않은 채 중복 접속할 경우 게임 플레이 기록이 정상적으로 반영되지 않을 수 있습니다. 해당 기능을 구현하려면 검증을 완료한 토큰 키를 관리하거나 이를 이용한 게임 자체의 세션 키를 관리하여 처리해야 합니다.

해당 기능은 인증 토큰키 유효성 검증 Server API를 참고하여 구현하세요.

톡플러스 로그인 토큰 획득

인증 v4 인터페이스를 통해 signIn() 완료 후 AuthV4.getHiveTalkPlusLoginToken API를 호출하여 획득한 로그인 토큰을 Hive 톡플러스 로그인 시 사용합니다.

Note

관련 가이드로 Hive 톡플러스 로그인 가이드를 참고하세요.

AuthV4.getHiveTalkPlusLoginToken((ResultAPI result, String loginToken) =&gt; {
if (result.isSuccess()) {
    // SUCCESS
    // TODO: 전달받은 loginToken 값 확인 후 HiveTalkPlus 로그인 진행
}
});
// Kotlin
AuthV4.getHiveTalkPlusLoginToken(object : AuthV4.AuthV4GetHiveTalkPlusLoginTokenListener {
        override fun onAuthV4GetHiveTalkPlusLoginToken(resultApi: ResultAPI, loginToken: String?) {
                if (resultApi.isSuccess) {
                        // SUCCESS
                }
        }
}
// Java
com.hive.AuthV4.INSTANCE.getHiveTalkPlusLoginToken(new com.hive.AuthV4.AuthV4GetHiveTalkPlusLoginTokenListener() {
        @Override
        public void onAuthV4GetHiveTalkPlusLoginToken(@NotNull ResultAPI result, @Nullable String loginToken) {
if (result.isSuccess()) {
// SUCCESS
}
        }
});
// Swift
AuthV4Interface.getHiveTalkPlusLoginToken { result, loginToken in
        if (result.isSuccess()) {
                // SUCCESS
        }
}
// Objective-c
[HIVEAuthV4 getHiveTalkplusLoginToken:^(HIVEResultAPI* result, NSString* loginToken) {
        if ([result isSuccess]) {
                // SUCCESS
        }
}];

백그라운드에서 IdP 계정 변경 감지

유저가 게임 실행 중에 기기 설정으로 이동하여 Apple Game Center 또는 Google Play 게임 계정을 변경할 수 있습니다. 게임 실행 중에 IdP 계정이 현재 PlayerID에 IdP 계정과 다른지 여부를 확인해야 하는 경우 setProviderChangedListener()를 SDK 초기화 이후 호출하세요. 해당 API를 호출하면 게임 Resume시 기기에 설정된 IdP계정이 변경되었다는 이벤트를 받을 수 있습니다.

iOS는 Apple Game Center, Android는 Google Play 게임의 계정이 변경 시에 동작하며 현재 로그인 된 PlayerID가 해당 IdP에 연동되어 있을 경우에만 응답이 전달됩니다. IdP 계정 변경 이벤트를 받을 경우, 유저에게 기기에 로그인된 IdP 계정을 사용할지 여부를 유저에게 선택할 수 있도록 UI를 구성합니다. 유저가 기기에 로그인된 IdP 계정을 선택하면, signOut을 호출하여 로그아웃 시킨 후, 묵시적 로그인을 진행합니다.

Warning

2021년 7월 이후 출시된 Google Play 게임을 설치한 단말은 Google Play 게임의 동작상 이슈로 인해 백그라운드에서 IdP 계정을 변경할 수 없습니다.

Note

이 기능으로 게임 플레이가 중단되고 계정을 변경하라는 요청이 발생할 수 있으며, 로비 진입이나 상점 진입 같이 계정 동기화가 필요한 시점에만 제한적으로 사용할 수 있습니다.

다음은 유저가 게임을 다시 시작했을 때, 기기에 설정된 IdP 계정이 변경되었다는 이벤트를 받도록 설정하는 예제 코드입니다.

API Reference: hive.AuthV4.setProviderChangedListener

using hive;

AuthV4.setProviderChangedListener((ResultAPI result, AuthV4.ProviderInfo providerInfo) => {
    if (!result.isSuccess()) {
        return;
    }

        if (providerInfo != null && providerInfo.providerType == AuthV4.ProviderType.APPLE) {
                // GameCenter 사용자 정보 변경
        }
});
#include "HiveAuthV4.h"

FHiveAuthV4::SetProviderChangedListener(FHiveAuthV4OnCheckProviderDelegate::CreateLambda([this](const FHiveResultAPI& Result, const FHiveProviderInfo& ProviderInfo) {
        if (Result.IsSuccess()) {
                // 호출 성공. ProviderInfo 객체를 통해 변경된 사용자 정보 확인
        }
}));

API Reference: 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 Game Service 계정 변경
    }
});

API Reference: 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 Game Service 계정 변경
                }
        }
})

API Reference: com.hive.AuthV4.setProviderChangedListener

import com.hive.AuthV4;
import com.hive.ResultAPI;

AuthV4.INSTANCE.setProviderChangedListener((result, providerInfo) -> {
        if (!result.isSuccess()) {
                return;
        }

        if (providerInfo != null && providerInfo.getProviderType() == AuthV4.ProviderType.GOOGLE) {
                // Google Play Game Service 계정 변경
        }
});

API Reference: AuthV4Interface.setProviderChangedListener

import HIVEService

AuthV4Interface.setProviderChangedListener() { result, providerInfo in 
    if !result.isSuccess() {
        return
    }

    if let providerInfo = providerInfo, providerInfo.providerType == .Apple {
        // GameCenter 사용자 정보 변경
    }
}

API Reference: HIVEAuthV4:setProviderChangedListener

#import <HIVEService/HIVEService-Swift.h>

[HIVEAuthV4 setProviderChangedListener: ^(HIVEResultAPI *result, ProviderInfo *providerInfo) {
    if (![result isSuccess]) {
        return;
    }

    if (providerInfo != nil && providerInfo.providerType == HIVEProviderTypeApple) {
        // GameCenter 사용자 정보 변경
    }
}];

게임 데이터 초기화

게임 데이터를 초기화할 때 로그아웃을 호출하지 마세요. PlayerID가 삭제되지 않기 때문에 계정간 충돌이 발생할 수 있습니다. 현재 로그인한 계정으로 계속 플레이할 수 있어야 하므로 유저가 명시적으로 요청하기 전에는 로그아웃을 호출하지 않도록 구현하세요.

로그아웃

Warning
  • Logout 동작시 인증 정보인 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 Reference: hive.AuthV4.signOut

using hive;    

    AuthV4.Helper.signOut (delegate (ResultAPI result, AuthV4.PlayerInfo playerInfo) {    
        switch(result.code) {    
            case ResultAPI.Code.Success:    
                // 로그아웃 성공    
                break;    
            default:    
                // 기타 예외 상황    
                break;    
        }    
});
#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 Reference: AuthV4::signOut

#include <HIVE_SDK_Plugin/HIVE_CPP.h>    
    using namespace std;    
    using namespace hive;    

    AuthV4::Helper::signOut([=](ResultAPI const & result, shared_ptr playerInfo) {    
        switch (result.code) {    
            case ResultAPI::Success:    
                // 로그아웃 성공    
                break;    
            default:    
                // 기타 예외 상황    
                break;    
        }    
});

API Reference: AuthV4.Helper.signOut

import com.hive.AuthV4
import com.hive.ResultAPI

AuthV4.Helper.signOut(object : AuthV4.Helper.AuthV4HelperListener {
        override fun onAuthV4Helper(result: ResultAPI, playerInfo: AuthV4.PlayerInfo?) {
                when (result.code) {
                        ResultAPI.Code.Success -> {
                                // 로그아웃 성공
                        }
                        else -> {
                                // 기타 예외 상황
                        }
                }
        }
})

API Reference: AuthV4.Helper.INSTANCE.signOut

import com.hive.AuthV4;
import com.hive.ResultAPI;

AuthV4.Helper.INSTANCE.signOut((result, playerInfo) -> {
        switch (result.getCode()) {
                case Success:
                        // 로그아웃 성공
                        break;
                default:
                        // 기타 예외 상황
                        break;
        }
});

API Reference: AuthV4Interface.helper().signOut()

import HIVEService

AuthV4Interface.helper().signOut() { result, playerInfo in
        switch result.getCode() {
                case .success:
                        // 로그아웃 성공
                default:
                        // 기타 예외 상황
                        break
        }}

API Reference: [HIVEAuthV4 helper] signOut

#import <HIVEService/HIVEService-Swift.h>

[[HIVEAuthV4 helper] signOut: ^(HIVEResultAPI *result, HIVEPlayerInfo *playerInfo) {
        switch ([result getCode]) {
                case HIVEResultAPICodeSuccess:
                        // 로그인 성공
                        break;
                default:
                        // 기타 예외 상황
                        break;
        }
}];

Game Center 취소 안내 문구

언어 문구
한국어 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.
아랍어 تم إلغاء تسجيل الدخول إلى مركز الألعاب.
سجل الدخول إلى [الإعدادات> مركز الألعاب] للمزامنة مع حساب مركز الألعاب وحاول مرة أخرى.