קריאות חוזרות לאימות בצד השרת הן בקשות לכתובות URL, עם פרמטרים של שאילתות שמורחבים על ידי Google, שנשלחות על ידי Google למערכת חיצונית כדי ליידע את המשתמש שצריך לקבל תגמול על אינטראקציה עם מודעת מעברון מתגמלת או מתגמלת. קריאות חוזרות (callback) מתגמלות (SSV) מספקות שכבת הגנה נוספת מפני זיוף של קריאות חוזרות (callback) בצד הלקוח, כדי לתגמל את המשתמשים.
במדריך הזה מוסבר איך לאמת קריאות חוזרות (callback) של צד שלישי מתגמלת באמצעות הספרייה הקריפטוגרפית של צד שלישי Tink Java Apps, כדי לוודא שהפרמטרים של השאילתה בקריאה החוזרת (callback) הם ערכים חוקיים. במדריך הזה משתמשים ב-Tink, אבל אפשר להשתמש בכל ספרייה של צד שלישי שתומכת ב-ECDSA. אתם יכולים לבדוק את השרת גם באמצעות כלי הבדיקה בממשק המשתמש של AdMob.
לפניכם דוגמה לדוגמה שפועלת באופן מלא באמצעות Java Spring-boot.
דרישות מוקדמות
משלבים מודעות מתגמלות באפליקציה לנייד באמצעות גרסה 7.28.0 ואילך של Google Mobile Ads SDK.
מפעילים אימות בצד השרת של מודעות מתגמלות ביחידת המודעות.
שימוש ב-RewardAdsVerifier מספריית האפליקציות Tink Java
המאגר ב-GitHub של Tink Java Apps ב-GitHub כולל מחלקת עזרה של RewardedAdsVerifier
, שמטרתה לצמצם את הקוד שנדרש כדי לאמת קריאה חוזרת (callback) מתגמלת.
שימוש במחלקה הזו מאפשר לאמת כתובת URL לקריאה חוזרת (callback) באמצעות הקוד הבא.
RewardedAdsVerifier verifier = new RewardedAdsVerifier.Builder()
.fetchVerifyingPublicKeysWith(
RewardedAdsVerifier.KEYS_DOWNLOADER_INSTANCE_PROD)
.build();
String rewardUrl = ...;
verifier.verify(rewardUrl);
אם השיטה verify()
מופעלת בלי להעלות חריג, כתובת ה-URL לקריאה חוזרת (callback) אומתה בהצלחה. בקטע תגמול למשתמש מפורטות השיטות המומלצות לגבי מועדי התגמול של המשתמשים. בקטע אימות ידני של אימות ידני של מודעות בצד השרת המתגמלות מפורט
פירוט של השלבים שהמחלקה הזו ביצעה כדי לאמת קריאה חוזרת (callback) מתגמלת.
פרמטרים של התקשרות חזרה בצד השרת (SSV)
קריאות חוזרות לאימות בצד השרת מכילות פרמטרים של שאילתה, שמתארים את האינטראקציה עם המודעה המתגמלת. שמות של פרמטרים, תיאורים וערכים לדוגמה מפורטים למטה. הפרמטרים נשלחים בסדר אלפביתי.
שם פרמטר | התיאור | ערך לדוגמה |
---|---|---|
ad_network | מזהה של מקור המודעות של מקור המודעות שהפעיל את המודעה הזו. השמות של מקורות המודעות שתואמים לערכי המזהים מפורטים בקטע מזהים של מקורות מודעות. | 1953547073528090325 |
ad_unit | מזהה יחידת המודעות ב-AdMob ששימשה לבקשת המודעה המתגמלת. | 2747237135 |
custom_data | מחרוזת נתונים בהתאמה אישית כפי שסופקה על ידי
customRewardString
.
אם האפליקציה לא מספקת מחרוזת נתונים מותאמת אישית, הערך של פרמטר השאילתה הזה לא יוצג בקריאה החוזרת של ה-SSV. |
SAMPLE_CUSTOM_DATA_STRING |
key_id | המפתח המשמש לאימות ההתקשרות החוזרת של ה-SSV. הערך הזה ממופה למפתח ציבורי שמסופק על ידי שרת המפתחות של AdMob. | 1234567890 |
reward_amount | סכום התגמול שצוין בהגדרות של יחידת המודעות. | 5 |
reward_item | פריט התגמול כפי שצוין בהגדרות של יחידת המודעות. | מטבעות |
signature | חתימה לקריאה חוזרת (SSV) שנוצרה על ידי AdMob. | MEUCIQCLJS_s4ia_sN06HqzeW7Wc3nhZi4RlW3qV0oO-6AIYdQIgGJEh-rzKreO-paNDbSCzWGMtmgJHYYW9k2_icM9LFMY |
חותמת זמן | חותמת הזמן של המועד שבו המשתמש קיבל תגמול לפי זמן מערכת באלפיות השנייה. | 1507770365237823 |
transaction_id | מזהה ייחודי בקידוד הקסדצימלי לכל אירוע של הענקת תגמול שנוצר על ידי AdMob. | 18fa792de1bca816048293fc71035638 |
user_id | מזהה המשתמש כפי שסופק על ידי
userIdentifier .
אם האפליקציה לא סיפקה מזהה משתמש, פרמטר השאילתה הזה לא יופיע בקריאה החוזרת של ה-SSV. |
1234567 |
מזהים של מקורות מודעות
מזהים ושמות של מקורות מודעות
שם מקור המודעה | מזהה של מקור מודעות |
---|---|
Aarki (בידינג) | 5240798063227064260 |
יצירת מודעות (בידינג) | 1477265452970951479 |
AdColony | 15586990674969969776 |
AdColony (לא SDK) (בידינג) | 4600416542059544716 |
AdColony (בידינג) | 6895345910719072481 |
AdFalcon | 3528208921554210682 |
רשת AdMob | 5450213213286189855 |
ADResult | 10593873382626181482 |
AMoAd | 17253994435944008978 |
אפלובין | 1063618907739174004 |
Appלובin (בידינג) | 1328079684332308356 |
Chartboost | 2873236629771172317 |
פלטפורמת שוקולד (בידינג) | 6432849193975106527 |
CrossChannel (MdotM) | 9372067028804390441 |
אירוע מותאם אישית | 18351550913290782395 |
DT Exchange* * לפני 21 בספטמבר 2022, הרשת הזו נקראה 'Fyber Marketplace'. | 2179455223494392917 |
EMX (בידינג) | 8497809869790333482 |
תנודות (בידינג) | 8419777862490735710 |
פלורי | 3376427960656545613 |
Fyber* * מקור המודעות הזה משמש לדיווח היסטורי. | 4839637394546996422 |
i-mobile | 5208827440166355534 |
שיפור הדיגיטל (בידינג) | 159382223051638006 |
המרת אינדקס (בידינג) | 4100650709078789802 |
InMobi | 7681903010231960328 |
InMobi (בידינג) | 6325663098072678541 |
IronSource | 6925240245545091930 |
Leadbolt | 2899150749497968595 |
LG U+AD | 18298738678491729107 |
רשת המודעות של LINE | 3025503711505004547 |
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 |
מינטגרל | 1357746574408896200 |
Mintegral (בידינג) | 6250601289653372374 |
MobFox | 8079529624516381459 |
MobFox (בידינג) | 3086513548163922365 |
MoPub (הוצאה משימוש) | 10872986198578383917 |
myTarget | 8450873672465271579 |
Nend | 9383070032774777750 |
ONE by AOL (Millennial Media) | 6101072188699264581 |
ONE by AOL (Nexage) | 3224789793037044399 |
OneTag Exchange (בידינג) | 4873891452523427499 |
OpenX (בידינג) | 4918705482605678398 |
Pangle (בידינג) | 3525379893916449117 |
PubMatic (בידינג) | 3841544486172445473 |
קמפיין בהזמנה | 7068401028668408324 |
RhythmOne (בידינג) | 2831998725945605450 |
Rubicon (בידינג) | 3993193775968767067 |
כוכב הלכת SK | 734341340207269415 |
שיעור המרות (Sharethrough) (בידינג) | 5247944089976324188 |
Smaato (בידינג) | 3362360112145450544 |
Equativ (בידינג)* * לפני 12 בינואר 2023, הרשת הזו נקראה 'שרת מודעות חכם'. | 5970199210771591442 |
Sonobi (בידינג) | 3270984106996027150 |
Tapjoy | 7295217276740746030 |
Tapjoy (בידינג) | 4692500501762622178 |
Tencent GDT | 7007906637038700218 |
TripleLift (בידינג) | 8332676245392738510 |
מודעות Unity | 4970775877303683148 |
UnrulyX (בידינג) | 2831998725945605450 |
Verizon Media | 7360851262951344112 |
קבוצת Verve (בידינג) | 5013176581647059185 |
VPN | 1940957084538325905 |
Liftoff Monetize* * לפני 30 בינואר 2023, הרשת הזו נקראה Vungle. | 1953547073528090325 |
Liftoff Monetize (בידינג)* * לפני 30 בינואר 2023, הרשת הזו נקראה Vungle (בידינג). | 4692500501762622185 |
Yieldmo (בידינג) | 4193081836471107579 |
YieldOne (בידינג) | 3154533971590234104 |
זאקס | 5506531810221735863 |
תגמול למשתמש
כשמחליטים מתי לתגמל משתמש, חשוב לאזן בין חוויית המשתמש לבין אימות התגמול. יכול להיות שיהיו עיכובים בהתקשרות חזרה בצד השרת לפני שהם יגיעו למערכות חיצוניות. לכן, השיטה המומלצת היא להשתמש בקריאה חוזרת (callback) בצד הלקוח כדי לתגמל את המשתמש באופן מיידי, תוך ביצוע אימות לכל התגמולים כשמקבלים קריאות חוזרות (callback) בצד השרת. הגישה הזו מספקת חוויית משתמש טובה וגם מבטיחה את תוקף התגמולים שניתנו.
עם זאת, במקרה של אפליקציות שבהן תוקף התגמול הוא קריטי (לדוגמה, התגמול משפיע על הכלכלה בתוך המשחק) ועיכובים במתן הפרסים הם מותרים, כדאי להמתין לקריאה החוזרת (callback) המאומתת בצד השרת.
נתונים בהתאמה אישית
באפליקציות שנדרשת עבורן נתונים נוספים בקריאות חוזרות לאימות בצד השרת, יש להשתמש בתכונה 'נתונים מותאמים אישית' במודעות המתגמלות. כל ערך מחרוזת שמוגדר באובייקט של מודעה
מתגמלת מועבר לפרמטר השאילתה custom_data
של הקריאה החוזרת (SSV). אם לא הוגדר ערך של נתונים מותאמים אישית, הערך של פרמטר השאילתה custom_data
לא יופיע בקריאה החוזרת של ה-SSV.
דוגמת הקוד הבאה מדגימה איך להגדיר את אפשרויות ה-SSV אחרי טעינת המודעה המתגמלת.
Swift
GADRewardedAd.load(withAdUnitID:"ca-app-pub-3940256099942544/1712485313", request: request, completionHandler: { [self] ad, error in if let error != error { rewardedAd = ad let options = GADServerSideVerificationOptions() options.customRewardString = "SAMPLE_CUSTOM_DATA_STRING" rewardedAd.serverSideVerificationOptions = options }
Objective-C
GADRequest *request = [GADRequest request]; [GADRewardedAd loadWithAdUnitID:@"ca-app-pub-3940256099942544/1712485313" request:request completionHandler:^(GADRewardedAd *ad, NSError *error) { if (error) { // Handle Error return; } self.rewardedAd = ad; GADServerSideVerificationOptions *options = [[GADServerSideVerificationOptions alloc] init]; options.customRewardString = @"SAMPLE_CUSTOM_DATA_STRING"; ad.serverSideVerificationOptions = options; }];
אימות ידני של אימות בצד השרת של מודעות מתגמלות
השלבים שהמחלקה RewardedAdsVerifier
ביצעה כדי לאמת אימות בצד השרת של מודעות מתגמלות מפורטים בהמשך. למרות שקטעי הקוד הכלולים נמצאים ב-Java ומשתמשים בספריית Tink של צד שלישי, תוכלו להטמיע את השלבים האלה בשפה שתבחרו באמצעות כל ספרייה של צד שלישי שתומכת ב-ECDSA.
אחזור מפתחות ציבוריים
כדי לאמת קריאה חוזרת (callback) של בצד השרת המתגמל, יש צורך במפתח ציבורי שיסופק על ידי AdMob.
משרת המפתחות של AdMob, אפשר לאחזר משרת המפתחות של AdMob רשימה של מפתחות ציבוריים שישמשו לאימות הקריאות החוזרות (callback) של ה-SSV המתגמל. רשימת המפתחות הציבוריים מסופקת כייצוג 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;
}
קבלת תוכן לאימות
שני הפרמטרים האחרונים של השאילתה בקריאות החוזרות (callback) של הצד השלישי המתגמלות הם תמיד signature
ו-key_id,
בסדר הזה. שאר הפרמטרים של השאילתה מציינים את התוכן שיש לבדוק. נניח שהגדרתם את המערכת של AdMob לשלוח קריאות חוזרות לתגמול אל
https://www.myserver.com/mypath
. בקטע הקוד שבהמשך מוצגת דוגמה לקריאה חוזרת (callback) של בצד השרת המתגמל (SSV) עם הדגשה של התוכן שיש לאמת.
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 של קריאה חוזרת (callback) כמערך בייטים מסוג 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 לקריאה חוזרת (callback), כפי שמוצג בהמשך:
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 לקריאה חוזרת (callback) כדי לקבל את המפתח הציבורי מהמיפוי הזה. לאחר מכן מאמתים את החתימה באמצעות המפתח הציבורי הזה. השלבים האלה מודגמים למטה בשיטה 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 לקריאה חוזרת (callback) אומתה בהצלחה.
שאלות נפוצות
- האם אפשר לשמור במטמון את המפתח הציבורי שסופק על ידי שרת המפתחות של AdMob?
- מומלץ לשמור במטמון את המפתח הציבורי שסופק על ידי שרת המפתחות של AdMob, כדי לצמצם את מספר הפעולות שנדרשות לאימות קריאה חוזרת (callback) של אימות בצד השרת. עם זאת, שימו לב שמפתחות ציבוריים עוברים רוטציה באופן קבוע ולא אמורים להישמר במטמון למשך יותר מ-24 שעות.
- באיזו תדירות מתבצעת רוטציה של המפתחות הציבוריים שסופקו על ידי שרת המפתחות של AdMob?
- מפתחות ציבוריים שמסופקים על ידי שרת המפתחות של AdMob עוברים רוטציה לפי לוח זמנים משתנה. כדי להבטיח שהאימות של קריאות חוזרות (callback) מסוג SSV ימשיך לפעול כמצופה, אין לשמור מפתחות ציבוריים במטמון למשך יותר מ-24 שעות.
- מה קורה אם לא ניתן להתחבר לשרת שלי?
- Google מצפה לקבל קוד תגובה של
HTTP 200 OK
לציון סטטוס הצלחה בתגובה לקריאה חוזרת (SSV). אם לא ניתן להשיג את השרת או לא מספק את התגובה הצפויה, Google תנסה שוב לשלוח קריאות חוזרות (callback) של SSV עד חמש פעמים במרווחים של שנייה אחת. - איך אפשר לוודא שהקריאות החוזרות של האימות בצד השרת מגיעות מ-Google?
- השתמשו בחיפוש DNS הפוך כדי לוודא שהקריאות החוזרות (callback) מסוג SSV מקורן ב-Google.