Começar

De acordo com a Política de consentimento de usuários da União Europeia do Google, você precisa divulgar algumas informações aos seus usuários no Espaço Econômico Europeu (EEE) e no Reino Unido. Além disso, é necessário solicitar o consentimento deles para usar cookies ou outro armazenamento local (quando exigido por lei) e usar dados pessoais (como o ID de publicidade) para veicular anúncios. Essa política reflete os requisitos da Diretiva de privacidade eletrônica da UE e do Regulamento geral de proteção de dados (GDPR).

Para ajudar os editores a cumprir as obrigações de acordo com essa política, o Google oferece o SDK da plataforma de mensagens aos usuários (UMP). O SDK da UMP foi atualizado para oferecer suporte aos padrões mais recentes do IAB. Todas essas configurações agora podem ser gerenciadas na AdMob privacidade e mensagens.

Pré-requisitos

  • API do Android de nível 21 ou mais recente (para Android)

Criar um tipo de mensagem

Crie mensagens para os usuários com um dos tipos de mensagens disponíveis na guia Privacidade e mensagens da sua conta da AdMob O SDK da UMP tenta mostrar uma mensagem do usuário criada com base no AdMob ID do aplicativo definido no projeto. Se nenhuma mensagem for configurada para o aplicativo, o SDK retornará um erro.

Para mais detalhes, consulte Sobre privacidade e mensagens.

Instalar o SDK

  1. Siga as etapas para instalar o SDK dos anúncios para dispositivos móveis do Google (GMA) para C++. O SDK da UMP para C++ está incluído no SDK do GMA para C++.

  2. Configure o ID do app AdMob do seu app no projeto antes de continuar.

  3. No seu código, inicialize o SDK da UMP chamando ConsentInfo::GetInstance().

    • No Android, você precisa transmitir o JNIEnv e o Activity fornecidos pelo NDK. Você só precisa fazer isso na primeira vez que chamar GetInstance().
    • Como alternativa, se você já estiver usando o SDK do Firebase para C++ no seu app, é possível transmitir um firebase::App na primeira vez que chamar 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
    

As chamadas subsequentes para ConsentInfo::GetInstance() retornam a mesma instância.

Se você terminar de usar o SDK da UMP, encerre o SDK excluindo a instância ConsentInfo:

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

Usar um Future para monitorar operações assíncronas

Um firebase::Future oferece uma maneira de determinar o status de conclusão das chamadas de método assíncronas.

Todas as chamadas de método e funções C++ da UMP que operam de forma assíncrona retornam um Future e também fornecem uma função de "último resultado" para extrair o Future da operação mais recente.

Há duas maneiras de conferir um resultado de uma Future:

  1. Chame OnCompletion(), transmitindo sua própria função de callback, que é chamada quando a operação é concluída.
  2. Verifique o status() do Future periodicamente. Quando o status muda de kFutureStatusPending para kFutureStatusCompleted, a operação foi concluída.

Após a conclusão da operação assíncrona, verifique o error() do Future para receber o código de erro da operação. Se o código do erro for 0 (kConsentRequestSuccess ou kConsentFormSuccess), a operação foi concluída com sucesso. Caso contrário, verifique o código do erro e error_message() para determinar o que deu errado.

Callback de conclusão

Confira um exemplo de como usar OnCompletion para definir um callback de conclusão, que é chamado quando a operação assíncrona é concluída.

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

Atualizar sondagem de loop

Neste exemplo, depois que uma operação assíncrona é iniciada na inicialização do app, os resultados são verificados em outro lugar, na função de loop de atualização do jogo, que é executada uma vez por frame.

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

Para mais informações sobre firebase::Future, consulte a documentação do SDK do Firebase para C++ e a documentação do SDK do GMA para C++.

Solicite uma atualização das informações de consentimento do usuário a cada inicialização do app usando RequestConsentInfoUpdate(). Isso determina se o usuário precisa dar o consentimento, caso ainda não tenha feito isso ou se o consentimento expirou.

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

Consulte acima um exemplo de verificação da conclusão usando a pesquisa de loop de atualização em vez de um callback de conclusão.

Carregar e mostrar um formulário de consentimento, se necessário

Depois de receber o status de consentimento mais atualizado, chameLoadAndShowConsentFormIfRequired() na classeConsentInfo para carregar um formulário de consentimento. Se o status de consentimento for obrigatório, o SDK vai carregar um formulário e apresentar imediatamente do FormParentfornecido. A chamada Future é concluída depois que o formulário é dispensado. Se o consentimento não for necessário, a Future será concluída imediatamente.

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

Se você precisar executar alguma ação depois que o usuário fizer uma escolha ou dispensar o formulário, coloque essa lógica no código que processa o Future retornado por LoadAndShowConsentFormIfRequired().

Solicitar anúncios

Antes de solicitar anúncios no seu app, verifique se você recebeu o consentimento do usuário usando ConsentInfo::GetInstance()‑>CanRequestAds(). Há dois lugares para verificar ao solicitar o consentimento:

  1. Depois que o consentimento for coletado na sessão atual.
  2. Imediatamente depois de chamar RequestConsentInfoUpdate(). É possível que o consentimento tenha sido obtido na sessão anterior. Como prática recomendada de latência, não aguarde a conclusão do callback para que você possa começar a carregar anúncios assim que possível após o lançamento do app.

Se ocorrer um erro durante o processo de solicitação de consentimento, ainda assim tente solicitar anúncios. O SDK da UMP usa o status de consentimento da sessão anterior.

O exemplo completo a seguir usa a pesquisa de loop de atualização, mas é possível também usar callbacks OnCompletion para monitorar operações assíncronas. Use a técnica mais adequada à estrutura do seu código.

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

Opções de privacidade

Alguns formulários de consentimento exigem que o usuário modifique o consentimento a qualquer momento. Siga as etapas abaixo para implementar um botão de opções de privacidade, se necessário.

Para fazer isso:

  1. Implemente um elemento da interface, como um botão na página de configurações do app, que possa acionar um formulário de opções de privacidade.
  2. Quando a LoadAndShowConsentFormIfRequired() for concluída, verifique getPrivacyOptionsRequirementStatus() para determinar se o elemento da interface que pode apresentar o formulário de opções de privacidade será mostrado.
  3. Quando um usuário interagir com o elemento da interface, chame showPrivacyOptionsForm() para mostrar o formulário. Assim, o usuário pode atualizar as opções de privacidade a qualquer momento.

testes

Se você quiser testar a integração no app durante o desenvolvimento, siga estas etapas para registrar o dispositivo de teste de forma programática. Remova o código que define esses IDs de dispositivo de teste antes de lançar o app.

  1. Chame RequestConsentInfoUpdate().
  2. Verifique a saída do registro para encontrar uma mensagem semelhante ao exemplo a seguir, que mostra o ID do dispositivo e como adicioná-lo como um dispositivo de teste:

    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. Copie o ID do dispositivo de teste para a área de transferência.

  4. Modifique seu código para definir ConsentRequestParameters.debug_settings.debug_device_ids para uma lista dos IDs dos dispositivos de teste.

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

Forçar uma região geográfica

O SDK da UMP oferece uma maneira de testar o comportamento do app como se o dispositivo estivesse localizado no EEE ou no Reino Unido usando ConsentRequestParameters.debug_settings.debug_geography. As configurações de depuração só funcionam em dispositivos de teste.

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

Ao testar seu app com o SDK da UMP, pode ser útil redefinir o estado do SDK para que você possa simular a primeira experiência de instalação de um usuário. O SDK fornece o método Reset() para fazer isso.

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