بموجب سياسة موافقة المستخدم في الاتحاد الأوروبي التي تتّبعها Google، يجب الإفصاح عن معلومات معيّنة للمستخدمين في المنطقة الاقتصادية الأوروبية (EEA) والمملكة المتحدة والحصول على موافقتهم على استخدام ملفات تعريف الارتباط أو غير ذلك من البيانات المحفوظة على أجهزتهم المحلية حسب ما يقتضيه القانون، وعلى استخدام البيانات الشخصية (مثل AdID) لعرض الإعلانات. تعكس هذه السياسة شروط "التوجيه الأوروبي بشأن الخصوصية الإلكترونية" و"اللائحة العامة لحماية البيانات" (GDPR).
لدعم الناشرين في الوفاء بالتزاماتهم بموجب هذه السياسة، تقدّم Google حزمة تطوير البرامج (SDK) لمنصّة User Messaging Platform (UMP). تم تحديث حزمة تطوير البرامج لمنصة UMP لتتوافق مع أحدث معايير IAB. يمكن الآن التعامل مع كل هذه الإعدادات بسهولة في AdMob الخصوصية والمراسلة.
المتطلّبات الأساسية
- أكمِل دليل البدء.
- المستوى 21 من واجهة برمجة تطبيقات Android أو المستويات الأعلى (لنظام التشغيل Android)
- إذا كنت تعمل على استيفاء المتطلبات المتعلّقة باللائحة العامة لحماية البيانات، يُرجى قراءة تأثير متطلّبات مكتب IAB على رسائل طلب موافقة المستخدمين في الاتحاد الأوروبي
إنشاء نوع رسالة
يمكنك إنشاء رسائل المستخدمين باستخدام أحد أنواع رسائل المستخدمين المتوفرة ضمن علامة تبويب الخصوصية والمراسلة في حساب AdMob . تحاول حزمة تطوير البرامج لمنصة UMP عرض رسالة مستخدم تم إنشاؤها من AdMob معرّف التطبيق المحدّد في مشروعك. وفي حال عدم إعداد أي رسالة لتطبيقك، ستعرض حزمة تطوير البرامج (SDK) رسالة خطأ.
لمزيد من التفاصيل، يُرجى الاطّلاع على لمحة عن الخصوصية والمراسلة.
تثبيت حزمة تطوير البرامج (SDK)
اتّبِع خطوات تثبيت حزمة تطوير البرامج (SDK) لإعلانات Google على الأجهزة الجوّالة (GMA). يتم تضمين حزمة تطوير البرامج (SDK) لمنصّة UMP C++ في حزمة تطوير البرامج (SDK) لإعلانات Google على الأجهزة الجوّالة (GMA C++).
تأكّد من ضبط رقم تعريف تطبيق AdMob الخاص بتطبيقك على AdMob في المشروع قبل المتابعة.
في الرمز البرمجي، عليك إعداد حزمة تطوير البرامج (SDK) لمنصّة UMP من خلال طلب الرقم
ConsentInfo::GetInstance()
.- على Android، يجب اجتياز الاختبار في
JNIEnv
وActivity
المقدَّمَين من NDK. عليك إجراء ذلك فقط في المرة الأولى التي تتصل فيها بـGetInstance()
. - بدلاً من ذلك، إذا كنت تستخدم حزمة تطوير البرامج (SDK) من Firebase C++
من Firebase في تطبيقك، يمكنك تمرير
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
- على Android، يجب اجتياز الاختبار في
تعرض جميع المكالمات اللاحقة إلى ConsentInfo::GetInstance()
المثيل نفسه.
إذا انتهيت من استخدام حزمة تطوير البرامج (SDK) لمنصّة 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
، يمكنك الاطّلاع على مستندات حزمة تطوير البرامج (SDK) الخاصة بـ Firebase C++
ومستندات حزمة تطوير البرامج (SDK) لإعلانات Google على الأجهزة الجوّالة (GMA C++ ).
إضافة معرّف التطبيق
يمكنك العثور على رقم تعريف تطبيقك في واجهة مستخدم AdMob. إضافة المعرّف إلى مع مقتطف الرمز التالي:
طلب الحصول على معلومات الموافقة
يجب طلب تعديل لمعلومات موافقة المستخدم في كل مرة يتم فيها تشغيل التطبيق، وذلك باستخدام 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()
". هناك مكانان للتحقق
منهما أثناء جمع الموافقات:
- بعد الحصول على الموافقة في الجلسة الحالية
- فور اتصالك بـ
RequestConsentInfoUpdate()
. من المحتمل أن تكون قد حصلت على موافقة في الجلسة السابقة. ومن أفضل ممارسات وقت الاستجابة، عدم انتظار اكتمال معاودة الاتصال حتى تتمكن من البدء في تحميل الإعلانات في أقرب وقت ممكن بعد إطلاق تطبيقك.
إذا حدث خطأ أثناء عملية الحصول على الموافقات، يجب أن تحاول طلب الإعلانات. تستخدم حزمة تطوير البرامج لمنصّة UMP حالة الموافقة من الجلسة السابقة.
يستخدم المثال الكامل التالي الاستطلاع المتكرر، ولكن يمكنك أيضًا استخدام استدعاءات 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;
}
}
}
}
خيارات الخصوصية
تتطلّب بعض نماذج الموافقة من المستخدِم تعديل موافقته في أي وقت. التزم بالخطوات التالية لتفعيل زر خيارات الخصوصية إذا لزم الأمر.
ولإجراء ذلك:
- تنفيذ عنصر في واجهة المستخدم، مثل زر في صفحة إعدادات التطبيق، يمكن أن يؤدي إلى ظهور نموذج خيارات الخصوصية
- بعد
LoadAndShowConsentFormIfRequired()
اكتمال البحث، ضَع علامة في المربّعgetPrivacyOptionsRequirementStatus()
لتحديد ما إذا كان سيتم عرض عنصر واجهة المستخدم الذي يمكنه تقديم نموذج خيارات الخصوصية. - عندما يتفاعل أحد المستخدمين مع عنصر واجهة المستخدم، يمكنك طلب
showPrivacyOptionsForm()
لعرض النموذج حتى يتمكن المستخدم من تعديل خيارات الخصوصية في أي وقت.
الاختبار
إذا أردت اختبار التكامل في تطبيقك أثناء تطويره، اتّبِع هذه الخطوات لتسجيل جهاز الاختبار آليًا. واحرص على إزالة الرمز الذي يضبط أرقام تعريف الأجهزة الاختبارية قبل إصدار تطبيقك.
- اتصل على
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); }
فرض موقع جغرافي
توفّر حزمة تطوير البرامج (SDK) لمنصّة UMP وسيلة لاختبار سلوك تطبيقك كما لو كان الجهاز يقع في المنطقة الاقتصادية الأوروبية أو المملكة المتحدة باستخدام 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);
}
إعادة ضبط حالة الموافقة
أثناء اختبار تطبيقك باستخدام حزمة تطوير البرامج (SDK) لمنصّة UMP، قد يكون من المفيد إعادة ضبط
حالة حزمة تطوير البرامج (SDK) كي تتمكّن من محاكاة تجربة التثبيت الأولى للمستخدم.
وتوفّر حزمة تطوير البرامج (SDK) الطريقة Reset()
لإجراء ذلك.
ConsentInfo::GetInstance()->Reset();