Bắt đầu

Theo Chính sách về sự đồng ý của người dùng ở Liên minh Châu Âu của Google, bạn phải đưa ra một số thông tin công bố nhất định cho người dùng ở Khu vực kinh tế Châu Âu (EEA) cùng với Vương quốc Anh, đồng thời có được sự đồng ý của họ để sử dụng cookie hoặc các phương pháp lưu trữ cục bộ khác (khi pháp luật yêu cầu) và để sử dụng dữ liệu cá nhân (chẳng hạn như mã nhận dạng cho quảng cáo (AdID)) để phân phát quảng cáo. Chính sách này thể hiện các yêu cầu của Chỉ thị về quyền riêng tư và truyền thông điện tử của Liên minh Châu Âu cũng như Quy định chung về việc bảo vệ dữ liệu (GDPR).

Để giúp các nhà xuất bản đáp ứng các nghĩa vụ của họ theo chính sách này, Google cung cấp SDK Nền tảng thông báo cho người dùng (UMP). UMP SDK đã được cập nhật để hỗ trợ các tiêu chuẩn mới nhất của IAB. Giờ đây, bạn có thể xử lý tất cả các cấu hình này một cách thuận tiện trong phần AdMob quyền riêng tư và thông báo.

Điều kiện tiên quyết

  • API Android cấp 21 trở lên (dành cho Android)

Tạo một loại thông báo

Tạo thông báo cho người dùng bằng một trong các các loại thông báo hiện có cho người dùng trong thẻ Quyền riêng tư và thông báo của tài khoản AdMob . SDK UMP cố gắng hiển thị một thông báo cho người dùng được tạo từ AdMob Mã ứng dụng được đặt trong dự án của bạn. Nếu không có thông báo nào được định cấu hình cho ứng dụng, thì SDK sẽ trả về lỗi.

Để biết thêm thông tin, hãy xem bài viết Giới thiệu về quyền riêng tư và thông báo.

Cài đặt SDK

  1. Làm theo các bước để cài đặt SDK C++ của Quảng cáo của Google trên thiết bị di động (GMA). SDK C++ của UMP có trong SDK C++ của GMA.

  2. Hãy đảm bảo rằng bạn đã định cấu hình mã ứng dụng AdMob của ứng dụng trong dự án trước khi tiếp tục.

  3. Trong mã nguồn của bạn, hãy khởi chạy UMP SDK bằng cách gọi ConsentInfo::GetInstance().

    • Trên Android, bạn cần truyền vào JNIEnvActivity do NDK cung cấp. Bạn chỉ cần thực hiện việc này vào lần đầu tiên gọi GetInstance().
    • Ngoài ra, nếu đã sử dụng SDK C++ của Firebase trong ứng dụng, bạn có thể truyền firebase::App vào lần đầu tiên gọi GetInstance().
    #include "firebase/gma/ump.h"
    
    namespace ump = ::firebase::gma::ump;
    
    // Initialize using a firebase::App
    void InitializeUserMessagingPlatform(const firebase::App& app) {
      ump::ConsentInfo* consent_info = ump::ConsentInfo::GetInstance(app);
    }
    
    // Initialize without a firebase::App
    #ifdef ANDROID
    void InitializeUserMessagingPlatform(JNIEnv* jni_env, jobject activity) {
      ump::ConsentInfo* consent_info = ump::ConsentInfo::GetInstance(jni_env, activity);
    }
    #else  // non-Android
    void InitializeUserMessagingPlatform() {
      ump::ConsentInfo* consent_info = ump::ConsentInfo::GetInstance();
    }
    #endif
    

Các lệnh gọi tiếp theo tới ConsentInfo::GetInstance() đều trả về cùng một phiên bản.

Nếu đã sử dụng xong SDK UMP, bạn có thể tắt SDK bằng cách xoá thực thể ConsentInfo:

void ShutdownUserMessagingPlatform() {
  ump::ConsentInfo* consent_info = ump::ConsentInfo::GetInstance();
  delete consent_info;
}

