Xác thực bằng Dịch vụ trò chơi của Google Play với C++

Bạn có thể sử dụng dịch vụ trò chơi của Google Play để đăng nhập người chơi vào trò chơi Android được tạo dựa trên Firebase và được viết bằng C++. Cách đăng nhập bằng dịch vụ trò chơi của Google Play bằng Firebase, trước tiên, hãy đăng nhập người chơi bằng Google Play Games rồi yêu cầu một Mã xác thực OAuth 2.0 khi bạn làm vậy. Sau đó, chuyển mã uỷ quyền cho PlayGamesAuthProvider để tạo thông tin đăng nhập Firebase mà bạn có thể sử dụng để xác thực bằng Firebase.

Trước khi bắt đầu

Trước khi bạn có thể sử dụng Firebase Authentication! bạn cần:

  • Đăng ký dự án C++ của bạn và định cấu hình dự án đó để sử dụng Firebase.

    Nếu dự án C++ của bạn đã sử dụng Firebase, có nghĩa là dự án đó đã được đăng ký và được định cấu hình cho Firebase.

  • Thêm SDK C++ Firebase vào dự án C++.

Lưu ý rằng việc thêm Firebase vào dự án C++ bao gồm các tác vụ trong cả Bảng điều khiển Firebase và trong dự án C++ đang mở của bạn (ví dụ: bạn tải xuống Tệp cấu hình Firebase từ bảng điều khiển, sau đó di chuyển các tệp đó vào dự án C++).

Thiết lập dự án Firebase

  1. Đặt vân tay SHA-1 của trò chơi trong Trang Cài đặt của bảng điều khiển Firebase.

    Bạn có thể lấy hàm băm SHA của chứng chỉ ký bằng gradle Lệnh signingReport:

    ./gradlew signingReport

  2. Cho phép Google Play Games làm nhà cung cấp dịch vụ đăng nhập:

    1. Trong bảng điều khiển Firebase, hãy mở Authentication.

    2. Tạo và lấy mã ứng dụng khách và ứng dụng khách của máy chủ web cho dự án của bạn bí mật:

      1. Trong thẻ Phương thức đăng nhập, hãy bật tính năng đăng nhập của Google Google Cloud.

      2. Sao chép mã ứng dụng khách của máy chủ web và mã bí mật trong phiên đăng nhập bằng Google Google Cloud.

    3. Trong thẻ Phương thức đăng nhập, hãy bật Play Games nhà cung cấp dịch vụ đăng nhập và chỉ định mã ứng dụng khách của máy chủ web của dự án và mật khẩu ứng dụng khách mà bạn nhận được ở bước cuối cùng.

Định cấu hình Play Games services bằng thông tin ứng dụng Firebase của bạn

  1. Trong Bảng điều khiển Google Play, hãy mở ứng dụng Google Play của bạn hoặc tạo một ứng dụng.

  2. Trong phần Phát triển, hãy nhấp vào Play Games services > Thiết lập và Quản lý > Cấu hình.

  3. Nhấp vào Có, trò chơi của tôi đã sử dụng API của Google, hãy chọn Firebase dự án từ danh sách, rồi nhấp vào Use (Sử dụng).

  4. Trên trang cấu hình Play Games services, hãy nhấp vào Thêm thông tin xác thực.

    1. Chọn loại Máy chủ trò chơi.
    2. Trong trường ứng dụng OAuth, hãy chọn mã ứng dụng web của dự án. Hãy đảm bảo đây chính là ID ứng dụng khách bạn đã chỉ định khi bật Đăng nhập Play Games.
    3. Lưu thay đổi.
  5. Vẫn trên trang cấu hình Play Games services, nhấp vào Thêm lại thông tin xác thực.

    1. Chọn loại Android.
    2. Trong trường ứng dụng OAuth, hãy chọn mã ứng dụng khách Android của dự án. (Nếu bạn không thấy ID ứng dụng khách Android của mình, hãy đảm bảo bạn đã đặt Vân tay số SHA-1 trong bảng điều khiển Firebase.)
    3. Lưu thay đổi.
  6. Trên trang Nhân viên kiểm thử, hãy thêm địa chỉ email của tất cả những người dùng cần đăng nhập vào trò chơi của bạn trước khi phát hành trên Play Store.

Tích hợp tính năng đăng nhập trên Play Games vào trò chơi của bạn

Trước khi có thể đăng nhập người chơi vào trò chơi, bạn phải tích hợp Google Play Đăng nhập vào trò chơi.

Cách dễ nhất và nên dùng để thêm tính năng hỗ trợ đăng nhập vào Play Games vào C++ Dự án Android sử dụng SDK C++ đăng nhập bằng Google.

