إنّ معاودات الاتصال لعملية تحقّق من جهة الخادم هي طلبات عناوين URL، مع معلمات طلب البحث التي توسّعها Google، والتي ترسلها Google إلى نظام خارجي لإعلامه بأنّه يجب مكافأة المستخدم على التفاعل مع إعلان بيني مقابل مكافأة أو إعلان مقابل مكافأة. توفّر معاودات الاتصال لعملية تحقّق من جهة الخادم للإعلانات مقابل مكافأة مستوى إضافيًا من الحماية من انتحال معاودات الاتصال من جهة العميل لمكافأة المستخدمين.
يوضّح لك هذا الدليل كيفية التحقّق من معاودات الاتصال لعملية إثبات الملكية من جهة الخادم للإعلانات مقابل مكافأة باستخدام مكتبة التشفير التابعة لجهة خارجية Tink Java Apps لضمان أنّ معامِلات طلب البحث في معاودة الاتصال هي قيم مشروعة. ECDSA يمكنك أيضًا اختبار الخادم باستخدام أداة الاختبار في واجهة مستخدم AdMob.
المتطلبات الأساسية
استخدام RewardedAdsVerifier من مكتبة Tink Java Apps
يتضمّن مستودع 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 |
| 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 | معرّف المستخدم كما يوفّره
SetUserId
إذا لم يوفّر التطبيق معرّف مستخدم، لن يكون معلَمة طلب البحث هذه متوفرة في معاودة الاتصال لعملية إثبات الملكية من جهة الخادم. |
1234567 |
معرّفات مصادر الإعلانات
أسماء مصادر الإعلانات وأرقام تعريفها
| اسم مصدر الإعلان | رقم تعريف مصدر الإعلان |
|---|---|
| Ad Generation (عرض أسعار) | 1477265452970951479 |
| AdColony | 15586990674969969776 |
| AdColony (عرض أسعار) | 6895345910719072481 |
| AdFalcon | 3528208921554210682 |
| شبكة AdMob | 5450213213286189855 |
| العرض الإعلاني بدون انقطاع في شبكة AdMob | 1215381445328257950 |
| Applovin | 1063618907739174004 |
| Applovin (عرض أسعار) | 1328079684332308356 |
| Chartboost | 2873236629771172317 |
| Chocolate Platform (عرض أسعار) | 6432849193975106527 |
| حدث مخصّص | 18351550913290782395 |
| DT Exchange* * قبل 21 سبتمبر 2022، كانت هذه الشبكة تُسمّى "Fyber Marketplace". | 2179455223494392917 |
| Equativ (عرض أسعار)* * قبل 12 يناير 2023، كانت هذه الشبكة تُسمّى "Smart Adserver". | 5970199210771591442 |
| Fluct (عرض أسعار) | 8419777862490735710 |
| Flurry | 3376427960656545613 |
| Fyber* * يُستخدم مصدر الإعلان هذا لإعداد التقارير السابقة. | 4839637394546996422 |
| i-mobile | 5208827440166355534 |
| Improve Digital (عرض أسعار) | 159382223051638006 |
| Index Exchange (عرض أسعار) | 4100650709078789802 |
| InMobi | 7681903010231960328 |
| InMobi (عرض أسعار) | 6325663098072678541 |
| InMobi Exchange (عرض أسعار) | 5264320421916134407 |
| IronSource | 6925240245545091930 |
| ironSource Ads (عرض أسعار) | 1643326773739866623 |
| Leadbolt | 2899150749497968595 |
| Liftoff Monetize* * قبل 30 يناير 2023، كانت هذه الشبكة تُسمّى "Vungle". | 1953547073528090325 |
| Liftoff Monetize (عرض أسعار)* * قبل 30 يناير 2023، كانت هذه الشبكة تُسمّى "Vungle (عرض أسعار)". | 4692500501762622185 |
| LG U+AD | 18298738678491729107 |
| LINE Ads Network | 3025503711505004547 |
| Magnite DV+ (عرض أسعار) | 3993193775968767067 |
| maio | 7505118203095108657 |
| maio (عرض أسعار) | 1343336733822567166 |
| 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 |
| MoPub (خدمة متوقّفة نهائيًا) | 10872986198578383917 |
| myTarget | 8450873672465271579 |
| Nend | 9383070032774777750 |
| Nexxen (عرض أسعار)* * قبل 1 مايو 2024، كانت هذه الشبكة تُسمّى "UnrulyX". | 2831998725945605450 |
| OneTag Exchange (عرض أسعار) | 4873891452523427499 |
| OpenX (عرض أسعار) | 4918705482605678398 |
| Pangle | 4069896914521993236 |
| Pangle (عرض أسعار) | 3525379893916449117 |
| PubMatic (عرض أسعار) | 3841544486172445473 |
| حملة قائمة على الحجز | 7068401028668408324 |
| SK planet | 734341340207269415 |
| Sharethrough (عرض أسعار) | 5247944089976324188 |
| Smaato (عرض أسعار) | 3362360112145450544 |
| Sonobi (عرض أسعار) | 3270984106996027150 |
| Tapjoy | 7295217276740746030 |
| Tapjoy (عرض أسعار) | 4692500501762622178 |
| Tencent GDT | 7007906637038700218 |
| TripleLift (عرض أسعار) | 8332676245392738510 |
| Unity Ads | 4970775877303683148 |
| Unity Ads (عرض أسعار) | 7069338991535737586 |
| Verve Group (عرض أسعار) | 5013176581647059185 |
| Vpon | 1940957084538325905 |
| Yieldmo (عرض أسعار) | 4193081836471107579 |
| YieldOne (عرض أسعار) | 3154533971590234104 |
| Zucks | 5506531810221735863 |
مكافأة المستخدم
من المهم تحقيق التوازن بين تجربة المستخدم والتحقّق من المكافأة عند تحديد موعد مكافأة المستخدم. قد تحدث تأخيرات في معاودات الاتصال من جهة الخادم قبل وصولها إلى الأنظمة الخارجية. لذلك، ننصحك باستخدام معاودة الاتصال من جهة العميل لمكافأة المستخدم على الفور، مع إجراء عملية التحقّق من جميع المكافآت عند تلقّي معاودات الاتصال من جهة الخادم. يوفّر هذا النهج تجربة جيدة للمستخدمين مع ضمان صلاحية المكافآت الممنوحة.
مع ذلك، بالنسبة إلى التطبيقات التي تكون فيها صلاحية المكافأة مهمة (على سبيل المثال، تؤثر المكافأة في الاقتصاد داخل اللعبة في تطبيقك) وتكون التأخيرات في منح المكافآت مقبولة، قد يكون الانتظار إلى حين تلقّي معاودة الاتصال التي تم التحقّق منها من جهة الخادم هو النهج الأفضل.
البيانات المخصّصة
يجب أن تستخدم التطبيقات التي تتطلّب بيانات إضافية في معاودات الاتصال لعملية تحقّق من جهة الخادم ميزة البيانات المخصّصة للإعلانات مقابل مكافأة. يتم تمرير أي قيمة سلسلة يتم ضبطها على عنصر إعلان مقابل مكافأة إلى معلَمة طلب البحث custom_data لمعاودة الاتصال لعملية إثبات الملكية من جهة الخادم. إذا لم يتم ضبط قيمة بيانات مخصّصة، لن تكون قيمة معلَمة طلب البحث custom_data متوفرة في معاودة الاتصال لعملية إثبات الملكية من جهة الخادم.
يوضّح نموذج الرمز البرمجي التالي كيفية ضبط خيارات عملية إثبات الملكية من جهة الخادم بعد تحميل الإعلان مقابل مكافأة:
private void LoadRewardedAd(string adUnitId)
{
// Send the request to load the ad.
AdRequest adRequest = new AdRequest();
RewardedAd.Load(adUnitId, adRequest, (RewardedAd rewardedAd, LoadAdError error) =>
{
// If the operation failed with a reason.
if (error != null)
{
Debug.LogError("Rewarded ad failed to load an ad with error : " + error);
return;
}
var options = new ServerSideVerificationOptions
.Builder()
.SetCustomData("SAMPLE_CUSTOM_DATA_STRING")
.Build()
rewardedAd.SetServerSideVerificationOptions(options);
});
}
إذا أردت ضبط سلسلة المكافأة المخصّصة، عليك إجراء ذلك قبل عرض الإعلان.
التحقّق اليدوي من معاودة الاتصال لعملية إثبات الملكية من جهة الخادم للإعلانات مقابل مكافأة
في ما يلي الخطوات التي تتّبعها فئة RewardedAdsVerifier للتحقّق من معاودة الاتصال لعملية إثبات الملكية من جهة الخادم للإعلانات مقابل مكافأة. على الرغم من أنّ مقتطفات الرموز البرمجية المضمّنة مكتوبة بلغة Java و
تستخدِم مكتبة Tink التابعة لجهة خارجية، يمكنك تنفيذ هذه الخطوات باللغة التي تختارها، باستخدام أي مكتبة تابعة لجهة خارجية تتوافق مع
ECDSA.
جلب المفاتيح العامة
للتحقّق من معاودة الاتصال لعملية إثبات الملكية من جهة الخادم للإعلانات مقابل مكافأة، تحتاج إلى مفتاح عام يوفّره 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.