Sử dụng Future để giám sát các hoạt động không đồng bộ

firebase::Future cung cấp cho bạn cách xác định trạng thái hoàn thành của các lệnh gọi phương thức không đồng bộ.

Tất cả hàm và lệnh gọi phương thức UMP C++ hoạt động không đồng bộ đều trả về Future, đồng thời cung cấp hàm "kết quả cuối cùng" để truy xuất Future từ thao tác gần đây nhất.

Có hai cách để lấy kết quả từ Future:

  1. Gọi OnCompletion(), truyền vào hàm callback của riêng bạn, hàm này được gọi khi hoạt động hoàn tất.
  2. Định kỳ kiểm tra status() của Future. Khi trạng thái thay đổi từ kFutureStatusPending thành kFutureStatusCompleted, thao tác đã hoàn tất.

Sau khi thực hiện xong thao tác không đồng bộ, bạn nên kiểm tra error() của Future để lấy mã lỗi của thao tác đó. Nếu mã lỗi là 0 (kConsentRequestSuccess hoặc kConsentFormSuccess), thì thao tác đã hoàn tất thành công; nếu không, hãy kiểm tra mã lỗi và error_message() để xác định xem đã xảy ra lỗi gì.

Lệnh gọi lại hoàn thành

Dưới đây là ví dụ về cách sử dụng OnCompletion để đặt lệnh gọi lại hoàn thành. Lệnh gọi lại này được gọi khi hoạt động không đồng bộ hoàn tất.

void MyApplicationStart() {
  // [... other app initialization code ...]

  ump::ConsentInfo *consent_info = ump::ConsentInfo::GetInstance();

  // See the section below for more information about RequestConsentInfoUpdate.
  firebase::Future<void> result = consent_info->RequestConsentInfoUpdate(...);

  result.OnCompletion([](const firebase::Future<void>& req_result) {
    if (req_result.error() == ump::kConsentRequestSuccess) {
      // Operation succeeded. You can now call LoadAndShowConsentFormIfRequired().
    } else {
      // Operation failed. Check req_result.error_message() for more information.
    }
  });
}

Cập nhật tính năng thăm dò vòng lặp

Trong ví dụ này, sau khi một hoạt động không đồng bộ được bắt đầu khi khởi chạy ứng dụng, kết quả sẽ được kiểm tra ở nơi khác, trong hàm lặp lại cập nhật của trò chơi (chạy một lần trên mỗi khung hình).

ump::ConsentInfo *g_consent_info = nullptr;
bool g_waiting_for_request = false;

void MyApplicationStart() {
  // [... other app initialization code ...]

  g_consent_info = ump::ConsentInfo::GetInstance();
  // See the section below for more information about RequestConsentInfoUpdate.
  g_consent_info->RequestConsentInfoUpdate(...);
  g_waiting_for_request = true;
}

// Elsewhere, in the game's update loop, which runs once per frame:
void MyGameUpdateLoop() {
  // [... other game logic here ...]

  if (g_waiting_for_request) {
    // Check whether RequestConsentInfoUpdate() has finished.
    // Calling "LastResult" returns the Future for the most recent operation.
    firebase::Future<void> result =
      g_consent_info->RequestConsentInfoUpdateLastResult();

    if (result.status() == firebase::kFutureStatusComplete) {
      g_waiting_for_request = false;
      if (result.error() == ump::kConsentRequestSuccess) {
        // Operation succeeded. You can call LoadAndShowConsentFormIfRequired().
      } else {
        // Operation failed. Check result.error_message() for more information.
      }
    }
  }
}

Để biết thêm thông tin về firebase::Future, hãy xem tài liệu về SDK C++ của Firebasetài liệu về SDK C++ của GMA.