Để thêm tính năng đăng nhập vào Play Games vào trò chơi của bạn bằng SDK C++ dành cho đăng nhập bằng Google, hãy làm như sau sau:

  1. Sao chép hoặc tải kho lưu trữ trình bổ trợ Unity đăng nhập bằng Google xuống, SDK này cũng chứa SDK C++.

  2. Tạo dự án có trong thư mục staging/native/, sử dụng Android Studio hoặc gradlew build.

    Bản dựng sẽ sao chép dữ liệu đầu ra vào một thư mục có tên là google-signin-cpp.

  3. Đưa SDK C++ đăng nhập bằng Google vào tệp tạo mã gốc của trò chơi:

    CMake

    Trong tệp CMakeLists.txt cấp cao nhất:

    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)

    Bản dựng ndk

    Trong tệp 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. Tiếp theo, hãy thêm thành phần trình trợ giúp Java mà SDK C++ yêu cầu.

    Để thực hiện việc này, trong tệp build.gradle cấp dự án, hãy thêm bản dựng SDK thư mục đầu ra làm kho lưu trữ cục bộ:

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

    Đồng thời, trong tệp build.gradle cấp mô-đun, hãy khai báo thành phần trợ giúp dưới dạng phần phụ thuộc:

    dependencies {
        implementation 'com.google.android.gms:play-services-auth:21.2.0'
        // 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. Sau đó, trong trò chơi của bạn, hãy định cấu hình đối tượng GoogleSignIn để sử dụng Play Games đăng nhập và truy xuất mã xác thực máy chủ:

    #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. Cuối cùng, hãy gọi SignIn() để đăng nhập người chơi vào Play Games:

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

    Khi phân giải Tương lai do SignIn() trả về, bạn có thể lấy thông tin xác thực máy chủ mã khỏi kết quả:

    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();
        }
    }
    

Xác thực bằng Firebase

Sau khi người chơi đăng nhập bằng Play Games, bạn có thể sử dụng mã xác thực để xác thực bằng Firebase.

  1. Sau khi người chơi đăng nhập thành công bằng Play Games, hãy yêu cầu xác thực cho tài khoản của người chơi.

  2. Sau đó, hãy trao đổi mã xác thực từ dịch vụ trò chơi của Play cho Firebase thông tin xác thực và sử dụng thông tin xác thực Firebase để xác thực người chơi:

    firebase::auth::Credential credential =
        firebase::auth::PlayGamesAuthProvider::GetCredential(server_auth_code);
    firebase::Future<firebase::auth::AuthResult> result =
        auth->SignInAndRetrieveDataWithCredential(credential);
    
  3. Nếu chương trình của bạn có vòng lặp cập nhật chạy thường xuyên (chẳng hạn như ở mức 30 hoặc 60 thời gian mỗi giây), bạn có thể kiểm tra kết quả một lần cho mỗi cập nhật bằng Auth::SignInAndRetrieveDataWithCredentialLastResult:

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

    Hoặc nếu chương trình của bạn hướng đến sự kiện, bạn có thể thích đăng ký gọi lại trên Future.

Đăng ký lệnh gọi lại trên Future

Một số chương trình có các hàm Update được gọi 30 hoặc 60 lần mỗi giây. Ví dụ: nhiều trò chơi tuân theo mô hình này. Các chương trình này có thể gọi LastResult các hàm để thăm dò lệnh gọi không đồng bộ. Tuy nhiên, nếu chương trình của bạn hướng sự kiện, thì bạn nên đăng ký các hàm callback. Hàm callback được gọi sau khi hoàn thành 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::AuthResult> result =
      auth->CreateUserWithEmailAndPasswordLastResult();

  // `&my_program_context` is passed verbatim to OnCreateCallback().
  result.OnCompletion(OnCreateCallback, &my_program_context);
}
Hàm callback cũng có thể là một lambda nếu bạn muốn.
void CreateUserUsingLambda(firebase::auth::Auth* auth) {
  // Callbacks work the same for any firebase::Future.
  firebase::Future<firebase::auth::AuthResult> 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);
}

Các bước tiếp theo

Sau khi người dùng đăng nhập lần đầu tiên, một tài khoản người dùng mới sẽ được tạo và có liên kết với mã nhận dạng Play Games của họ. Tài khoản mới này được lưu trữ như một phần của dự án Firebase và có thể được dùng để xác định người dùng trên mọi ứng dụng trong dự án.

Trong trò chơi của mình, bạn có thể lấy UID Firebase của người dùng từ Đối tượng firebase::auth::User:

firebase::auth::User user = auth->current_user();
if (user.is_valid()) {
  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();
}

Trong Cơ sở dữ liệu theo thời gian thực của Firebase và Quy tắc bảo mật của Cloud Storage, bạn có thể nhận được mã nhận dạng người dùng duy nhất của người dùng đã đăng nhập từ biến auth rồi sử dụng mã đó để kiểm soát loại dữ liệu mà người dùng có thể truy cập.

Để lấy thông tin người chơi của Play Games hoặc để truy cập vào dịch vụ trò chơi của Play, sử dụng API do SDK C++ trong dịch vụ Google Play Games cung cấp.

Để đăng xuất một người dùng, hãy gọi SignOut():

auth->SignOut();