콘솔로 이동

C++로 Google Play 게임 서비스를 사용하여 인증하기

Google Play 게임 서비스를 사용하여 Firebase를 기반으로 C++으로 개발된 Android 게임에 플레이어가 로그인하도록 할 수 있습니다. Firebase를 통한 Google Play 게임 서비스 로그인을 사용하려면 우선 Google Play 게임에 플레이어를 로그인 처리하면서 OAuth 2.0 인증 코드를 요청합니다. 그런 다음 PlayGamesAuthProvider에 인증 코드를 전달하여 Firebase 사용자 인증 정보를 생성합니다. 이 인증 정보를 사용하여 Firebase에 인증할 수 있습니다.

시작하기 전에

Android NDK 프로젝트에 Firebase 추가

Firebase C++ SDK 설정 가이드의 Android 설정 단계에 따라 Android NDK 프로젝트에 Firebase를 추가합니다.

프로젝트의 원본 코드 작성 파일에 Firebase C++ SDK를 포함합니다.

CMake

상위 수준 CMakeLists.txt 파일:

set(FIREBASE_CPP_SDK_DIR "/path/to/firebase_cpp_sdk")
string(REGEX REPLACE "(.*)_.*" "\\1" STL ${ANDROID_STL})

add_library(firebase_app STATIC IMPORTED)
set_target_properties(firebase_app PROPERTIES IMPORTED_LOCATION
    ${FIREBASE_CPP_SDK_DIR}/libs/android/${ANDROID_ABI}/${STL}/libapp.a)

add_library(firebase_auth STATIC IMPORTED)
set_target_properties(firebase_auth PROPERTIES IMPORTED_LOCATION
    ${FIREBASE_CPP_SDK_DIR}/libs/android/${ANDROID_ABI}/${STL}/libauth.a)

...

target_link_libraries(
    ...
    firebase_app
    firebase_auth)

ndk-build

Android.mk 파일:

STL := $(firstword $(subst _, ,$(APP_STL)))
FIREBASE_CPP_SDK_DIR := /path/to/frebase_cpp_sdk
FIREBASE_LIBRARY_PATH := \
    $(FIREBASE_CPP_SDK_DIR)/libs/android/$(TARGET_ARCH_ABI)/$(STL)