Bạn nên yêu cầu cập nhật thông tin về sự đồng ý của người dùng mỗi khi khởi chạy ứng dụng bằng cách sử dụng RequestConsentInfoUpdate(). Điều này xác định liệu người dùng có cần đưa ra sự đồng ý hay không (nếu họ chưa làm vậy) hay nếu trạng thái đồng ý của họ đã hết hạn.

#include "firebase/gma/ump.h"

namespace ump = ::firebase::gma::ump;

void MyApplicationStart() {
  ump::ConsentInfo* consent_info = ump::ConsentInfo::GetInstance();

  // Create a ConsentRequestParameters struct.
  ump::ConsentRequestParameters params;
  // Set tag for under age of consent. False means users are NOT under age
  // of consent.
  params.tag_for_under_age_of_consent = false;

  consent_info->RequestConsentInfoUpdate(params).OnCompletion(
    [](const Future<void>& result) {
      if (result.error() != ump::kConsentRequestSuccess) {
        LogMessage("Error requesting consent update: %s", result.error_message());
      } else {
        // Consent status is now available.
      }
    });
}

Hãy xem phần ở trên để biết ví dụ về cách kiểm tra trạng thái hoàn thành bằng cách sử dụng tính năng kiểm tra vòng lặp cập nhật thay vì lệnh gọi lại hoàn thành.

Tải và hiển thị biểu mẫu lấy sự đồng ý (nếu cần)

Sau khi bạn nhận được trạng thái đồng ý mới nhất, hãy gọi LoadAndShowConsentFormIfRequired() trên lớp ConsentInfo để tải biểu mẫu đồng ý. Nếu trạng thái đồng ý là bắt buộc, SDK sẽ tải một biểu mẫu và ngay lập tức hiển thị biểu mẫu đó từ FormParentđược cung cấp. Future đã hoàn tất sau khi biểu mẫu bị loại bỏ. Nếu không cần có sự đồng ý, thì Future sẽ hoàn tất ngay lập tức.

void MyApplicationStart(ump::FormParent parent) {
  ump::ConsentInfo* consent_info = ump::ConsentInfo::GetInstance();

  // Create a ConsentRequestParameters struct..
  ump::ConsentRequestParameters params;
  // Set tag for under age of consent. False means users are NOT under age of consent.
  params.tag_for_under_age_of_consent = false;

  consent_info->RequestConsentInfoUpdate(params).OnCompletion(
    [*](const Future<void>& req_result) {
      if (req_result.error() != ump::kConsentRequestSuccess) {
        // req_result.error() is a kConsentRequestError enum.
        LogMessage("Error requesting consent update: %s", req_result.error_message());
      } else {
        consent_info->LoadAndShowConsentFormIfRequired(parent).OnCompletion(
        [*](const Future<void>& form_result) {
          if (form_result.error() != ump::kConsentFormSuccess) {
            // form_result.error() is a kConsentFormError enum.
            LogMessage("Error showing consent form: %s", form_result.error_message());
          } else {
            // Either the form was shown and completed by the user, or consent was not required.
          }
        });
      }
    });
}

Nếu bạn cần thực hiện bất kỳ hành động nào sau khi người dùng đã đưa ra lựa chọn hoặc đóng biểu mẫu, hãy đặt logic đó vào mã xử lý Future do LoadAndShowConsentFormIfRequired() trả về.

Yêu cầu quảng cáo

Trước khi yêu cầu quảng cáo trong ứng dụng của bạn, hãy kiểm tra xem bạn có được người dùng đồng ý bằng cách sử dụng ConsentInfo::GetInstance()‑>CanRequestAds()hay không. Có 2 nơi để kiểm tra trong quá trình thu thập sự đồng ý:

  1. Sau khi có được sự đồng ý trong phiên hiện tại.
  2. Ngay sau khi bạn gọi RequestConsentInfoUpdate(). Có thể bạn đã nhận được sự đồng ý trong phiên trước đó. Một phương pháp hay nhất về độ trễ là bạn không nên đợi lệnh gọi lại hoàn tất để có thể bắt đầu tải quảng cáo ngay khi có thể sau khi ứng dụng khởi chạy.

