Начало работы

В соответствии с Политикой согласия пользователей Google из ЕС вы должны раскрыть определенную информацию своим пользователям в Европейской экономической зоне (ЕЭЗ), а также в Великобритании, и получить их согласие на использование файлов cookie или другого локального хранилища, если это требуется по закону, а также на использование личных данных ( например AdID) для показа рекламы. Эта политика отражает требования Директивы ЕС об электронной конфиденциальности и Общего регламента защиты данных (GDPR).

Чтобы помочь издателям выполнять свои обязанности в соответствии с этой политикой, Google предлагает SDK User Messaging Platform (UMP). UMP SDK был обновлен для поддержки новейших стандартов IAB. Всеми этими конфигурациями теперь можно удобно управлять в разделе конфиденциальности и обмена сообщениями AdMob .

Предварительные условия

  • Android API уровня 21 или выше(для Android)

Создайте тип сообщения

Создавайте пользовательские сообщения с одним из доступных типов сообщенийна вкладке Конфиденциальность и обмен сообщениями вашего аккаунтаAdMob. UMP SDK пытается отобразить сообщение пользователя, созданное на основе идентификатора приложения AdMob ​​установленного в вашем проекте. Если для вашего приложения не настроено сообщение, SDK возвращает ошибку.

Дополнительные сведения см.О конфиденциальности и обмене сообщениями .

Установите SDK

  1. Следуйте инструкциям по установке Google Mobile Ads (GMA) C++ SDK . UMP C++ SDK включен в GMA C++ SDK.

  2. Прежде чем продолжить, убедитесь, что вы настроили идентификатор приложения AdMob в проекте.

  3. В своем коде инициализируйте UMP SDK, вызвав ConsentInfo::GetInstance() .

    • На Android вам необходимо передать JNIEnv и Activity , предоставленные NDK. Вам нужно сделать это только при первом вызове GetInstance() .
    • В качестве альтернативы, если вы уже используете Firebase C++ SDK в своем приложении, вы можете передать firebase::App при первом вызове 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
    

Последующие вызовы ConsentInfo::GetInstance() возвращают один и тот же экземпляр.

Если вы закончили использовать UMP SDK, вы можете закрыть SDK, удалив экземпляр ConsentInfo :

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

Используйте Future для мониторинга асинхронных операций

firebase::Future предоставляет вам возможность определить статус завершения вызовов асинхронных методов.

Все функции и вызовы методов UMP C++, которые работают асинхронно, возвращают Future , а также предоставляют функцию «последнего результата» для получения Future из самой последней операции.

Есть два способа получить результат из Future :

  1. Вызовите OnCompletion() , передав собственную функцию обратного вызова, которая вызывается после завершения операции.
  2. Периодически проверяйте статус Future status() . Когда статус меняется с kFutureStatusPending на kFutureStatusCompleted , операция завершена.

После завершения асинхронной операции вам следует проверить функцию Future error() , чтобы получить код ошибки операции. Если код ошибки равен 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/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.
      }
    });
}

См . выше пример проверки завершения с использованием опроса цикла обновления, а не обратного вызова завершения.

Загрузите и покажите форму согласия, если требуется.

После получения последней версии статуса согласия вызовитеLoadAndShowConsentFormIfRequired() в классеConsentInfo чтобы загрузить форму согласия. Если требуется статус согласия, SDK загружает форму и немедленно представляет ее из предоставленного FormParent. Futureзавершается. после закрытия формы. Если согласие не требуется, Futureзаполняется. .

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

Если вам нужно выполнить какие-либо действия после того, как пользователь сделал выбор или закрыл форму, поместите эту логику в код, который обрабатывает Future возвращаемый LoadAndShowConsentFormIfRequired() .

Запросить рекламу

Прежде чем запрашивать рекламу в своем приложении, проверьте, получили ли вы согласие от пользователя с помощью ConsentInfo::GetInstance()‑>CanRequestAds(). При получении согласия необходимо проверить два места:

  1. После того, как согласие было получено в текущем сеансе.
  2. Сразу после того, как вы вызвали RequestConsentInfoUpdate(). Возможно, согласие было получено на предыдущем сеансе. В целях снижения задержки мы рекомендуем не дожидаться завершения обратного вызова, чтобы вы могли начать загрузку рекламы как можно скорее после запуска приложения.

