Zgodnie z polityką Google w zakresie zgody użytkownika z UE musisz udzielać odpowiednich informacji użytkownikom z Europejskiego Obszaru Gospodarczego (EOG) i Wielkiej Brytanii oraz uzyskać ich zgodę na stosowanie plików cookie lub innych środków do lokalnego przechowywania danych, jeśli jest to wymagane prawnie. Musisz też uzyskać ich zgodę na wykorzystywanie danych osobowych (takich jak AdID) do wyświetlania reklam. Polityka ta odzwierciedla wymagania UE zawarte w dyrektywie o prywatności i łączności elektronicznej oraz w Ogólnym rozporządzeniu o ochronie danych (RODO).
Aby pomóc wydawcom w wypełnieniu obowiązków, jakie nakłada na nich ta polityka, Google oferuje pakiet SDK User Messaging Platform (UMP). Zaktualizowaliśmy pakiet UMP SDK, aby obsługiwał najnowsze standardy IAB. Wszystkimi tymi konfiguracjami możesz teraz wygodnie zarządzać na stronie AdMob prywatności i przesyłania wiadomości.
Wymagania wstępne
- Wykonaj czynności opisane w przewodniku dla początkujących.
- Interfejs API Androida na poziomie 21 lub wyższym (Android)
- Jeśli pracujesz nad wymaganiami dotyczącymi RODO, przeczytaj artykułJak wymagania IAB wpływają na wiadomości z prośbą o zgodę na wykorzystanie danych (zgodnie z wytycznymi UE)
Tworzenie typu wiadomości
Utwórz wiadomości dla użytkowników za pomocą dostępnego typu wiadomości dla użytkowników na karcie Prywatność i wyświetlanie wiadomości na koncie AdMob Pakiet UMP SDK próbuje wyświetlić wiadomość dla użytkownika utworzoną na podstawie AdMob identyfikatora aplikacji ustawionego w Twoim projekcie. Jeśli dla aplikacji nie jest skonfigurowany żaden komunikat, pakiet SDK zwraca błąd.
Więcej informacji znajdziesz w artykule Informacje o prywatności i przesyłaniu wiadomości.
Zainstaluj pakiet SDK
Wykonaj te czynności, aby zainstalować pakiet SDK do reklam mobilnych Google (GMA) C++. Pakiet UMP C++ SDK jest częścią pakietu GMA C++ SDK.
Zanim przejdziesz dalej, skonfiguruj identyfikator aplikacji AdMob w projekcie.
W kodzie zainicjuj pakiet UMP SDK, wywołując metodę
ConsentInfo::GetInstance()
.- W Androidzie musisz zaliczyć
JNIEnv
iActivity
dostarczone przez NDK. Musisz to zrobić tylko przy pierwszym połączeniu z numeremGetInstance()
. - Jeśli w swojej aplikacji używasz już pakietu SDK Firebase w C++, możesz też przekazać
firebase::App
przy pierwszym wywołaniuGetInstance()
.
#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
- W Androidzie musisz zaliczyć
Kolejne wywołania ConsentInfo::GetInstance()
zwracają tę samą instancję.
Jeśli korzystasz już z pakietu UMP SDK, możesz go wyłączyć, usuwając instancję ConsentInfo
:
void ShutdownUserMessagingPlatform() {
ump::ConsentInfo* consent_info = ump::ConsentInfo::GetInstance();
delete consent_info;
}
Używanie metody Future
do monitorowania operacji asynchronicznych
klasa firebase::Future
umożliwia określenie stanu ukończenia wywołań metod asynchronicznych.
Wszystkie funkcje i wywołania metod UMP C++, które działają asynchronicznie, zwracają parametr Future
oraz zapewniają funkcję „ostatniego wyniku”, która pobiera Future
z ostatniej operacji.
Wynik można uzyskać z Future
na 2 sposoby:
- Wywołaj
OnCompletion()
, przekazując własną funkcję wywołania zwrotnego, która jest wywoływana po zakończeniu operacji. - Okresowo sprawdzaj
status()
na urządzeniuFuture
. Gdy stan zmieni się zkFutureStatusPending
nakFutureStatusCompleted
, operacja została ukończona.
Po zakończeniu operacji asynchronicznej sprawdź error()
Future
, aby uzyskać kod błędu. Jeśli kod błędu to 0
(kConsentRequestSuccess
lub kConsentFormSuccess
), operacja zakończyła się pomyślnie. W przeciwnym razie sprawdź kod błędu i error_message()
, aby określić, co poszło nie tak.
Ukończenie wywołania zwrotnego
Oto przykład użycia funkcji OnCompletion
do ustawienia wywołania zwrotnego uzupełniającego, które jest wywoływane po zakończeniu operacji asynchronicznej.
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.
}
});
}
Aktualizowanie sondowania w pętli
W tym przykładzie, gdy operacja asynchroniczna zostanie uruchomiona przy uruchomieniu aplikacji, wyniki są sprawdzane w innym miejscu – w funkcji pętli aktualizacji gry (która uruchamia się raz na klatkę).
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.
}
}
}
}
Więcej informacji na temat firebase::Future
znajdziesz w dokumentacji pakietu SDK Firebase C++ SDK i dokumentacji pakietu SDK do reklam mobilnych Google C++ SDK.
Prośba o zgodę na wykorzystanie danych
Po każdym uruchomieniu aplikacji musisz prosić użytkownika o aktualizację informacji o zgodzie użytkownika za pomocą funkcji RequestConsentInfoUpdate()
. Pozwala to określić, czy użytkownik musi wyrazić zgodę, jeśli jeszcze tego nie zrobił, czy też wygasła.
#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.
}
});
}
powyżej znajdziesz przykład sprawdzania ukończenia za pomocą odpytywania w pętli aktualizacji zamiast wywołania zwrotnego w trakcie całego procesu.
Wczytaj i wyświetl formularz zgody, jeśli jest to wymagane
Gdy otrzymasz najbardziej aktualny stan zgody, zadzwońLoadAndShowConsentFormIfRequired()
naConsentInfo
zajęcia, aby wczytać formularz zgody. Jeśli stan zgody jest wymagany, pakiet SDK wczytuje formularz i od razu wyświetla go z przesłanych FormParent
. Po zamknięciu formularza Future
jest ukończony . Jeśli zgoda nie jest wymagana, proces Future
jest ukończony .
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.
}
});
}
});
}
Jeśli po dokonaniu wyboru przez użytkownika lub zamknięciu formularza musisz wykonać jakieś działanie, umieść tę logikę w kodzie obsługującym Future
zwracany przez LoadAndShowConsentFormIfRequired()
.
Wyślij żądanie
Zanim poprosisz o reklamy w aplikacji, sprawdź, czy masz zgodę użytkownika korzystającego z usługi ConsentInfo::GetInstance()‑>CanRequestAds()
. Zgodę należy sprawdzić w 2 miejscach:
- Gdy w bieżącej sesji uzyskasz zgodę użytkowników.
- Zaraz po rozmowie telefonicznej z firmą
RequestConsentInfoUpdate()
. Możliwe, że zgoda została udzielona w poprzedniej sesji. Zalecamy, aby nie czekać na zakończenie wywołania zwrotnego, ponieważ pozwoli to rozpocząć ładowanie reklam jak najszybciej po uruchomieniu aplikacji.
Jeśli podczas uzyskiwania zgody użytkowników wystąpi błąd, nadal próbuj wysłać żądania reklam. Pakiet UMP SDK używa stanu zgody z poprzedniej sesji.
Poniższy pełny przykład wykorzystuje odpytywanie w pętli aktualizacji, ale do monitorowania operacji asynchronicznych możesz używać też wywołań zwrotnych OnCompletion
. Używaj tej metody, która lepiej pasuje do Twojej struktury kodu.
#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;
}
}
}
}
Opcje prywatności
Niektóre formularze zgody wymagają od użytkownika wprowadzenia zmian w dowolnym momencie. Aby w razie potrzeby zaimplementować przycisk opcji prywatności, postępuj zgodnie z poniższymi instrukcjami.
W tym celu:
- Zaimplementuj element interfejsu, np. przycisk na stronie ustawień aplikacji, który może uruchamiać formularz opcji prywatności.
- Gdy
LoadAndShowConsentFormIfRequired()
to się zakończy, zaznaczgetPrivacyOptionsRequirementStatus()
, aby określić, czy wyświetlić element interfejsu, który może wyświetlać formularz opcji prywatności. - Gdy użytkownik wejdzie w interakcję z elementem interfejsu, wywołaj
showPrivacyOptionsForm()
, aby wyświetlić formularz. Dzięki temu będzie mógł w dowolnym momencie zaktualizować swoje opcje prywatności.
Testowanie
Jeśli chcesz przetestować integrację z aplikacją w trakcie jej tworzenia, wykonaj te czynności, aby automatycznie zarejestrować urządzenie testowe. Pamiętaj, aby przed opublikowaniem aplikacji usunąć kod, który ustawia te identyfikatory urządzeń testowych.
- Zadzwoń pod numer
RequestConsentInfoUpdate()
. Sprawdź, czy w danych wyjściowych logu nie pojawia się komunikat podobny do tego przykładowego poniżej, który zawiera identyfikator urządzenia i informuje, jak dodać go jako urządzenie testowe:
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]
Skopiuj identyfikator urządzenia testowego do schowka.
Zmodyfikuj kod tak, aby
ConsentRequestParameters.debug_settings.debug_device_ids
listę identyfikatorów urządzeń testowych.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); }
Wymuś ustawienie geograficzne
Pakiet UMP SDK umożliwia przetestowanie działania aplikacji tak, jakby urządzenie znajdowało się w Europejskim Obszarze Gospodarczym lub Wielkiej Brytanii w ramach usługi ConsentRequestParameters.debug_settings.debug_geography
. Pamiętaj, że ustawienia debugowania działają tylko na urządzeniach testowych.
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);
}
Resetuj stan zgody użytkownika
Podczas testowania aplikacji za pomocą pakietu UMP SDK warto zresetować stan tego pakietu, aby zasymulować proces pierwszej instalacji przez użytkownika.
Pakiet SDK udostępnia Reset()
metodę pozwalającą to zrobić.
ConsentInfo::GetInstance()->Reset();