Google User Messaging Platform (UMP) SDK – это инструмент для управления настройками конфиденциальности и сообщениями. Дополнительную информацию вы найдете в статье О странице "Конфиденциальность и сообщения".
Требования
- Android API уровня 21 или выше (для Android).
Как создать тип сообщения
Создайте сообщения для пользователей, выбрав один из доступных типов на вкладке Конфиденциальность и сообщения в аккаунте AdMob. UMP SDK пытается показать сообщение о конфиденциальности, созданное на основе идентификатора приложения AdMob, который задан в вашем проекте.
Подробнее о странице "Конфиденциальность и сообщения"…Установите SDK
Следуйте инструкциям по установке Firebase C++ SDK. UMP C++ SDK входит в состав Firebase C++ SDK.
Прежде чем продолжить, настройте идентификатор приложения AdMob в проекте.
Инициализируйте UMP SDK в коде, вызвав
ConsentInfo::GetInstance().- В Android необходимо передать
JNIEnvиActivity, предоставленные NDK. Это нужно сделать только при первом вызовеGetInstance(). - Если вы уже используете в приложении Firebase C++ SDK, то можете передать
firebase::Appпри первом вызовеGetInstance().
#include "firebase/ump/ump.h" namespace ump = ::firebase::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- В Android необходимо передать
Последующие вызовы ConsentInfo::GetInstance() возвращают тот же экземпляр.
Если вы больше не используете UMP SDK, вы можете отключить его, удалив экземпляр ConsentInfo:
void ShutdownUserMessagingPlatform() {
ump::ConsentInfo* consent_info = ump::ConsentInfo::GetInstance();
delete consent_info;
}
Используйте Future для отслеживания асинхронных операций
firebase::Future позволяет определить статус выполнения асинхронных вызовов методов.
Все асинхронные функции и вызовы методов UMP C++ возвращают Future, а также предоставляют функцию "последний результат" для получения Future из последней операции.
Получить результат из Future можно двумя способами:
- Вызовите
OnCompletion(), передав собственную функцию обратного вызова, которая будет вызвана по завершении операции. - Периодически проверяйте
status()Future. Когда статус изменится сkFutureStatusPendingнаkFutureStatusCompleted, операция будет завершена.
После завершения асинхронной операции проверьте свойство error() объекта Future, чтобы получить код ошибки. Если код ошибки – 0 (kConsentRequestSuccess или kConsentFormSuccess), операция выполнена успешно. В противном случае проверьте код ошибки и error_message(), чтобы определить, что пошло не так.
Обратный вызов при завершении
Ниже приведен пример того, как использовать OnCompletion, чтобы задать обратный вызов, который будет выполняться по завершении асинхронной операции.
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.
}
});
}
Опрос цикла обновления
В этом примере после запуска асинхронной операции при запуске приложения результаты проверяются в другом месте – в функции цикла обновления игры (которая выполняется один раз за кадр).
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.
}
}
}
}
Дополнительную информацию о firebase::Future можно найти в документации по Firebase C++ SDK и GMA C++ SDK.
Как получить информацию о согласии пользователя
Запрашивайте обновление информации о согласии пользователя при каждом запуске приложения с помощью метода
RequestConsentInfoUpdate(). При этом проверяется следующее:
- Требуется ли согласие. Например, если согласие запрашивается впервые или срок действия предыдущего согласия истек.
- Нужна ли точка входа для настроек конфиденциальности. Некоторые сообщения о конфиденциальности требуют, чтобы приложения позволяли пользователям в любое время изменять настройки конфиденциальности.
#include "firebase/ump/ump.h"
namespace ump = ::firebase::ump;
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());
}
// Consent information is successfully updated.
});
}
Загрузка и показ формы сообщения о конфиденциальности
Получив актуальный статус согласия, вызовите
LoadAndShowConsentFormIfRequired(), чтобы загрузить формы, необходимые для получения согласия пользователя. После загрузки формы сразу же показываются.
#include "firebase/ump/ump.h"
namespace ump = ::firebase::ump;
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 privacy message form: %s", form_result.error_message());
} else {
// Either the form was shown and completed by the user, or consent was not required.
}
});
}
});
}
Пример проверки завершения с помощью опроса цикла обновления, а не обратного вызова, приведен выше.
Если вам нужно выполнить какие-либо действия после того, как пользователь сделал выбор или закрыл форму, поместите эту логику в код, который обрабатывает Future, возвращенный LoadAndShowConsentFormIfRequired().
Настройки конфиденциальности
Некоторые формы сообщений о конфиденциальности показываются в точке входа для настроек конфиденциальности, которую создает издатель. Это позволяет пользователям в любой момент изменить свои настройки конфиденциальности. Подробнее о том, какое сообщение увидят пользователи, выбравшие вариант конфиденциальности, читайте в статье Доступные типы сообщений для пользователей.
Как запрашивать объявления с согласия пользователя
Прежде чем запрашивать объявления, используйте
ConsentInfo::GetInstance()‑>
CanRequestAds(), чтобы проверить, получено ли согласие пользователя:
Ниже перечислены места, в которых можно проверить, запрашивается ли реклама во время сбора согласия.
- После того как UMP SDK получит согласие в текущем сеансе.
- Сразу после вызова
RequestConsentInfoUpdate(). Возможно, UMP SDK получил согласие в предыдущем сеансе приложения.
Если в процессе получения согласия возникает ошибка, проверьте, можете ли вы запрашивать объявления. UMP SDK использует статус согласия из предыдущего сеанса приложения.
Как избежать лишних запросов объявлений
При проверке
ConsentInfo::GetInstance()‑>
CanRequestAds() после получения согласия и вызова
RequestConsentInfoUpdate() убедитесь, что ваша логика предотвращает избыточные запросы объявлений, которые могут привести к тому, что обе проверки вернут true. Например, с помощью логической переменной.
В следующем полном примере используется опрос цикла обновления, но вы также можете использовать обратные вызовы OnCompletion для отслеживания асинхронных операций. Используйте тот способ, который лучше подходит для структуры вашего кода.
#include "firebase/future.h"
#include "firebase/gma/gma.h"
#include "firebase/ump/ump.h"
namespace gma = ::firebase::gma;
namespace ump = ::firebase::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 privacy message 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;
}
}
}
}
Тестирование
Чтобы протестировать интеграцию в приложении во время разработки, выполните следующие действия для программной регистрации тестового устройства. Перед публикацией приложения не забудьте удалить код, который задает эти идентификаторы тестовых устройств.
- Позвоните в компанию "
RequestConsentInfoUpdate()". Найдите в журнале сообщение, похожее на приведенное ниже. В нем будет указан идентификатор устройства и инструкции по его добавлению в качестве тестового.
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]Скопируйте идентификатор тестового устройства в буфер обмена.
Измените код, чтобы задать для
ConsentRequestParameters.debug_settings.debug_device_idsсписок идентификаторов тестовых устройств.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); }
Принудительное указание местоположения
UMP SDK позволяет проверить, как будет работать приложение для пользователей из разных регионов, например из Европейской экономической зоны (ЕЭЗ), Великобритании и Швейцарии. Для этого используется debug_settings.debug_geography. Обратите внимание, что настройки отладки работают только на тестовых устройствах.
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);
}
Сбросить статус согласия
При тестировании приложения с UMP SDK может быть полезно сбросить состояние SDK, чтобы смоделировать первый запуск приложения пользователем.
Для этого в SDK предусмотрен метод Reset().
ConsentInfo::GetInstance()->Reset();