Nếu xảy ra lỗi trong quá trình thu thập sự đồng ý, bạn vẫn nên tìm cách yêu cầu quảng cáo. SDK UMP sử dụng trạng thái đồng ý từ phiên trước.

Ví dụ hoàn chỉnh sau đây sử dụng tính năng kiểm tra vòng lặp cập nhật, nhưng bạn cũng có thể dùng lệnh gọi lại OnCompletion để theo dõi các hoạt động không đồng bộ. Hãy sử dụng bất kỳ kỹ thuật nào phù hợp hơn với cấu trúc mã của bạn.

#include "firebase/future.h"
#include "firebase/gma/gma.h"
#include "firebase/gma/ump.h"

namespace gma = ::firebase::gma;
namespace ump = ::firebase::gma::ump;
using firebase::Future;

ump::ConsentInfo* g_consent_info = nullptr;
// State variable for tracking the UMP consent flow.
enum { kStart, kRequest, kLoadAndShow, kInitGma, kFinished, kErrorState } g_state = kStart;
bool g_ads_allowed = false;

void MyApplicationStart() {
  g_consent_info = ump::ConsentInfo::GetInstance(...);

  // Create a ConsentRequestParameters struct..
  ump::ConsentRequestParameters params;
  // Set tag for under age of consent. False means users are NOT under age of consent.
  params.tag_for_under_age_of_consent = false;

  g_consent_info->RequestConsentInfoUpdate(params);
  // CanRequestAds() can return a cached value from a previous run immediately.
  g_ads_allowed = g_consent_info->CanRequestAds();
  g_state = kRequest;
}

// This function runs once per frame.
void MyGameUpdateLoop() {
  // [... other game logic here ...]

  if (g_state == kRequest) {
    Future<void> req_result = g_consent_info->RequestConsentInfoUpdateLastResult();

    if (req_result.status() == firebase::kFutureStatusComplete) {
      g_ads_allowed = g_consent_info->CanRequestAds();
      if (req_result.error() == ump::kConsentRequestSuccess) {
        // You must provide the FormParent (Android Activity or iOS UIViewController).
        ump::FormParent parent = GetMyFormParent();
        g_consent_info->LoadAndShowConsentFormIfRequired(parent);
        g_state = kLoadAndShow;
      } else {
        LogMessage("Error requesting consent status: %s", req_result.error_message());
        g_state = kErrorState;
      }
    }
  }
  if (g_state == kLoadAndShow) {
    Future<void> form_result = g_consent_info->LoadAndShowConsentFormIfRequiredLastResult();

    if (form_result.status() == firebase::kFutureStatusComplete) {
      g_ads_allowed = g_consent_info->CanRequestAds();
      if (form_result.error() == ump::kConsentRequestSuccess) {
        if (g_ads_allowed) {
          // Initialize GMA. This is another asynchronous operation.
          firebase::gma::Initialize();
          g_state = kInitGma;
        } else {
          g_state = kFinished;
        }
        // Optional: shut down the UMP SDK to save memory.
        delete g_consent_info;
        g_consent_info = nullptr;
      } else {
        LogMessage("Error displaying consent form: %s", form_result.error_message());
        g_state = kErrorState;
      }
    }
  }
  if (g_state == kInitGma && g_ads_allowed) {
    Future<gma::AdapterInitializationStatus> gma_future = gma::InitializeLastResult();

    if (gma_future.status() == firebase::kFutureStatusComplete) {
      if (gma_future.error() == gma::kAdErrorCodeNone) {
        g_state = kFinished;
        // TODO: Request an ad.
      } else {
        LogMessage("Error initializing GMA: %s", gma_future.error_message());
        g_state = kErrorState;
      }
    }
  }
}

Tuỳ chọn quyền riêng tư

