عمليات معاودة الاتصال لعملية تحقّق من جهة الخادم هي طلبات عناوين URL، مع توسيع معلمات طلب البحث من قِبل Google، وترسلها Google إلى نظام خارجي لإعلامه بأنّه يجب منح مكافأة للمستخدم مقابل التفاعل مع إعلان بيني مقابل مكافأة أو إعلان مقابل مكافأة. توفّر عمليات معاودة الاتصال لإثبات الملكية من جانب الخادم للإعلانات مقابل مكافأة طبقة حماية إضافية ضدّ انتحال عمليات معاودة الاتصال من جانب العميل لمنح مكافآت للمستخدمين.
يوضّح هذا الدليل كيفية التحقّق من عمليات معاودة الاتصال لإثبات الملكية من جانب الخادم للإعلانات مقابل مكافأة باستخدام الـ Tink Java Apps مكتبة التشفير التابعة لجهة خارجية لضمان أنّ معلَمات طلب البحث في عملية معاودة الاتصال هي قيم مشروعة. على الرغم من استخدام Tink لأغراض هذا الدليل، يمكنك استخدام أيّ مكتبة تابعة لجهة خارجية تتيح خوارزمية ECDSA. يمكنك أيضًا اختبار الخادم باستخدام أداة الاختبار في واجهة مستخدم AdMob.
المتطلبات الأساسية
- تفعيل ميزة إثبات الملكية من جانب الخادم للإعلانات مقابل مكافأة على وحدتك الإعلانية
استخدام RewardedAdsVerifier من مكتبة تطبيقات Tink Java
يتضمّن مستودع Tink Java Apps على GitHub
فئة مساعِدة هي
RewardedAdsVerifier
لتقليل الرمز البرمجي المطلوب للتحقّق من عملية معاودة الاتصال لإثبات الملكية من جانب الخادم للإعلانات مقابل مكافأة.
يتيح لك استخدام هذه الفئة التحقّق من عنوان URL لمعاودة الاتصال باستخدام الرمز البرمجي التالي.
RewardedAdsVerifier verifier = new RewardedAdsVerifier.Builder()
.fetchVerifyingPublicKeysWith(
RewardedAdsVerifier.KEYS_DOWNLOADER_INSTANCE_PROD)
.build();
String rewardUrl = ...;
verifier.verify(rewardUrl);
إذا تمّ تنفيذ طريقة verify() بدون ظهور استثناء، تمّ التحقّق من عنوان URL لمعاودة الاتصال بنجاح. يقدّم قسم منح مكافأة للمستخدم
أفضل الممارسات المتعلّقة بالوقت الذي يجب فيه منح مكافأة للمستخدمين. للاطّلاع على تفاصيل الخطوات التي تتّبعها هذه الفئة للتحقّق من عمليات معاودة الاتصال لإثبات الملكية من جانب الخادم للإعلانات مقابل مكافأة،
يمكنك قراءة قسم التحقّق اليدوي من عمليات معاودة الاتصال لإثبات الملكية من جانب الخادم للإعلانات مقابل مكافأة.
مَعلمات معاودة الاتصال لإثبات الملكية من جانب الخادم
تحتوي عمليات معاودة الاتصال لإثبات الملكية من جانب الخادم على معلَمات طلب بحث تصف التفاعل مع الإعلان مقابل مكافأة. في ما يلي أسماء المَعلمات وأوصافها وأمثلة على قيمها. يتم إرسال المَعلمات بترتيب أبجدي.
| اسم المَعلمة | الوصف | مثال على القيمة |
|---|---|---|
| ad_network | مُعرّف مصدر الإعلان لمصدر الإعلان الذي عرض هذا الإعلان تظهر أسماء مصادر الإعلانات المقابلة لقيم رقم التعريف في قسم مُعرّفات مصادر الإعلانات. | 1953547073528090325 |
| ad_unit | رقم تعريف الوحدة الإعلانية في AdMob الذي تمّ استخدامه لطلب الإعلان مقابل مكافأة | 2747237135 |
| custom_data | سلسلة البيانات المخصّصة كما يقدّمها
customData.
إذا لم يقدّم التطبيق سلسلة بيانات مخصّصة، لن تظهر قيمة معلَمة طلب البحث هذه في عملية معاودة الاتصال لإثبات الملكية من جانب الخادم. |
SAMPLE_CUSTOM_DATA_STRING |
| key_id | المفتاح الذي سيتمّ استخدامه للتحقّق من عملية معاودة الاتصال لإثبات الملكية من جانب الخادم ترتبط هذه القيمة بمفتاح عام يقدّمه خادم مفاتيح AdMob. | 1234567890 |
| reward_amount | مبلغ المكافأة كما هو محدّد في إعدادات الوحدة الإعلانية | 5 |
| reward_item | عنصر المكافأة كما هو محدّد في إعدادات الوحدة الإعلانية | عملات معدنية |
| signature | توقيع عملية معاودة الاتصال لإثبات الملكية من جانب الخادم الذي أنشأته AdMob | MEUCIQCLJS_s4ia_sN06HqzeW7Wc3nhZi4RlW3qV0oO-6AIYdQIgGJEh-rzKreO-paNDbSCzWGMtmgJHYYW9k2_icM9LFMY |
| timestamp | الطابع الزمني لوقت منح المكافأة للمستخدم، بتنسيق وقت Epoch بالملّي ثانية | 1507770365237823 |
| transaction_id | مُعرّف فريد مُرمَّز بنظام العدّ السداسي العشري لكلّ حدث منح مكافأة تنشئه AdMob | 18fa792de1bca816048293fc71035638 |
| user_id | مُعرّف المستخدم كما يقدّمه
userId.
إذا لم يقدّم التطبيق مُعرّف مستخدم، لن تظهر معلَمة طلب البحث هذه في عملية معاودة الاتصال لإثبات الملكية من جانب الخادم. |
1234567 |
مُعرّفات مصادر الإعلانات
أسماء مصادر الإعلانات وأرقام تعريفها
| اسم مصدر الإعلان | رقم تعريف مصدر الإعلان |
|---|---|
| Ad Generation (عروض الأسعار) | 1477265452970951479 |
| شبكة AdMob | 5450213213286189855 |
| العرض الإعلاني بدون انقطاع في شبكة AdMob | 1215381445328257950 |
| AppLovin | 1063618907739174004 |
| AppLovin (عروض الأسعار) | 1328079684332308356 |
| Bidease (عروض الأسعار) | 3670825090829827805 |
| BidMachine (عروض الأسعار) | 7943972370566394673 |
| Chartboost | 2873236629771172317 |
| Chocolate Platform (عروض الأسعار) | 6432849193975106527 |
| حدث مخصّص | 18351550913290782395 |
| DT Exchange* * قبل 21 سبتمبر 2022، كانت هذه الشبكة تُعرف باسم "Fyber Marketplace". | 2179455223494392917 |
| DT Exchange (عروض الأسعار) | 8189833498765234879 |
| Equativ (عروض الأسعار)* * قبل 12 يناير 2023، كانت هذه الشبكة تُعرف باسم "Smart Adserver". | 5970199210771591442 |
| Fluct (عروض الأسعار) | 8419777862490735710 |
| i-mobile | 5208827440166355534 |
| Improve Digital (عروض الأسعار) | 159382223051638006 |
| Index Exchange (عروض الأسعار) | 4100650709078789802 |
| InMobi | 7681903010231960328 |
| InMobi (حزمة تطوير البرامج) (عروض الأسعار) | 8468954295581492586 |
| InMobi Exchange (عروض الأسعار) | 5264320421916134407 |
| ironSource Ads | 6925240245545091930 |
| ironSource Ads (عروض الأسعار) | 1643326773739866623 |
| Liftoff Monetize* * قبل 30 يناير 2023، كانت هذه الشبكة تُعرف باسم "Vungle". | 1953547073528090325 |
| Liftoff Monetize (عروض الأسعار)* * قبل 30 يناير 2023، كانت هذه الشبكة تُعرف باسم "Vungle (عروض الأسعار)". | 4692500501762622185 |
| شبكة إعلانات LY | 3025503711505004547 |
| شبكة إعلانات LY (عروض الأسعار) | 2615812619460460513 |
| Magnite DV+ (عروض الأسعار) | 3993193775968767067 |
| maio | 7505118203095108657 |
| Media.net (عروض الأسعار) | 2127936450554446159 |
| الإعلانات الذاتية المعتمَدة على التوسّط | 6060308706800320801 |
| Meta Audience Network* * قبل 6 يونيو 2022، كانت هذه الشبكة تُعرف باسم "Facebook Audience Network". | 10568273599589928883 |
| Meta Audience Network (عروض الأسعار)* * قبل 6 يونيو 2022، كانت هذه الشبكة تُعرف باسم "Facebook Audience Network (عروض الأسعار)". | 11198165126854996598 |
| Mintegral | 1357746574408896200 |
| Mintegral (عروض الأسعار) | 6250601289653372374 |
| Mobfox (عروض الأسعار) | 3086513548163922365 |
| MobileFuse (عروض الأسعار) | 7303547408604090310 |
| Moloco Ads SDK (عروض الأسعار) | 8267622065755668722 |
| myTarget | 8450873672465271579 |
| Nativo (عروض الأسعار) | 3240503836211327896 |
| Nexxen (عروض الأسعار)* * قبل 1 مايو 2024، كانت هذه الشبكة تُعرف باسم "UnrulyX". | 2831998725945605450 |
| OneTag Exchange (عروض الأسعار) | 4873891452523427499 |
| OpenX (عروض الأسعار) | 4918705482605678398 |
| Pangle | 4069896914521993236 |
| Pangle KR SDK (عروض الأسعار) | 12171279046073404914 |
| Pangle ROW SDK (عروض الأسعار) | 3525379893916449117 |
| Pangle US SDK (عروض الأسعار) | 15999446638585856012 |
| PubMatic (عروض الأسعار) | 3841544486172445473 |
| حزمة SDK الخاصة بمنصة PubMatic OpenWrap | 7702975372504485373 |
| حزمة SDK الخاصة بمنصة PubMatic OpenWrap (عروض الأسعار) | 1234567890123456789 |
| حملة قائمة على الحجز | 7068401028668408324 |
| Rise (عروض الأسعار) | 6816468518946650043 |
| Sharethrough (عروض الأسعار) | 5247944089976324188 |
| Smaato (عروض الأسعار) | 3362360112145450544 |
| Sonobi (عروض الأسعار) | 3270984106996027150 |
| TripleLift (عروض الأسعار) | 8332676245392738510 |
| Unity Ads | 4970775877303683148 |
| Unity Ads (عروض الأسعار) | 7069338991535737586 |
| Verve Group (عروض الأسعار) | 5013176581647059185 |
| Vpon | 1940957084538325905 |
| Yieldmo (عروض الأسعار) | 4193081836471107579 |
| YieldOne (عروض الأسعار) | 3154533971590234104 |
| Zucks | 5506531810221735863 |
منح مكافأة للمستخدم
من المهمّ تحقيق التوازن بين تجربة المستخدم والتحقّق من المكافأة عند تحديد وقت منح مكافأة للمستخدم. قد يحدث تأخير في وصول عمليات معاودة الاتصال من جهة الخادم إلى الأنظمة الخارجية. لذلك، ننصحك باستخدام عملية معاودة الاتصال من جهة العميل لمنح مكافأة للمستخدم على الفور، مع إجراء عملية التحقّق من جميع المكافآت عند تلقّي عمليات معاودة الاتصال من جهة الخادم. يوفّر هذا النهج تجربة مستخدم جيدة مع ضمان صحة المكافآت الممنوحة.
مع ذلك، بالنسبة إلى التطبيقات التي تكون فيها صحة المكافأة مهمّة (على سبيل المثال، إذا كانت المكافأة تؤثّر في الاقتصاد داخل اللعبة في تطبيقك) وكان التأخير في منح المكافآت مقبولاً، قد يكون الانتظار إلى حين تلقّي عملية معاودة الاتصال التي تمّ التحقّق منها من جهة الخادم هو النهج الأفضل.
البيانات المخصّصة
يجب أن تستخدم التطبيقات التي تتطلّب بيانات إضافية في عمليات معاودة الاتصال لعملية تحقّق من جهة الخادم ميزة البيانات المخصّصة للإعلانات مقابل مكافأة. يتمّ تمرير أيّ قيمة سلسلة يتمّ ضبطها على عنصر إعلان مقابل مكافأة إلى معلَمة طلب البحث custom_data في عملية معاودة الاتصال لإثبات الملكية من جانب الخادم. إذا لم يتمّ ضبط قيمة بيانات مخصّصة، لن تظهر قيمة معلَمة طلب البحث custom_data في عملية معاودة الاتصال لإثبات الملكية من جانب الخادم.
يضبط المثال التالي خيارات إثبات الملكية من جانب الخادم بعد تحميل الإعلان مقابل مكافأة:
استبدِل SAMPLE_CUSTOM_DATA_STRING ببياناتك المخصّصة.
إذا أردت ضبط سلسلة المكافأة المخصّصة، عليك إجراء ذلك قبل عرض الإعلان.
التحقّق اليدوي من عمليات معاودة الاتصال لإثبات الملكية من جانب الخادم للإعلانات مقابل مكافأة
في ما يلي الخطوات التي تتّبعها فئة RewardedAdsVerifier للتحقّق من عملية معاودة الاتصال لإثبات الملكية من جانب الخادم للإعلانات مقابل مكافأة. على الرغم من أنّ مقتطفات الرموز البرمجية المضمّنة مكتوبة بلغة Java و
تستخدِم مكتبة Tink التابعة لجهة خارجية، يمكنك تنفيذ هذه الخطوات باللغة التي تختارها، باستخدام أيّ مكتبة تابعة لجهة خارجية تتيح
ECDSA.
جلب المفاتيح العامة
للتحقّق من عملية معاودة الاتصال لإثبات الملكية من جانب الخادم للإعلانات مقابل مكافأة، تحتاج إلى مفتاح عام يقدّمه AdMob.
يمكن جلب قائمة بالمفاتيح العامة التي سيتمّ استخدامها للتحقّق من عمليات معاودة الاتصال لإثبات الملكية من جانب الخادم للإعلانات مقابل مكافأة من خادم مفاتيح AdMob AdMob. يتمّ تقديم قائمة المفاتيح العامة كتمثيل JSON بتنسيق مشابه للتنسيق التالي:
{
"keys": [
{
keyId: 1916455855,
pem: "-----BEGIN PUBLIC KEY-----\nMF...YTPcw==\n-----END PUBLIC KEY-----"
base64: "MFkwEwYHKoZIzj0CAQYI...ltS4nzc9yjmhgVQOlmSS6unqvN9t8sqajRTPcw=="
},
{
keyId: 3901585526,
pem: "-----BEGIN PUBLIC KEY-----\nMF...aDUsw==\n-----END PUBLIC KEY-----"
base64: "MFYwEAYHKoZIzj0CAQYF...4akdWbWDCUrMMGIV27/3/e7UuKSEonjGvaDUsw=="
},
],
}
لاسترداد المفاتيح العامة، اتّصِل بخادم مفاتيح AdMob ونزِّل المفاتيح. ينفّذ الرمز البرمجي التالي هذه المهمّة ويحفظ تمثيل JSON للمفاتيح في المتغيّر data.
String url = ...;
NetHttpTransport httpTransport = new NetHttpTransport.Builder().build();
HttpRequest httpRequest =
httpTransport.createRequestFactory().buildGetRequest(new GenericUrl(url));
HttpResponse httpResponse = httpRequest.execute();
if (httpResponse.getStatusCode() != HttpStatusCodes.STATUS_CODE_OK) {
throw new IOException("Unexpected status code = " + httpResponse.getStatusCode());
}
String data;
InputStream contentStream = httpResponse.getContent();
try {
InputStreamReader reader = new InputStreamReader(contentStream, UTF_8);
data = readerToString(reader);
} finally {
contentStream.close();
}
يُرجى العِلم أنّه يتمّ تدوير المفاتيح العامة بانتظام. ستتلقّى رسالة إلكترونية لإعلامك بعملية التدوير القادمة. إذا كنت تخزّن المفاتيح العامة مؤقتًا، عليك تعديل المفاتيح عند تلقّي هذه الرسالة الإلكترونية.
بعد جلب المفاتيح العامة، يجب تحليلها. تأخذ طريقة parsePublicKeysJson أدناه سلسلة JSON، مثل المثال أعلاه، كإدخال، وتنشئ ربطًا من قيم key_id بالمفاتيح العامة، التي يتمّ تغليفها كعناصر ECPublicKey من مكتبة Tink.
private static Map<Integer, ECPublicKey> parsePublicKeysJson(String publicKeysJson)
throws GeneralSecurityException {
Map<Integer, ECPublicKey> publicKeys = new HashMap<>();
try {
JSONArray keys = new JSONObject(publicKeysJson).getJSONArray("keys");
for (int i = 0; i < keys.length(); i++) {
JSONObject key = keys.getJSONObject(i);
publicKeys.put(
key.getInt("keyId"),
EllipticCurves.getEcPublicKey(Base64.decode(key.getString("base64"))));
}
} catch (JSONException e) {
throw new GeneralSecurityException("failed to extract trusted signing public keys", e);
}
if (publicKeys.isEmpty()) {
throw new GeneralSecurityException("No trusted keys are available.");
}
return publicKeys;
}
الحصول على المحتوى الذي سيتمّ التحقّق منه
آخر معلَمتَي طلب بحث في عمليات معاودة الاتصال لإثبات الملكية من جانب الخادم للإعلانات مقابل مكافأة هما دائمًا signature وkey_id, بهذا الترتيب. تحدّد معلَمات طلب البحث المتبقية المحتوى الذي سيتمّ التحقّق منه. لنفترض أنّك ضبطت AdMob لإرسال عمليات معاودة الاتصال لمنح المكافآت إلى https://www.myserver.com/mypath. يعرض المقتطف أدناه مثالاً على عملية معاودة الاتصال لإثبات الملكية من جانب الخادم للإعلانات مقابل مكافأة مع تمييز المحتوى الذي سيتمّ التحقّق منه.
https://www.myserver.com/path?ad_network=54...55&ad_unit=12345678&reward_amount=10&reward_item=coins ×tamp=150777823&transaction_id=12...DEF&user_id=1234567&signature=ME...Z1c&key_id=1268887
يوضّح الرمز البرمجي أدناه كيفية تحليل المحتوى الذي سيتمّ التحقّق منه من عنوان URL لمعاودة الاتصال كمصفوفة بايت بتنسيق UTF-8.
public static final String SIGNATURE_PARAM_NAME = "signature=";
...
URI uri;
try {
uri = new URI(rewardUrl);
} catch (URISyntaxException ex) {
throw new GeneralSecurityException(ex);
}
String queryString = uri.getQuery();
int i = queryString.indexOf(SIGNATURE_PARAM_NAME);
if (i == -1) {
throw new GeneralSecurityException("needs a signature query parameter");
}
byte[] queryParamContentData =
queryString
.substring(0, i - 1)
// i - 1 instead of i because of & in the query string
.getBytes(Charset.forName("UTF-8"));
الحصول على التوقيع وkey_id من عنوان URL لمعاودة الاتصال
باستخدام قيمة queryString من الخطوة السابقة، حلِّل معلَمتَي طلب البحث signature وkey_id من عنوان URL لمعاودة الاتصال كما هو موضّح أدناه:
public static final String KEY_ID_PARAM_NAME = "key_id=";
...
String sigAndKeyId = queryString.substring(i);
i = sigAndKeyId.indexOf(KEY_ID_PARAM_NAME);
if (i == -1) {
throw new GeneralSecurityException("needs a key_id query parameter");
}
String sig =
sigAndKeyId.substring(
SIGNATURE_PARAM_NAME.length(), i - 1 /* i - 1 instead of i because of & */);
int keyId = Integer.valueOf(sigAndKeyId.substring(i + KEY_ID_PARAM_NAME.length()));
إجراء عملية التحقّق
الخطوة الأخيرة هي التحقّق من محتوى عنوان URL لمعاودة الاتصال باستخدام المفتاح العام المناسب. استخدِم الربط الذي تمّ عرضه من طريقة parsePublicKeysJson واستخدِم معلَمة key_id من عنوان URL لمعاودة الاتصال للحصول على المفتاح العام من هذا الربط. بعد ذلك، تحقَّق من التوقيع باستخدام هذا المفتاح العام. يتمّ توضيح هذه الخطوات أدناه في طريقة verify.
private void verify(final byte[] dataToVerify, int keyId, final byte[] signature)
throws GeneralSecurityException {
Map<Integer, ECPublicKey> publicKeys = parsePublicKeysJson();
if (publicKeys.containsKey(keyId)) {
foundKeyId = true;
ECPublicKey publicKey = publicKeys.get(keyId);
EcdsaVerifyJce verifier = new EcdsaVerifyJce(publicKey, HashType.SHA256, EcdsaEncoding.DER);
verifier.verify(signature, dataToVerify);
} else {
throw new GeneralSecurityException("cannot find verifying key with key ID: " + keyId);
}
}
إذا تمّ تنفيذ الطريقة بدون ظهور استثناء، تمّ التحقّق من عنوان URL لمعاودة الاتصال بنجاح.
الأسئلة الشائعة
- هل يمكنني تخزين المفتاح العام الذي يقدّمه خادم مفاتيح AdMob مؤقتًا؟
- ننصحك بتخزين المفتاح العام الذي يقدّمه خادم مفاتيح AdMob مؤقتًا لتقليل عدد العمليات المطلوبة للتحقّق من عمليات معاودة الاتصال لإثبات الملكية من جانب الخادم. مع ذلك، يُرجى العِلم أنّه يتمّ تدوير المفاتيح العامة بانتظام ويجب عدم تخزينها مؤقتًا لأكثر من 24 ساعة.
- ما هو معدّل تدوير المفاتيح العامة التي يقدّمها خادم مفاتيح AdMob؟
- يتمّ تدوير المفاتيح العامة التي يقدّمها خادم مفاتيح AdMob وفقًا لجدول زمني متغيّر. لضمان استمرار عمل التحقّق من عمليات معاودة الاتصال لإثبات الملكية من جانب الخادم على النحو المطلوب، يجب عدم تخزين المفاتيح العامة مؤقتًا لأكثر من 24 ساعة.
- ماذا يحدث إذا تعذّر الوصول إلى الخادم؟
- تتوقّع Google رمز استجابة لحالة النجاح
HTTP 200 OKلعمليات معاودة الاتصال لإثبات الملكية من جانب الخادم. إذا تعذّر الوصول إلى الخادم أو لم يقدّم الاستجابة المتوقّعة، ستعيد Google محاولة إرسال عمليات معاودة الاتصال لإثبات الملكية من جانب الخادم بحدّ أقصى خمس مرّات على فترات ثانية واحدة. - كيف يمكنني التأكّد من أنّ عمليات معاودة الاتصال لإثبات الملكية من جانب الخادم واردة من Google؟
- استخدِم بحث نظام أسماء النطاقات العكسي للتأكّد من أنّ عمليات معاودة الاتصال لإثبات الملكية من جانب الخادم صادرة من Google.