Если в процессе сбора согласия возникает ошибка, вам все равно следует попытаться запросить рекламу. UMP SDK использует статус согласия из предыдущего сеанса.

В следующем полном примере используется опрос цикла обновления, но вы также можете использовать обратные вызовы OnCompletion для мониторинга асинхронных операций. Используйте тот метод, который лучше соответствует вашей структуре кода.

#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;
      }
    }
  }
}

Параметры конфиденциальности

Некоторые формы согласия требуют от пользователя изменить свое согласие в любое время. При необходимости выполните следующие действия, чтобы добавить кнопку параметров конфиденциальности.

Для этого:

  1. Реализуйте элемент пользовательского интерфейса, например кнопку на странице настроек вашего приложения, который может запускать форму параметров конфиденциальности.
  2. После завершения работы LoadAndShowConsentFormIfRequired() проверьтеgetPrivacyOptionsRequirementStatus() , чтобы определить, отображать ли элемент пользовательского интерфейса, который может отображать форму параметров конфиденциальности.
  3. Когда пользователь взаимодействует с вашим элементом пользовательского интерфейса, вызовитеshowPrivacyOptionsForm() чтобы отобразить форму, чтобы пользователь мог обновить свои параметры конфиденциальности в любое время.

Тестирование

Если вы хотите протестировать интеграцию в своем приложении во время разработки, выполните следующие действия, чтобы программно зарегистрировать свое тестовое устройство. Обязательно удалите код, который устанавливает эти идентификаторы тестовых устройств, прежде чем выпускать приложение.

  1. Вызовите RequestConsentInfoUpdate().
  2. Проверьте вывод журнала на наличие сообщения, похожего на следующий пример, в котором показан идентификатор вашего устройства и способы его добавления в качестве тестового устройства:

    Андроид

    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. Скопируйте идентификатор тестового устройства в буфер обмена.

  4. Измените свой код на , установите для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 предоставляет возможность протестировать поведение вашего приложения, как если бы устройство находилось в ЕЭЗ или Великобритании, с помощью ConsentRequestParameters.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();

,

В соответствии с Политикой согласия пользователей Google из ЕС вы должны раскрыть определенную информацию своим пользователям в Европейской экономической зоне (ЕЭЗ), а также в Великобритании, и получить их согласие на использование файлов cookie или другого локального хранилища, если это требуется по закону, а также на использование личных данных ( например AdID) для показа рекламы. Эта политика отражает требования Директивы ЕС об электронной конфиденциальности и Общего регламента защиты данных (GDPR).

Чтобы помочь издателям выполнять свои обязанности в соответствии с этой политикой, Google предлагает SDK User Messaging Platform (UMP). UMP SDK был обновлен для поддержки новейших стандартов IAB. Всеми этими конфигурациями теперь можно удобно управлять в разделе конфиденциальности и обмена сообщениями AdMob .

Предварительные условия

  • Android API уровня 21 или выше(для Android)

Создайте тип сообщения

Создавайте пользовательские сообщения, используя один из доступных типов сообщений пользователяна вкладке Конфиденциальность и обмен сообщениями вашей учетной записиAdMob. UMP SDK пытается отобразить сообщение пользователя, созданное на основе идентификатора приложения AdMob ​​установленного в вашем проекте. Если для вашего приложения не настроено сообщение, SDK возвращает ошибку.

Дополнительные сведения см.О конфиденциальности и обмене сообщениями .

Установите SDK

  1. Следуйте инструкциям по установке Google Mobile Ads (GMA) C++ SDK . UMP C++ SDK включен в GMA C++ SDK.

  2. Прежде чем продолжить, убедитесь, что вы настроили идентификатор приложения AdMob в проекте.

  3. В своем коде инициализируйте UMP SDK, вызвав ConsentInfo::GetInstance() .

    • На Android вам необходимо передать JNIEnv и Activity , предоставленные NDK. Вам нужно сделать это только при первом вызове GetInstance() .
    • В качестве альтернативы, если вы уже используете Firebase C++ SDK в своем приложении, вы можете передать firebase::App при первом вызове 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
    

Последующие вызовы ConsentInfo::GetInstance() возвращают один и тот же экземпляр.

