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 de receber o consentimento deles para usar cookies ou outro armazenamento local, quando exigido por lei, e usar dados pessoais (como 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 determinadas por essa política, o Google oferece o SDK da plataforma de mensagens aos usuários (UMP, na sigla em inglês). O SDK da UMP foi atualizado para ser compatível com os padrões mais recentes do IAB. Todas essas configurações agora podem ser processadas de maneira conveniente em AdMob Privacidade e mensagens.

Pré-requisitos

  • Nível 21 da API do Android ou mais recente (para Android)

Criar um tipo de mensagem

Crie mensagens para os usuários com um dos tipos de mensagem disponíveis na guia Privacidade e mensagens da sua AdMob . O SDK da UMP tenta exibir uma mensagem de usuário criada a partir do AdMob ID do aplicativo definido no seu 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 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, poderá 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
    

Todas as chamadas seguintes para ConsentInfo::GetInstance() retornam a mesma instância.

Se você terminar de usar o SDK da UMP, encerre-o 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 funções C++ da UMP e chamadas de método que operam de modo assíncrono retornam um Future e também fornecem uma função de "último resultado" para recuperar o Future da operação mais recente.

Há duas maneiras de conseguir um resultado de um Future:

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

Após a conclusão da operação assíncrona, verifique o error() do Future para ver o código do erro da operação. Se o código de erro for 0 (kConsentRequestSuccess ou kConsentFormSuccess), a operação foi concluída com êxito. Caso contrário, verifique o código de 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 pesquisa 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 consentimento caso ainda não tenha feito isso ou tenha expirado.

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

Veja acima um exemplo de verificação da conclusão usando a pesquisa de loop de atualização em vez de um retorno de chamada 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 carregará um formulário e o apresentará imediatamente a partir do FormParentfornecido. O método Future é concluído depois que o formulário é dispensado. Se o consentimento não for necessário, a consulta 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 realizar qualquer ação depois que o usuário fizer uma escolha ou dispensar o formulário, coloque essa lógica no código que processa a Future retornada por LoadAndShowConsentFormIfRequired().

Solicitar anúncios

Antes de solicitar anúncios no seu app, verifique se você recebeu o consentimento do usuário que utiliza ConsentInfo::GetInstance()‑>CanRequestAds(). Há dois locais a serem verificados ao obter o consentimento:

  1. Quando o consentimento for recebido na sessão atual.
  2. Imediatamente após você ter chamado RequestConsentInfoUpdate(). É possível que o consentimento tenha sido dado na sessão anterior. Como prática recomendada de latência, não espere a conclusão do callback para poder começar a carregar anúncios o mais rápido possível após o início do aplicativo.

Se ocorrer um erro durante o processo de solicitação de consentimento, 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 você também pode usar callbacks OnCompletion para monitorar operações assíncronas. Use a técnica que melhor se adapta à sua estrutura de 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 acione um formulário de opções de privacidade.
  2. Após a conclusão de LoadAndShowConsentFormIfRequired() , confira getPrivacyOptionsRequirementStatus() para determinar se o elemento da interface que pode apresentar o formulário de opções de privacidade será mostrado ou não.
  3. Quando um usuário interagir com o elemento da interface, chame showPrivacyOptionsForm() para mostrar o formulário e poder 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 ver uma mensagem semelhante ao exemplo a seguir, que mostra o ID do dispositivo e como adicioná-lo como 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 localização geográfica

O SDK da UMP oferece uma maneira de testar o comportamento do seu 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();