include $(CLEAR_VARS)
LOCAL_MODULE := firebase_app
LOCAL_SRC_FILES := $(FIREBASE_LIBRARY_PATH)/libapp.a
LOCAL_EXPORT_C_INCLUDES := $(FIREBASE_CPP_SDK_DIR)/include
include $(PREBUILT_STATIC_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE := firebase_auth
LOCAL_SRC_FILES := $(FIREBASE_LIBRARY_PATH)/libauth.a
LOCAL_EXPORT_C_INCLUDES := $(FIREBASE_CPP_SDK_DIR)/include
include $(PREBUILT_STATIC_LIBRARY)

모듈 수준 build.gradle 파일에서 Firebase를 종속 항목으로 선언합니다.

dependencies {
    implementation 'com.google.firebase:firebase-auth:16.0.4'
    implementation 'com.google.android.gms:play-services-base:16.0.1'
    implementation 'com.google.android.gms:play-services-auth:16.0.1'
}

Firebase 프로젝트 설정

  1. Firebase 콘솔의 설정 페이지에서 게임의 SHA-1 지문을 설정합니다.

    keytool 명령어로 키의 SHA-1 지문을 가져올 수 있습니다.

    keytool -exportcert -list -v \
        -alias YOUR-KEY-NAME -keystore PATH-TO-KEYSTORE

  2. Google Play 게임을 로그인 제공업체로 사용 설정합니다.

    1. 프로젝트의 웹 서버 클라이언트 ID와 클라이언트 보안 비밀을 찾습니다. 웹 서버 클라이언트 ID는 Google Play 인증 서버에 대해 Firebase 프로젝트를 식별합니다.

      이 값을 확인하는 방법은 다음과 같습니다.

      1. Google API 콘솔 사용자 인증 정보 페이지에서 Firebase 프로젝트를 엽니다.
      2. OAuth 2.0 클라이언트 ID 섹션에서 웹 클라이언트(Google 서비스에서 자동 생성) 세부정보 페이지를 엽니다. 이 페이지에 웹 서버 클라이언트 ID와 보안 비밀이 표시됩니다.
    2. 그런 다음 Firebase 콘솔에서 인증 섹션을 엽니다.

    3. 로그인 방법 탭에서 Play 게임 로그인 제공업체를 사용 설정합니다. API 콘솔에서 가져온 프로젝트의 웹 서버 클라이언트 ID와 클라이언트 보안 비밀을 지정해야 합니다.

  1. Google Play Console을 열고 게임 서비스를 클릭합니다.
  2. 새 게임 추가를 클릭합니다. 새 게임 대화상자에서 게임에서 이미 Google API를 사용하고 있습니다를 클릭하고 목록에서 Firebase 프로젝트의 이름을 클릭합니다. 게임 카테고리를 선택한 다음 계속을 클릭하여 게임 세부정보 페이지로 이동합니다.
  3. 게임 세부정보 페이지의 끝에서 모든 필수 API가 사용 설정되어 있는지 확인합니다.
  4. 그런 다음 연결된 앱 페이지를 열고 Android를 클릭합니다. 게임의 패키지 이름을 지정하고 저장 후 계속을 클릭합니다. 콘솔에 Android 클라이언트 ID가 표시됩니다. 이 값은 무시해도 됩니다.
  5. Play 스토어에 게임을 출시하기 전에 테스트 페이지에서 게임에 로그인해야 하는 사용자의 이메일 주소를 허용 목록에 추가합니다.

게임에 Play 게임 로그인 통합

Google Play 게임 로그인을 통합해야 플레이어가 게임에 로그인할 수 있습니다.

Google Sign-in C++ SDK를 사용하면 C++ Android 프로젝트에 Play 게임 로그인 지원을 간편하게 추가할 수 있으며 이 방법이 권장됩니다.

Google Sign-in C++ SDK를 사용하여 게임에 Play 게임 로그인을 추가하려면 다음을 진행합니다.

  1. C++ SDK도 포함된 Google Sign-in Unity 플러그인 저장소를 복제하거나 다운로드합니다.

  2. Android 스튜디오나 gradlew build를 사용하여 staging/native/ 디렉토리에 포함된 프로젝트를 빌드합니다.

    빌드가 google-signin-cpp라는 디렉토리에 출력을 복사합니다.

  3. 게임의 기본 코드 작성 파일에 Google Sign-in C++ SDK를 포함합니다.

    CMake

    상위 수준 CMakeLists.txt 파일:

    set(GSI_PACKAGE_DIR "/path/to/google-signin-cpp")
    add_library(lib-google-signin-cpp STATIC IMPORTED) set_target_properties(lib-google-signin-cpp PROPERTIES IMPORTED_LOCATION     ${GSI_PACKAGE_DIR}/lib/${ANDROID_ABI}/libgoogle-signin-cpp.a )
    ...
    target_link_libraries(     ...     lib-google-signin-cpp)

    ndk-build

    Android.mk 파일:

    include $(CLEAR_VARS)
    LOCAL_MODULE := google-signin-cpp
    GSI_SDK_DIR := /path/to/google-signin-cpp
    LOCAL_SRC_FILES := $(GSI_SDK_DIR)/lib/$(TARGET_ARCH_ABI)/libgoogle-signin-cpp.a
    LOCAL_EXPORT_C_INCLUDES := $(GSI_SDK_DIR)/include
    include $(PREBUILT_STATIC_LIBRARY)
    

  4. 다음으로 C++ SDK에 필요한 자바 헬퍼 구성요소를 포함합니다.

    이렇게 하려면 프로젝트 수준의 build.gradle 파일에 로컬 저장소로 SDK 빌드 출력 디렉토리를 추가합니다.

    allprojects {
        repositories {
            // ...
            flatDir {
                dirs 'path/to/google-signin-cpp'
            }
        }
    }
    

    또한 모듈 수준의 build.gradle 파일에서 헬퍼 구성요소를 종속 항목으로 선언합니다.

    dependencies {
        implementation 'com.google.android.gms:play-services-auth:16.0.1'
        // Depend on the AAR built with the Google Sign-in SDK in order to add
        // the Java helper classes, which are used by the C++ library.
        compile(name:'google-signin-cpp-release', ext:'aar')
    }
    
  5. 그런 다음 게임에서 Play 게임 로그인을 사용하고 서버 인증 코드를 가져오도록 GoogleSignIn 객체를 구성합니다.

    #include "google_signin.h"
    #include "future.h"
    
    using namespace google::signin;
    
    // ...
    
    GoogleSignIn::Configuration config = {};
    config.web_client_id = "YOUR_WEB_CLIENT_ID_HERE";
    config.request_id_token = false;
    config.use_game_signin = true;
    config.request_auth_code = true;
    
    GoogleSignIn gsi = GoogleSignIn(GetActivity(), GetJavaVM());
    gsi.Configure(config);
    
  6. 마지막으로 SignIn()을 호출하여 Play 게임에서 사용자를 로그인 처리합니다.

    Future<GoogleSignIn::SignInResult> &future = gsi.SignIn();
    

    SignIn()로 반환된 Future가 확인되면 결과에서 서버 인증 코드를 가져올 수 있습니다.

    if (!future.Pending()) {
        const GoogleSignIn::StatusCode status =
                static_cast<GoogleSignIn::StatusCode>(future.Status());
        if (status == GoogleSignIn::kStatusCodeSuccess) {
            // Player successfully signed in to Google Play! Get auth code to
            //   pass to Firebase
            const GoogleSignIn::SignInResult result =
                    static_cast<GoogleSignIn::SignInResult>(future.Result());
            const char* server_auth_code = result.User.GetServerAuthCode();
        }
    }
    

Firebase로 인증하기

플레이어가 Play 게임에 로그인한 후 인증 코드를 사용하여 Firebase에 인증할 수 있습니다.

  1. 플레이어가 Play 게임으로 로그인한 후 플레이어 계정의 인증 코드를 가져옵니다.

  2. 그런 다음 Play 게임 서비스의 인증 코드를 Firebase 사용자 인증 정보로 교환하고, Firebase 사용자 인증 정보를 사용하여 플레이어를 인증합니다.

    firebase::auth::Credential credential =
        firebase::auth::PlayGamesAuthProvider::GetCredential(server_auth_code);
    firebase::Future<firebase::auth::User*> result =
        auth->SignInWithCredential(credential);
    
  3. 프로그램에 정기적으로 실행되는 업데이트 루프(예: 초당 30회 또는 60회)가 있는 경우 다음과 같이 Auth::SignInWithCredentialLastResult를 사용해 업데이트 시마다 한 번씩 결과를 확인할 수 있습니다.

    firebase::Future<firebase::auth::User*> result =
        auth->SignInWithCredentialLastResult();
    if (result.status() == firebase::kFutureStatusComplete) {
      if (result.error() == firebase::auth::kAuthErrorNone) {
        firebase::auth::User* user = *result.result();
        printf("Sign in succeeded for `%s`\n", user->display_name().c_str());
      } else {
        printf("Sign in failed with error '%s'\n", result.error_message());
      }
    }

    또는 프로그램이 이벤트 기반이라면 Future에 콜백을 등록하는 것이 나을 수도 있습니다.

Future에 콜백 등록하기

일부 프로그램에는 초당 30회 또는 60회 호출되는 Update 함수가 있습니다. 예를 들면 상당수의 게임들이 이 모델을 따릅니다. 이런 프로그램은 LastResult 함수를 호출하여 비동기 호출에 대해 폴링을 수행합니다. 하지만 프로그램이 이벤트 기반일 경우 콜백 함수를 등록하는 것이 나을 수도 있습니다. 콜백 함수는 Future 완료 시에 호출됩니다.
void OnCreateCallback(const firebase::Future<firebase::auth::User*>& result,
                      void* user_data) {
  // The callback is called when the Future enters the `complete` state.
  assert(result.status() == firebase::kFutureStatusComplete);

  // Use `user_data` to pass-in program context, if you like.
  MyProgramContext* program_context = static_cast<MyProgramContext*>(user_data);

  // Important to handle both success and failure situations.
  if (result.error() == firebase::auth::kAuthErrorNone) {
    firebase::auth::User* user = *result.result();
    printf("Create user succeeded for email %s\n", user->email().c_str());

    // Perform other actions on User, if you like.
    firebase::auth::User::UserProfile profile;
    profile.display_name = program_context->display_name;
    user->UpdateUserProfile(profile);

  } else {
    printf("Created user failed with error '%s'\n", result.error_message());
  }
}

void CreateUser(firebase::auth::Auth* auth) {
  // Callbacks work the same for any firebase::Future.
  firebase::Future<firebase::auth::User*> result =
      auth->CreateUserWithEmailAndPasswordLastResult();

  // `&my_program_context` is passed verbatim to OnCreateCallback().
  result.OnCompletion(OnCreateCallback, &my_program_context);
}
원한다면 콜백 함수는 람다 함수도 가능합니다.
void CreateUserUsingLambda(firebase::auth::Auth* auth) {
  // Callbacks work the same for any firebase::Future.
  firebase::Future<firebase::auth::User*> result =
      auth->CreateUserWithEmailAndPasswordLastResult();

  // The lambda has the same signature as the callback function.
  result.OnCompletion(
      [](const firebase::Future<firebase::auth::User*>& result,
         void* user_data) {
        // `user_data` is the same as &my_program_context, below.
        // Note that we can't capture this value in the [] because std::function
        // is not supported by our minimum compiler spec (which is pre C++11).
        MyProgramContext* program_context =
            static_cast<MyProgramContext*>(user_data);

        // Process create user result...
        (void)program_context;
      },
      &my_program_context);
}

다음 단계

사용자가 처음으로 로그인하면 신규 사용자 계정이 생성되어 사용자의 Play 게임 ID에 연결됩니다. 이 신규 계정은 Firebase 프로젝트의 일부로서 저장되며 프로젝트의 모든 앱에서 사용자 본인 확인에 사용할 수 있습니다.

게임에서 firebase::auth::User 객체로부터 사용자의 Firebase UID를 가져올 수 있습니다.

firebase::auth::User* user = auth->current_user();
if (user != nullptr) {
  std::string playerName = user->displayName();

  // The user's ID, unique to the Firebase project.
  // Do NOT use this value to authenticate with your backend server,
  // if you have one. Use firebase::auth::User::Token() instead.
  std::string uid = user->uid();
}

Firebase 실시간 데이터베이스 및 Cloud Storage 보안 규칙에서 auth 변수로부터 로그인한 사용자의 고유 사용자 ID를 가져온 후 이 ID를 통해 사용자의 데이터 액세스를 관리할 수 있습니다.

사용자의 Play 게임 플레이어 정보를 가져오거나 Play 게임 서비스에 액세스하려면 Google Play 게임 서비스 C++ SDK에서 제공하는 API를 사용하세요.

사용자를 로그아웃시키려면 다음과 같이 SignOut()을 호출합니다.

auth->SignOut();