Если вы закончили использовать UMP SDK, вы можете закрыть SDK, удалив экземпляр ConsentInfo :

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

Используйте Future для мониторинга асинхронных операций

firebase::Future предоставляет вам возможность определить статус завершения вызовов асинхронных методов.

Все функции и вызовы методов UMP C++, которые работают асинхронно, возвращают Future , а также предоставляют функцию «последнего результата» для получения Future из самой последней операции.

Есть два способа получить результат из Future :

  1. Вызовите OnCompletion() , передав собственную функцию обратного вызова, которая вызывается после завершения операции.
  2. Периодически проверяйте статус Future status() . Когда статус меняется с kFutureStatusPending на kFutureStatusCompleted , операция завершена.

После завершения асинхронной операции вам следует проверить функцию Future error() , чтобы получить код ошибки операции. Если код ошибки равен 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/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.
      }
    });
}

См . выше пример проверки завершения с использованием опроса цикла обновления, а не обратного вызова завершения.

Загрузите и покажите форму согласия, если требуется.

После получения последней версии статуса согласия вызовитеLoadAndShowConsentFormIfRequired() в классеConsentInfo чтобы загрузить форму согласия. Если требуется статус согласия, SDK загружает форму и немедленно представляет ее из предоставленного FormParent. Futureзавершается. после закрытия формы. Если согласие не требуется, Futureзаполняется. .

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

Если вам нужно выполнить какие-либо действия после того, как пользователь сделал выбор или закрыл форму, поместите эту логику в код, который обрабатывает Future возвращаемый LoadAndShowConsentFormIfRequired() .

Запросить рекламу

Прежде чем запрашивать рекламу в своем приложении, проверьте, получили ли вы согласие от пользователя с помощью ConsentInfo::GetInstance()‑>CanRequestAds(). При получении согласия необходимо проверить два места:

  1. После того, как согласие было получено в текущем сеансе.
  2. Сразу после того, как вы вызвали RequestConsentInfoUpdate(). Возможно, согласие было получено на предыдущем сеансе. В целях снижения задержки мы рекомендуем не дожидаться завершения обратного вызова, чтобы вы могли начать загрузку рекламы как можно скорее после запуска приложения.

Если в процессе сбора согласия возникает ошибка, вам все равно следует попытаться запросить рекламу. UMP SDK использует статус согласия из предыдущего сеанса.

В следующем полном примере используется опрос цикла обновления, но вы также можете использовать обратные вызовы OnCompletion для мониторинга асинхронных операций. Используйте тот метод, который лучше соответствует вашей структуре кода.

#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;
      }
    }
  }
}

Параметры конфиденциальности

Некоторые формы согласия требуют от пользователя изменить свое согласие в любое время. При необходимости выполните следующие действия, чтобы добавить кнопку параметров конфиденциальности.

Для этого:

  1. Реализуйте элемент пользовательского интерфейса, например кнопку на странице настроек вашего приложения, который может запускать форму параметров конфиденциальности.
  2. После завершения работы LoadAndShowConsentFormIfRequired() проверьтеgetPrivacyOptionsRequirementStatus() , чтобы определить, отображать ли элемент пользовательского интерфейса, который может отображать форму параметров конфиденциальности.
  3. Когда пользователь взаимодействует с вашим элементом пользовательского интерфейса, вызовитеshowPrivacyOptionsForm() чтобы отобразить форму, чтобы пользователь мог обновить свои параметры конфиденциальности в любое время.

Тестирование

Если вы хотите протестировать интеграцию в своем приложении во время разработки, выполните следующие действия, чтобы программно зарегистрировать свое тестовое устройство. Обязательно удалите код, который устанавливает эти идентификаторы тестовых устройств, прежде чем выпускать приложение.

  1. Вызовите RequestConsentInfoUpdate().
  2. Проверьте вывод журнала на наличие сообщения, похожего на следующий пример, в котором показан идентификатор вашего устройства и способы его добавления в качестве тестового устройства:

    Андроид

    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. Скопируйте идентификатор тестового устройства в буфер обмена.

  4. Измените свой код на , установите для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 предоставляет возможность протестировать поведение вашего приложения, как если бы устройство находилось в ЕЭЗ или Великобритании, с помощью ConsentRequestParameters.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();