Một số biểu mẫu đồng ý yêu cầu người dùng sửa đổi sự đồng ý của họ bất cứ lúc nào. Hãy làm theo các bước sau đây để triển khai nút tuỳ chọn quyền riêng tư nếu cần.

Để thực hiện điều này:

  1. Triển khai một thành phần trên giao diện người dùng, chẳng hạn như một nút trong trang cài đặt của ứng dụng, để có thể kích hoạt biểu mẫu các tuỳ chọn về quyền riêng tư.
  2. Sau khi LoadAndShowConsentFormIfRequired() hoàn tất, hãy kiểm tragetPrivacyOptionsRequirementStatus() để xác định xem có hiển thị thành phần trên giao diện người dùng có thể hiển thị biểu mẫu tuỳ chọn quyền riêng tư hay không.
  3. Khi người dùng tương tác với phần tử trên giao diện người dùng, hãy gọishowPrivacyOptionsForm() để hiển thị biểu mẫu và người dùng có thể cập nhật các tuỳ chọn quyền riêng tư của họ bất cứ lúc nào.

Kiểm thử

Nếu bạn muốn kiểm thử tính năng tích hợp trong ứng dụng khi đang phát triển, hãy làm theo các bước sau để đăng ký thiết bị kiểm thử theo phương thức lập trình. Hãy nhớ xóa mã dùng để đặt các mã thiết bị thử nghiệm này trước khi bạn phát hành ứng dụng.

  1. Gọi RequestConsentInfoUpdate().
  2. Kiểm tra đầu ra nhật ký để tìm một thông báo tương tự như ví dụ sau. Thông báo này cho biết mã thiết bị của bạn và cách thêm mã thiết bị đó làm thiết bị thử nghiệm:

    Android

    Use new ConsentDebugSettings.Builder().addTestDeviceHashedId("33BE2250B43518CCDA7DE426D04EE231")
    to set this as a debug device.
    

    iOS

    <UMP SDK>To enable debug mode for this device,
    set: UMPDebugSettings.testDeviceIdentifiers = @[2077ef9a63d2b398840261c8221a0c9b]
    
  3. Sao chép mã thiết bị thử nghiệm vào bảng nhớ tạm.

  4. Sửa đổi mã để đặt ConsentRequestParameters.debug_settings.debug_device_ids thành danh sách mã thiết bị thử nghiệm.

    void MyApplicationStart() {
      ump::ConsentInfo consent_info = ump::ConsentInfo::GetInstance(...);
    
      ump::ConsentRequestParameters params;
      params.tag_for_under_age_of_consent = false;
      params.debug_settings.debug_device_ids = {"TEST-DEVICE-HASHED-ID"};
    
      consent_info->RequestConsentInfoUpdate(params);
    }
    

Chỉ định một vị trí địa lý

SDK UMP cung cấp một cách để kiểm thử hành vi của ứng dụng như thể thiết bị được đặt ở Khu vực kinh tế Châu Âu (EEA) hoặc Vương quốc Anh bằng cách sử dụng ConsentRequestParameters.debug_settings.debug_geography. Xin lưu ý rằng chế độ gỡ lỗi chỉ hoạt động trên thiết bị thử nghiệm.

void MyApplicationStart() {
  ump::ConsentInfo consent_info = ump::ConsentInfo::GetInstance(...);

  ump::ConsentRequestParameters params;
  params.tag_for_under_age_of_consent = false;
  params.debug_settings.debug_device_ids = {"TEST-DEVICE-HASHED-ID"};
  // Geography appears as EEA for debug devices.
  params.debug_settings.debug_geography = ump::kConsentDebugGeographyEEA

  consent_info->RequestConsentInfoUpdate(params);
}

Khi kiểm thử ứng dụng bằng UMP SDK, bạn nên đặt lại trạng thái của SDK để có thể mô phỏng trải nghiệm cài đặt lần đầu của người dùng. SDK sẽ cung cấp phương thức Reset() để thực hiện việc này.

  ConsentInfo::GetInstance()->Reset();