מדריך למפתחים בנושא Protected Audience API

בזמן הקריאה במסמכי העזרה של ארגז החול לפרטיות ב-Android, תוכלו להשתמש בלחצן גרסת Developer Preview או בלחצן Beta כדי לבחור את גרסת התוכנית שבה אתם עובדים, כי ההוראות עשויות להשתנות.


Protected Audience API ב-Android (לשעבר FLEDGE) כולל את Custom Audience API ואת Ad Selection API. פלטפורמות טכנולוגיית פרסום ומפרסמים יכולים להשתמש בממשקי ה-API האלה כדי להציג מודעות בהתאמה אישית על סמך אינטראקציות קודמות באפליקציה, תוך הגבלת שיתוף המזהים בין אפליקציות והגבלת שיתוף המידע על האינטראקציות של המשתמשים באפליקציות עם צדדים שלישיים.

Custom Audience API מתמקד בהפשטה של 'קהל בהתאמה אישית', שמייצגת קבוצה של משתמשים עם כוונות משותפות. מפרסם יכול לרשום משתמש לקהל מותאם אישית ולשייך אליו מודעות רלוונטיות. המידע הזה מאוחסן באופן מקומי, וניתן להשתמש בו כדי להשפיע על הצעות המחיר של המפרסמים, על סינון המודעות ועל העיבוד שלהן.

Ad Selection API מספק מסגרת שמאפשרת למפתחים מרובים להפעיל מכרז מקומי לקהל מותאם אישית. כדי לעשות זאת, המערכת מביאה בחשבון מודעות רלוונטיות שמשויכות לקהל המותאם אישית, ומבצעת עיבוד נוסף על מודעות שפלטפורמת טכנולוגיית הפרסום מחזירה למכשיר.

פלטפורמות של טכנולוגיות פרסום יכולות לשלב את ממשקי ה-API האלה כדי להטמיע רימרקטינג ששומר על פרטיות המשתמשים. אנחנו מתכננים להוסיף תמיכה בתרחישי שימוש נוספים, כולל מודעות להתקנת אפליקציות, בגרסאות עתידיות. מידע נוסף על Protected Audience API ב-Android זמין בהצעת העיצוב.

במדריך הזה נסביר איך משתמשים ב-Protected Audience API ב-Android כדי לבצע את הפעולות הבאות:

  1. ניהול קהלים בהתאמה אישית
  2. הגדרה והפעלה של בחירת מודעות במכשיר
  3. דיווח על חשיפות של מודעות

לפני שמתחילים

לפני שמתחילים, צריך לבצע את הפעולות הבאות:

  1. מגדירים את סביבת הפיתוח של ארגז החול לפרטיות ב-Android.
  2. מתקינים קובץ אימג' של מערכת במכשיר נתמך או מגדירים אמולטור שכולל תמיכה בארגז החול לפרטיות ב-Android.
  3. בטרמינל, מפעילים את הגישה ל-Protected Audience API (מושבת כברירת מחדל) באמצעות הפקודה הבאה של adb.

      adb shell device_config put adservices ppapi_app_allow_list \"*\"
    
  4. בטרמינל, מפעילים את הדיווח על סמנים באמצעות פקודות adb הבאות.

     adb shell device_config put adservices fledge_beacon_reporting_metrics_enabled true
     adb shell device_config put adservices fledge_register_ad_beacon_enabled true
    
  5. כוללים הרשאה ACCESS_ADSERVICES_CUSTOM_AUDIENCE במניפסט של האפליקציה:

      <uses-permission android:name="android.permission.ACCESS_ADSERVICES_CUSTOM_AUDIENCE" />
    
  6. מפנים להגדרה של שירותי המודעות ברכיב <application> במניפסט:

      <property android:name="android.adservices.AD_SERVICES_CONFIG"
                android:resource="@xml/ad_services_config" />
    
  7. מציינים את משאב ה-XML של שירותי המודעות שאליו יש הפניה במניפסט, למשל res/xml/ad_services_config.xml. מידע נוסף על הרשאות של שירותי מודעות ועל בקרת גישה של SDK

      <ad-services-config>
        <custom-audiences allowAllToAccess="true" />
      </ad-services-config>
    
  8. ברירת המחדל של Ad Selection API היא לאכוף מגבלות על נפח הזיכרון המקסימלי שסקריפט של דיווח על מכרז או על חשיפות יכול להקצות. כדי להשתמש בתכונה של הגבלת הזיכרון, נדרשת גרסת WebView מגרסה 105.0.5195.58 ואילך. הפלטפורמה אוכפת בדיקת גרסה, וקריאות לממשקי ה-API selectAds ו-reportImpression נכשלות אם התנאי הזה לא מתקיים. יש שתי אפשרויות להגדרה הזו:

    • אפשרות 1: מריצים את הפקודה הבאה של adb כדי להשבית את הבדיקה הזו:

      adb device_config put fledge_js_isolate_enforce_max_heap_size false
      
    • אפשרות 2: מתקינים את WebView Beta מחנות Google Play. הערך הזה צריך להיות שווה לגרסת ה-SDK שצוינה קודם או גרסה מתקדמת יותר.

הצטרפות לקהל בהתאמה אישית

קהל בהתאמה אישית מייצג קבוצה של משתמשים עם תחומי עניין או כוונות משותפים, כפי שהחליטה אפליקציית המפרסם. אפליקציה או ערכת SDK עשויות להשתמש בקהל בהתאמה אישית כדי לציין קהל מסוים, למשל משתמש שהשאיר פריטים בעגלת קניות. כדי ליצור קהל בהתאמה אישית או להצטרף אליו באופן אסינכרוני, מבצעים את הפעולות הבאות:

  1. מאתחלים את האובייקט CustomAudienceManager.
  2. יוצרים אובייקט CustomAudience על ידי ציון פרמטרים מרכזיים כמו החבילה של הקונה ושם רלוונטי. לאחר מכן, מאתחלים את האובייקט JoinCustomAudienceRequest באמצעות האובייקט CustomAudience.
  3. קוראים לפונקציה joinCustomAudience() האסינכרונית עם האובייקט JoinCustomAudienceRequest והאובייקטים הרלוונטיים Executor ו-OutcomeReceiver.

Kotlin

val customAudienceManager: CustomAudienceManager =
    context.getSystemService(CustomAudienceManager::class.java)

// Initialize a custom audience.
val audience = CustomAudience.Builder()
    .setBuyer(buyer)
    .setName(name)
    ...
    .build()

// Initialize a custom audience request.
val joinCustomAudienceRequest: JoinCustomAudienceRequest =
    JoinCustomAudienceRequest.Builder().setCustomAudience(audience).build()

// Request to join a custom audience.
customAudienceManager.joinCustomAudience(joinCustomAudienceRequest,
    executor,
    outcomeReceiver)

Java

CustomAudienceManager customAudienceManager =
    context.getSystemService(CustomAudienceManager.class);

// Initialize a custom audience.
CustomAudience audience = new CustomAudience.Builder()
    .setBuyer(buyer)
    .setName(name)
    ...
    .build();

// Initialize a custom audience request.
JoinCustomAudienceRequest joinCustomAudienceRequest =
    new JoinCustomAudienceRequest.Builder().setCustomAudience(audience).build();

// Request to join a custom audience.
customAudienceManager.joinCustomAudience(joinCustomAudienceRequest,
    executor,
    outcomeReceiver);

השילוב של הפרמטרים הבאים מזהה באופן ייחודי כל אובייקט CustomAudience במכשיר:

  • owner: שם החבילה של אפליקציית הבעלים. הערך מוגדר באופן משתמע לשם החבילה של אפליקציית מבצע הקריאה החוזרת.
  • buyer: המזהה של רשת המודעות של הקונה שמנהלת את המודעות לקהל המותאם אישית הזה.
  • name: שם או מזהה שרירותיים של הקהל בהתאמה אישית.

קריאה חוזרת ל-joinCustomAudience() עם מופע אחר של CustomAudience מעדכנת כל CustomAudience קיים עם פרמטרים תואמים של owner, buyer ו-name. כדי לשמור על הפרטיות, התוצאה של ה-API לא מבדילה בין 'יצירה' לבין 'עדכון'.

בנוסף, צריך ליצור את CustomAudience עם הפרמטרים הנדרשים הבאים:

  • כתובת URL לעדכון יומי: כתובת URL מסוג HTTPS שמתבצעת לה שאילתה מדי יום ברקע כדי לעדכן את אותות הבידינג של משתמשים בקהל מותאם אישית, נתוני בידינג מהימנים ורינדור של כתובות URL ומטא-נתונים של מודעות.
  • כתובת URL של לוגיקה לבידינג: כתובת URL מסוג HTTPS שמופיעה בשאילתה במהלך בחירת המודעה כדי לאחזר את לוגיקת הבידינג של JavaScript של הקונה. חתימות הפונקציות הנדרשות מפורטות בקוד ה-JavaScript הזה.
  • Ad Render IDs: מזהה שרירותי שהוגדר על ידי טכנולוגיית הפרסום של הקונה. זהו אופטימיזציה ליצירת עומס התועלת (payload) ל-B&A.

הפרמטרים האופציונליים לאובייקט CustomAudience יכולים לכלול:

  • זמן ההפעלה: קהל מותאם אישית יכול להשתתף בבחירת המודעות ובעדכונים היומיים רק אחרי זמן ההפעלה שלו. לדוגמה, אפשר להשתמש באפשרות הזו כדי לעורר עניין בקרב משתמשים שהפסיקו להשתמש באפליקציה.
  • מועד תפוגה: מועד עתידי שבו הקהל המותאם אישית יוסר מהמכשיר.
  • אותות בידינג של משתמשים: מחרוזת JSON שמכילה אותות של משתמשים, כמו השפה המועדפת על המשתמש, שקוד ה-JavaScript של לוגיקה הבידינג של הקונה משתמש בה כדי ליצור הצעות מחיר במהלך תהליך בחירת המודעות. הפורמט הזה עוזר לפלטפורמות של טכנולוגיות פרסום לעשות שימוש חוזר בקוד בפלטפורמות שונות, ומקל על השימוש בפונקציות JavaScript.
  • נתוני בידינג מהימנים: כתובת URL מסוג HTTPS ורשימת מחרוזות שמשמשות במהלך תהליך בחירת המודעות לאחזור אותות בידינג משירות מהימן של מפתח/ערך.
  • Ads: רשימה של אובייקטים מסוג AdData שתואמים למודעות שמשתתפות בבחירת המודעות. כל אובייקט AdData מורכב מ:
    • כתובת URL לעיבוד: כתובת URL מסוג HTTPS שמופיעה בשאילתה לצורך עיבוד המודעה הסופית.
    • מטא-נתונים: אובייקט JSON שעבר סריאליזציה למחרוזת, ומכיל מידע שמערכת הבידינג של הקונה תשתמש בו במהלך תהליך בחירת המודעות.
    • מסנני מודעות: כיתה שמכילה את כל המידע הנדרש לסינון מודעות להתקנת אפליקציות ולהגדרת מכסות תדירות במהלך בחירת המודעות.

דוגמה ליצירת אובייקט CustomAudience:

Kotlin

// Minimal initialization of a CustomAudience object
val customAudience: CustomAudience = CustomAudience.Builder()
    .setBuyer(AdTechIdentifier.fromString("my.buyer.domain.name"))
    .setName("example-custom-audience-name")
    .setDailyUpdateUrl(Uri.parse("https://DAILY_UPDATE_URL"))
    .setBiddingLogicUrl(Uri.parse("https://BIDDING_LOGIC_URL"))
    .build()

Java

// Minimal initialization of a CustomAudience object
CustomAudience customAudience = CustomAudience.Builder()
    .setBuyer(AdTechIdentifier.fromString("my.buyer.domain.name"))
    .setName("example-custom-audience-name")
    .setDailyUpdateUrl(Uri.parse("https://DAILY_UPDATE_URL"))
    .setBiddingLogicUrl(Uri.parse("https://BIDDING_LOGIC_URL"))
    .build();

טיפול בתוצאות של joinCustomAudience()

השיטה האסינכרונית joinCustomAudience() משתמשת באובייקט OutcomeReceiver כדי לסמן את התוצאה של קריאת ה-API.

  • הקריאה החוזרת (callback) של onResult() מציינת שהקהל בהתאמה אישית נוצר או עודכן בהצלחה.
  • קריאת החזרה (callback) של onError() מציינת שני תנאים אפשריים.

דוגמה לטיפול בתוצאה של joinCustomAudience():

Kotlin

var callback: OutcomeReceiver<Void, AdServicesException> =
    object : OutcomeReceiver<Void, AdServicesException> {
    override fun onResult(result: Void) {
        Log.i("CustomAudience", "Completed joinCustomAudience")
    }

    override fun onError(error: AdServicesException) {
        // Handle error
        Log.e("CustomAudience", "Error executing joinCustomAudience", error)
    }
};

Java

OutcomeReceiver callback = new OutcomeReceiver<Void, AdServicesException>() {
    @Override
    public void onResult(@NonNull Void result) {
        Log.i("CustomAudience", "Completed joinCustomAudience");
    }

    @Override
    public void onError(@NonNull AdServicesException error) {
        // Handle error
        Log.e("CustomAudience", "Error executing joinCustomAudience", error);
    }
};

עזיבת קהל בהתאמה אישית

אם המשתמש כבר לא עומד בקריטריונים העסקיים של קהל מותאם אישית נתון, אפליקציה או SDK יכולים להפעיל את leaveCustomAudience() כדי להסיר את הקהל המותאם אישית מהמכשיר. כדי להסיר CustomAudience על סמך הפרמטרים הייחודיים שלו:

  1. מאתחלים את האובייקט CustomAudienceManager.
  2. מאתחלים את LeaveCustomAudienceRequest באמצעות הערכים של buyer ו-name של הקהל בהתאמה אישית. מידע נוסף על שדות הקלט האלה זמין במאמר הצטרפות לקהל בהתאמה אישית.
  3. קוראים ל-method leaveCustomAudience() האסינכרוני עם האובייקט LeaveCustomAudienceRequest והאובייקטים הרלוונטיים Executor ו-OutcomeReceiver.

Kotlin

val customAudienceManager: CustomAudienceManager =
    context.getSystemService(CustomAudienceManager::class.java)

// Initialize a LeaveCustomAudienceRequest
val leaveCustomAudienceRequest: LeaveCustomAudienceRequest =
    LeaveCustomAudienceRequest.Builder()
        .setBuyer(buyer)
        .setName(name)
        .build()

// Request to leave a custom audience
customAudienceManager.leaveCustomAudience(
    leaveCustomAudienceRequest,
    executor,
    outcomeReceiver)

Java

CustomAudienceManager customAudienceManager =
    context.getSystemService(CustomAudienceManager.class);

// Initialize a LeaveCustomAudienceRequest
LeaveCustomAudienceRequest leaveCustomAudienceRequest =
    new LeaveCustomAudienceRequest.Builder()
        .setBuyer(buyer)
        .setName(name)
        .build();

// Request to leave a custom audience
customAudienceManager.leaveCustomAudience(
    leaveCustomAudienceRequest,
    executor,
    outcomeReceiver);

בדומה לקריאה ל-joinCustomAudience(), הקריאה OutcomeReceiver מסמנת את סיום הקריאה ל-API. כדי להגן על הפרטיות, בתוצאה של שגיאה לא מבחינים בין שגיאות פנימיות לבין ארגומנטים לא חוקיים. פונקציית ה-callback‏ onResult() מופעלת בסיום קריאת ה-API, גם אם קבוצת משתמשים מותאמת אישית תואמת הוסרה בהצלחה וגם אם לא.

הרצת הבחירה של המודעות

כדי להשתמש ב-Protected Audience API לבחירת מודעות, צריך לקרוא ל-method‏ selectAds():

  1. מאתחלים אובייקט AdSelectionManager.
  2. יוצרים אובייקט AdSelectionConfig.
  3. קוראים ל-method selectAds() האסינכרוני עם האובייקט AdSelectionConfig והאובייקטים הרלוונטיים Executor ו-OutcomeReceiver.

Kotlin

val adSelectionManager: AdSelectionManager =
  context.getSystemService(AdSelectionManager::class.java)

// Initialize AdSelectionConfig
val adSelectionConfig: AdSelectionConfig =
  AdSelectionConfig.Builder().setSeller(seller)
    .setDecisionLogicUrl(decisionLogicUrl)
    .setCustomAudienceBuyers(customAudienceBuyers)
    .setAdSelectionSignals(adSelectionSignals)
    .setSellerSignals(sellerSignals)
    .setPerBuyerSignals(perBuyerSignals)
    .setBuyerContextualAds(
      Collections.singletonMap(
        contextualAds.getBuyer(), contextualAds
      )
    ).build()

// Run ad selection with AdSelectionConfig
adSelectionManager.selectAds(
  adSelectionConfig, executor, outcomeReceiver
)

Java

AdSelectionManager adSelectionManager =
    context.getSystemService(AdSelectionManager.class);

// Initialize AdSelectionConfig
AdSelectionConfig adSelectionConfig =
  new AdSelectionConfig.Builder()
    .setSeller(seller)
    .setDecisionLogicUrl(decisionLogicUrl)
    .setCustomAudienceBuyers(customAudienceBuyers)
    .setAdSelectionSignals(adSelectionSignals)
    .setSellerSignals(sellerSignals)
    .setPerBuyerSignals(perBuyerSignals)
    .setBuyerContextualAds(
      Collections.singletonMap(contextualAds.getBuyer(), contextualAds)
    )
    .build();

// Run ad selection with AdSelectionConfig
adSelectionManager.selectAds(adSelectionConfig, executor, outcomeReceiver);

השיטה selectAds() דורשת קלט AdSelectionConfig, שבו צריך לציין את הפרמטרים הנדרשים הבאים:

  • Seller: מזהה של רשת המודעות של המוכר שמפעילה את בחירת המודעות.
  • כתובת URL של לוגיקה של החלטה: כתובת URL מסוג HTTPS שמופיעה בשאילתה כדי לקבל את הלוגיקה של JavaScript של רשת המודעות של המוכר.
    • כתובת URL מסוג HTTPS: נשלחת שאילתה כדי לקבל את הלוגיקה של JavaScript של רשת המודעות של המוכר. חתימות הפונקציות הנדרשות
    • מזהה URI שנוצר מראש: שמתאים לפורמט של FLEDGE לבחירת מודעות. IllegalArgumentException תושלח אם מועבר URI מוגדר מראש שלא נתמך או בפורמט שגוי.
  • קונים של קהלים בהתאמה אישית: רשימה מלאה של מזהים של רשתות מודעות של קונים שהמוכר העניק להן הרשאה להשתתף בתהליך בחירת המודעות. מזהי הקונים האלה תואמים ל-CustomAudience.getBuyer() מהקהלים המותאמים אישית שמשתתפים.

אפשר לציין את הפרמטרים הבאים כדי להתאים אישית את בחירת המודעות:

  • אותות לבחירת מודעות: אובייקט JSON שעבר סריאליזציה למחרוזת, ומכיל אותות לשימוש בלוגיקה של בידינג ב-JavaScript של הקונה שאוחזרה מ-CustomAudience.getBiddingLogicUrl().
  • אותות של מוכרים: אובייקט JSON שעבר סריאליזציה למחרוזת, ומכיל אותות שמנוצלים על ידי לוגיקת ההחלטות של JavaScript של המוכר שאוחזרה מ-AdSelectionConfig.getDecisionLogicUrl().
  • לפי אותות של קונים: מפה של אובייקטי JSON, שעבר סריאליזציה למחרוזות, שמכילה אותות לשימוש בלוגיקה של בידינג ב-JavaScript של קונים ספציפיים שאוחזרו מ-CustomAudience.getBiddingLogicUrl(), וזוהו לפי השדות של הקונים בקהלים המותאמים אישית שמשתתפים.
  • מודעות לפי הקשר: אוסף של מועמדות למודעות שנאספות ישירות מקונים במהלך מכרז שמתרחש מחוץ למכרז של קהל מוגן.

אחרי שבוחרים מודעה, התוצאות, הצעות המחיר והאותות נשמרים באופן פנימי לצורך דיווח. פונקציית הקריאה החוזרת OutcomeReceiver.onResult() מחזירה AdSelectionOutcome שמכיל את הפרטים הבאים:

  • כתובת URL לעיבוד של המודעה הזוכה, שהתקבלה מ-AdData.getRenderUrl().
  • מזהה בחירת מודעות ייחודי למשתמש במכשיר. המזהה הזה משמש לדיווח על חשיפת המודעה.

אם לא ניתן להשלים את בחירת המודעה מסיבות כמו ארגומנטים לא חוקיים, תפוגות זמן או צריכת משאבים מוגזמת, פונקציית ה-callback של OutcomeReceiver.onError() מספקת אירוע AdServicesException עם ההתנהגויות הבאות:

  • אם בחירת המודעה מופעלת עם ארגומנטים לא חוקיים, הערך IllegalArgumentException יופיע ב-AdServicesException כגורם.
  • כל שאר השגיאות מקבלות את הערך AdServicesException עם הערך IllegalStateException כגורם.

מודעות לפי הקשר

Protected Audience API מאפשר לכם לשלב מודעות לפי הקשר במכרזים עם הגנה על נתונים אישיים. צריך לבחור מודעות לפי הקשר בשרת של טכנולוגיית הפרסום ולהחזיר אותן למכשיר מחוץ ל-Protected Audience API. לאחר מכן תוכלו לכלול מודעות לפי הקשר במכרז באמצעות הערך AdSelectionConfig. בשלב הזה, המודעות יפעלו כמו מודעות במכשיר, כולל הזכאות לסינון של מודעות שליליות. אחרי שהמכרז של הקהל המוגן מסתיים, צריך להפעיל את reportImpression(). הפונקציה הזו מפעילה את reportWin() במודעה ההקשרית הזוכה, באותו דפוס כמו דיווח על חשיפות, כדי לקבל את המודעה הזוכה במכשיר. כל מודעה לפי הקשר צריכה קונה, הצעת מחיר, קישור ללוגיקת הדיווח, כתובת URL לעיבוד (render) ומטא-נתונים של מודעה.

כדי לפרוס מודעות לפי הקשר באפליקציה, האפליקציה היעד צריכה ליצור אובייקט ContextualAds:

Kotlin

val contextualAds: ContextualAds =
  Builder().setBuyer(AdTechIdentifier.fromString(mBiddingLogicUri.getHost()))
    //Pass in your valid app install ads
    .setDecisionLogicUri(mContextualLogicUri)
    .setAdsWithBid(appInstallAd)
    .build()

Java

ContextualAds contextualAds = new ContextualAds.Builder()
  .setBuyer(AdTechIdentifier.fromString(mBiddingLogicUri.getHost()))
  .setDecisionLogicUri(mContextualLogicUri)
  //Pass in your valid app install ads
  .setAdsWithBid(appInstallAd)
  .build();

לאחר מכן אפשר להעביר את האובייקט ContextualAds כשיוצרים את AdSelectionConfig:

Kotlin

// Create a new ad
val noFilterAd: AdData = Builder()
  .setMetadata(JSONObject().toString())
  .setRenderUri(Uri.parse(baseUri + NO_FILTER_RENDER_SUFFIX))
  .build()
val noFilterAdWithBid = AdWithBid(noFilterAd, NO_FILTER_BID)
contextualAds.getAdsWithBid().add(noFilterAdWithBid)

Java

// Create a new ad
AdData noFilterAd = new AdData.Builder()
  .setMetadata(new JSONObject().toString())
  .setRenderUri(Uri.parse(baseUri + NO_FILTER_RENDER_SUFFIX))
  .build();
AdWithBid noFilterAdWithBid = new AdWithBid(noFilterAd, NO_FILTER_BID);
contextualAds.getAdsWithBid().add(noFilterAdWithBid);

סינון מודעות להתקנת אפליקציות

סינון של מודעות להתקנת אפליקציות עוזר לכם לסנן מודעות להתקנת אפליקציות שכבר מותקנות במכשיר.

השלב הראשון בתהליך הזה הוא להגדיר לאילו מפרסמים תהיה אפשרות לסנן לפי החבילה המותקנת. הפעולה הזו צריכה להתרחש באפליקציה שאליה רוצים לטרגט מודעה.

Kotlin

//Create a request for setting the app install advertisers
val adtech = AdTechIdentifier.fromString("your.enrolled.uri")
val adtechSet = setOf(adtech)
val request = SetAppInstallAdvertisersRequest(adtechSet)

//Set the app install advertisers in the ad selection manager
mAdSelectionManager.setAppInstallAdvertisers(
  request,
  mExecutor,
  object : OutcomeReceiver<Any?, Exception?>() {
    fun onResult(@NonNull ignoredResult: Any?) {
      Log.v("[your tag]", "Updated app install advertisers")
    }

    fun onError(@NonNull error: Exception?) {
      Log.e("[your tag]", "Failed to update app install advertisers", error)
    }
  })

Java

//Create a request for setting the app install advertisers
AdTechIdentifier adtech = AdTechIdentifier.fromString("your.enrolled.uri");
Set<AdTechIdentifier> adtechSet = Collections.singleton(adtech);
SetAppInstallAdvertisersRequest request = new SetAppInstallAdvertisersRequest(adtechSet);

//Set the app install advertisers in the ad selection manager
mAdSelectionManager.setAppInstallAdvertisers(
  request,
  mExecutor,
  new OutcomeReceiver<Object, Exception>() {
    @Override
    public void onResult(@NonNull Object ignoredResult) {
      Log.v("[your tag]", "Updated app install advertisers");
    }

    @Override
    public void onError(@NonNull Exception error) {
      Log.e("[your tag]", "Failed to update app install advertisers", error);
    }
  });

כשהקוד הקודם מופעל, המפרסמים שהועברו יוכלו לסנן את האפליקציות המותקנות שציינתם במהלך יצירת הצעות המחיר שלהם. אם רוצים להסיר ממפרסם את הגישה לסטטוס ההתקנה של האפליקציה הזו, מריצים שוב את הקוד הזה אחרי שמסירים את פרטי המפרסם.

השלב הבא הוא הגדרת סינון מודעות באפליקציה של בעל התוכן הדיגיטלי. הגורם שמציג את המודעה באפליקציה של בעל התוכן הדיגיטלי (סביר להניח שזו ערכת SDK בצד ההיצע) צריך לאתחל את האובייקט AdFilters עם מידע על המודעות שקשורות לאפליקציות שרוצים לסנן:

Kotlin

// Instantiate AdFilters object with package names.
val filters: AdFilters = Builder().setAppInstallFilters(
    Builder().setPackageNames(setOf("example.target.app")).build()
  ).build()

Java

// Instantiate AdFilters object with package names.
AdFilters filters = new AdFilters.Builder()
.setAppInstallFilters(
  new AppInstallFilters.Builder()
  .setPackageNames(Collections.singleton("example.target.app"))
  .build())
.build();

בעלי תוכן דיגיטלי בצד הביקוש יכולים גם להגדיר AdFilter למודעות שנמצאות בתוך הקהלים המותאמים אישית שלהם.

אפשר גם להעביר את AdFilters בנקודה שבה יוצרים אובייקט AdData חדש:

Kotlin

// Instantiate an AdData object with the AdFilters created in the
// previous example.
val appInstallAd: AdData =
  Builder().setMetadata("{ ... }") // Valid JSON string
    .setRenderUri(Uri.parse("www.example-dsp1.com/.../campaign123.html"))
    .setAdFilters(filters).build()

Java

// Instantiate an AdData object with the AdFilters created in the
// previous example.
AdData appInstallAd = new AdData.Builder()
.setMetadata("{ ... }") // Valid JSON string
.setRenderUri(Uri.parse("www.example-dsp1.com/.../campaign123.html"))
    .setAdFilters(filters)
    .build();

סינון לפי מכסת תדירות

סינון לפי מכסת תדירות מאפשר לטכנאי הפרסום להגביל את מספר הפעמים שהמודעה תוצג. סינון לפי מכסת תדירות מפחית את חשיפת המודעות ומבצע אופטימיזציה של הבחירה של מודעות חלופיות בקמפיין מודעות נתון.

למסנן של מכסת תדירות יש שני רכיבים עיקריים: סוג האירוע של המודעה ומפתח המונה של המודעה. סוגי אירועי המודעות הזמינים שאפשר להשתמש בהם הם:

  • זכייה: אירוע זכייה מציין שהמודעה זכתה במכרז. אירועי זכייה מתעדכנים באופן אוטומטי על ידי Protected Audience API, והמפתח לא יכול להפעיל אותם ישירות. נתוני ההמרות האלה גלויים רק למודעות בקהל מותאם אישית נתון.
  • חשיפת מודעה: בנפרד מ-reportImpression, מבצע קריאה בהתקן (SSP או MMP) משתמש ב-updateAdCounterHistogram() כדי להפעיל אירועי חשיפת מודעות בנקודה בקוד שבחר. אירועי חשיפות גלויים לכל המודעות ששייכות ל-DSP נתון, והם לא מוגבלים למודעות באותו קהל מותאם אישית.
  • View: האירוע מופעל על ידי מבצע הקריאה במכשיר (SSP או MMP) בנקודה בקוד שבחר באמצעות קריאה ל-updateAdCounterHistogram(). אירועי צפייה גלויים לכל המודעות ששייכות ל-DSP נתון, ולא מוגבלים למודעות באותו קהל מותאם אישית.
  • קליק: האירוע מופעל על ידי מבצע הקריאה במכשיר (SSP או MMP) בנקודה בקוד שבחר באמצעות קריאה ל-updateAdCounterHistogram(). אירועי קליקים גלויים לכל המודעות ששייכות ל-DSP נתון, ולא מוגבלים למודעות באותו קהל מותאם אישית.

באפליקציה של בעל האפליקציה, פלטפורמת SSP או MMP שנמצאת במכשיר מפעילה אירועי מודעות. כשפונים לפונקציה updateAdCounterHistogram(), המונה של מסנן מכסת התדירות עולה, כך שבמכרזים עתידיים יהיה מידע עדכני על החשיפה של משתמש למודעה מסוימת. סוגי האירועים של המודעות לא קשורים באופן גורף לפעולת המשתמש המתאימה, והם הנחיות שניתנות כדי לעזור למפעילים לבנות את מערכת האירועים שלהם. כדי להגדיל את ספירת המודעות בזמן אירוע, הגורם במכשיר מספק את מזהה הבחירה של המודעה הזוכה במכרז.

מפתחות של ספירת מודעות הם מספרים שלמים בעלי 32 ביט עם סימן, שהוקצו על ידי טכנולוגיית הפרסום של הקונה, והם תואמים לקבוצה נתונה של מודעות כפי שהוגדרו על ידי ה-DSP. מכיוון שמפתחות של מודעות מוגבלים רק למודעות ששייכות ל-DSP נתון, אפשר לבחור את המפתחות האלה בלי חפיפה לתרשים העלאות (histogram) של טכנולוגיית פרסום אחרת. מפתחות של מודעות משמשים להגדלת מזהי DSP ספציפיים במודעות של DSP או בתוך קהל מותאם אישית נתון, כדי לסנן מודעות ממעשי מכרז עתידיים.

אפשר להשתמש במפתחות מונים כדי לתת עדיפות למודעות שיש סיכוי גבוה יותר שהן יעניינו משתמש נתון, על סמך האינטראקציות שלו עם מודעות אחרות מטכנולוגיית פרסום נתונה של קונה. לדוגמה, מודעה שקיבלה רמת התעניינות גבוהה במכרזים על מודעות, צפיות וקליקים, מייצגת נקודה של נתונים משוערים. כדי להמחיש את הנקודה הזו: מודעה למקלות גולף ליד שמאל עשויה להצביע על כך שהמשתמש לא יהיה מעוניין במקלות ליד ימין. מסנן של מכסת תדירות שמוגדר למפתח מונה שהוקצה למודעות ליד שמאל עלול לסנן מודעות למועדונים ליד ימין.

כדי להשתמש במכסת תדירות במכרז, קודם צריך ליצור אובייקטים מסוג KeyedFrequencyCap:

Kotlin

// Value used when incrementing frequency counter
val adCounterKey = 123

// Frequency cap exceeded after 2 counts
val keyedFrequencyCapForImpression: KeyedFrequencyCap = Builder(
  adCounterKey, 2, Duration.ofSeconds(10)
).build()

// Frequency cap exceeded after 1 counts
val keyedFrequencyCapForImpression: KeyedFrequencyCap = Builder(
  adCounterKey, 1, Duration.ofSeconds(10)
).build()

Java

// Value used when incrementing frequency counter
int adCounterKey = 123;

// Frequency cap exceeded after 2 counts
KeyedFrequencyCap keyedFrequencyCapForImpression =
  new KeyedFrequencyCap.Builder(
    adCounterKey, 2, Duration.ofSeconds(10)
  ).build();

// Frequency Cap exceeded after 1 counts
KeyedFrequencyCap keyedFrequencyCapForClick =
  new KeyedFrequencyCap.Builder(
    adCounterKey, 1, Duration.ofSeconds(10)
  ).build();

אחרי שיוצרים את אובייקטי KeyedFrequencyCap, אפשר להעביר אותם לאובייקט AdFilters.

Kotlin

val filters: AdFilters = Builder()
  .setFrequencyCapFilters(
    Builder()
      .setKeyedFrequencyCapsForImpressionEvents(
        ImmutableObject.of(keyedFrequencyCapForImpression)
      )
      .setKeyedFrequencyCapsForClickEvents(
        ImmutableObject.of(keyedFrequencyCapForClick)
      )
  ).build()

Java

AdFilters filters = new AdFilters.Builder()
    .setFrequencyCapFilters(new FrequencyCapFilters.Builder()
        .setKeyedFrequencyCapsForImpressionEvents(
            ImmutableObject.of(keyedFrequencyCapForImpression)
        )
        .setKeyedFrequencyCapsForClickEvents(
            ImmutableObject.of(keyedFrequencyCapForClick)
        )
    ).build();

כשאובייקט AdFilters מאוכלס במסננים של מכסת תדירות, אפשר להעביר אותו כשיוצרים את הקהל המותאם אישית:

Kotlin

// Initialize a custom audience.
val audience: CustomAudience = Builder()
  .setBuyer(buyer)
  .setName(name)
  .setAds(
    listOf(
      Builder()
        .setRenderUri(renderUri)
        .setMetadata(JSONObject().toString())
        .setAdFilters(filters)
        .setAdCounterKeys(adCounterKeys)
        .build()
    )
  ).build()

Java

// Initialize a custom audience.
CustomAudience audience = new CustomAudience.Builder()
    .setBuyer(buyer)
    .setName(name)
    .setAds(Collections.singletonList(new AdData.Builder()
        .setRenderUri(renderUri)
        .setMetadata(new JSONObject().toString())
        .setAdFilters(filters)
        .setAdCounterKeys(adCounterKeys)
        .build()))
    .build();

כשמסננים של מכסת תדירות מוטמעים בקהל מותאם אישית, פלטפורמת ה-SSP יכולה להפעיל את אירועי הקליק, הצפייה או החשיפות הנדרשים.

Kotlin

val callerAdTech: AdTechIdentifier = mAdSelectionConfig.getSeller()

val request: UpdateAdCounterHistogramRequest = Builder(
  adSelectionId,
  FrequencyCapFilters.AD_EVENT_TYPE_CLICK,  //CLICK, VIEW, or IMPRESSION
  callerAdTech
).build()

Java

AdTechIdentifier callerAdTech = mAdSelectionConfig.getSeller();

UpdateAdCounterHistogramRequest request =
  new UpdateAdCounterHistogramRequest.Builder(
      adSelectionId,
      FrequencyCapFilters.AD_EVENT_TYPE_CLICK, //CLICK, VIEW, or IMPRESSION
      callerAdTech
).build();

מודעות שהגיעו למגבלות המסנן של מכסת התדירות שהוגדרו מראש יוסרו מהמכרז. הסינון מתבצע לפני שהלוגיקה של הבידינג מתבצעת במכרזים במכשיר, ותוך כדי יצירת עומס הנתונים במכרזים של שירותי בידינג ומכרזים.ערכת הכלים הזו מעניקה לטכנאי הפרסום גמישות להשתמש באינטראקציות בין המשתמשים לבין המודעות בקהל המותאם אישית שלהם כדי למקד את הטירגוט של המודעות תוך צמצום החשיפה העודפת למודעות.

סינון מודעות לפי הקשר ללא קריאות לרשתות

אם אין ביקוש לרימרקטינג במכשיר, אפשר להפעיל את בחירת המודעות למודעות לפי הקשר בלי קריאות לרשת. כשמשתמשים במזהי URI שנוצרו מראש וברשימה של מודעות לפי הקשר עם הצעות מחיר, הפלטפורמה יכולה לדלג על אחזור הלוגיקה של הבידינג, אותות הבידינג ואותות הדירוג. הפלטפורמה משתמשת ב-URI שנוצר מראש כדי לבחור את המודעה לפי הקשר עם הצעת המחיר הגבוהה ביותר.

כדי לשפר את זמן האחזור, טכנאי הפרסום יכולים להריץ תהליך בחירת מודעות שכולל רק מודעות לפי הקשר עם פונקציונליות של סינון מודעות, ללא קריאות לרשת. כדי לעשות זאת, משתמשים ב-URIs מוכנים מראש למתן ציונים לאותות. בקטע 'תרחישי שימוש ושמות של URI מוגדרים מראש נתמכים' מפורטת רשימה של הטמעות של scoreAds.

כדי להפעיל את בחירת המודעות בלי קריאות לרשתות:

  1. הגדרת סינון מודעות
  2. יצירת מודעות לפי הקשר
  3. יוצרים אובייקט AdSelectionConfig עם הפרטים הבאים:

    1. רשימה ריקה של קונים
    2. URI שנוצר מראש כדי לבחור את הצעת המחיר הגבוהה ביותר
    3. מודעות לפי הקשר
    4. URI ריק לאותות למתן ניקוד. אפשר להשתמש ב-URI הריק כדי לציין שאתם לא רוצים להשתמש באחזור של אותות מהימנים לצורך ניקוד:
    Uri prebuiltURIScoringUri = Uri.parse("ad-selection-prebuilt://ad-selection/highest-bid-wins/?reportingUrl=your.registered.uri/reporting");
    // Initialize AdSelectionConfig
    AdSelectionConfig adSelectionConfig =
      new AdSelectionConfig.Builder()
        .setSeller(seller)
        .setDecisionLogicUri(prebuiltURIScoringUri)
        .setCustomAudienceBuyers(Collections.emptyList())
        .setAdSelectionSignals(adSelectionSignals)
        .setSellerSignals(sellerSignals)
        .setPerBuyerSignals(perBuyerSignals)
        .setBuyerContextualAds(buyerContextualAds)
        .setTrustedScoringSignalsUri(Uri.EMPTY)
        .build();
    
  4. מריצים את הבחירה של המודעות:

    adSelectionManager.selectAds(
        adSelectionConfig,
        executor,
        outcomeReceiver);
    

הפעלת קוד JavaScript משלכם לדיווח תוך שימוש ב-URI שנוצרו מראש

נכון לעכשיו, בפלטפורמת ארגז החול לפרטיות יש רק הטמעה בסיסית של JavaScript לדיווח, שזמינה למזהי URI שנוצרו מראש. אם אתם רוצים להריץ קוד JavaScript משלכם לדיווח ועדיין להשתמש בכתובות URI מוכנות מראש לצורך בחירת מודעות עם זמן אחזור קצר, תוכלו לשנות את הערך של DecisionLogicUri בין ההפעלות של בחירת המודעות לבין ההפעלות של הדיווח.

  1. מבצעים את השלבים להפעלת בחירת מודעות למודעות לפי הקשר באמצעות כתובות URI שנוצרו מראש
  2. יצירת עותק של AdSelectionConfig לפני הפעלת הדיווח

    adSelectionConfigWithYourReportingJS = adSelectionConfig.cloneToBuilder()
      // Replace <urlToFetchYourReportingJS> with your own URL:
      .setDecisionLogicUri(Uri.parse(<urlToFetchYourReportingJS>))
      .build();
    
  3. הרצת דוחות חשיפות

    // adSelectionId is from the result of the previous selectAds run
    ReportImpressionRequest request = new ReportImpressionRequest(
      adSelectionId,
      adSelectionConfigWithYourReportingJS);
    adSelectionManager.reportImpression(
      request,
      executor,
      outcomeReceiver);
    

הפעלת רשימת רשתות בתהליך בחירת הרשת

כדי להשתמש בתהליך בחירת הרשת מסוג Waterfall, צריך כמה ערכות SDK של צד שלישי (רשתות צד שלישי) שיושקו על ידי רשת תהליך בחירת הרשת מסוג SDK של צד ראשון. תהליך בחירת הרשת (Mediation) ב-Waterfall מתבצע באותו אופן, בין שהמכרז התקיים במכשיר ובין שהוא הופעל בשירותי בידינג ומכרזים (B&A).

רשתות של צד שלישי

רשתות צד שלישי צריכות לספק מתאם שמאפשר לרשת בחירת הרשת להפעיל את השיטות הנדרשות להפעלת מכרז:

  • הרצת הבחירה של המודעות
  • דיווח על חשיפות

דוגמה למתאם רשת לבחירת רשת:

Kotlin

class NetworkAdaptor {
    private val adSelectionManager : AdSelectionManager

    init {
        adSelectionManager = context.getSystemService(AdSelectionManager::class.java)
    }

    fun selectAds() {...}

    fun reportImpressions() {...}
}

Java

class NetworkAdaptor {
    AdSelectionManager adSelectionManager;

    public NetworkAdaptor() {
        AdSelectionManager adSelectionManager =
            context.getSystemService(AdSelectionManager.class);
    }

    public void selectAds() {...}

    public void reportImpressions() {...}
}

לכל SDK יש מנהלים ולקוחות משלו של שירות בחירת המודעות, והטמעה משלו של selectAds ו-reportImpressions. ספקי SDK יכולים לעיין בקטעים בנושא הפעלת בחירת מודעות במכרזים במכשיר או במאמר ההסבר על B&A במכרזים מסוג B&A. פועלים לפי ההוראות לדיווח על חשיפות של מודעות (בהתאם לדיווח על חשיפות ב-SSP יחיד).

רשת בתהליך בחירת הרשת (Mediation)

בדומה לרשתות צד שלישי, גם ברשתות לבחירת רשת צריך להטמיע את selectAds ו-reportImpression. מידע נוסף זמין בקטעים בנושא הפעלת בחירת מודעות ודיווח על חשיפות של מודעות.

רשתות בחירת הרשת אחראיות להפעלת שרשרת בחירת הרשת ולמיקום שלהן בשרשרת. בקטע הבא מוסבר איך מגדירים ומפעילים את התהליך הזה.

אחזור של שרשרת תהליך בחירת הרשת (Mediation) וסכומים מינימלי להצעות מחיר

רשת בחירת הרשת אחראית לאחזור של מודעות לפי הקשר (1P), שרשרת בחירת הרשת וסכומי מינימום של הצעות מחיר של רשתות צד שלישי (3P). מצב כזה יכול לקרות בבקשה לאחזור מודעות לפי הקשר שמבוצעת על ידי הרשת לבחירת רשת. שרשרת תהליך בחירת הרשת קובעת איך לעבור על רשתות הצד השלישי, וניתן להעביר את סכומי מינימום הצעות המחיר לתהליך המכרז כ-adSelectionSignals.

מיקום הרשת בשרשרת לבחירת רשת

ערכת SDK לבחירת רשת יכולה למקם את עצמה בשרשרת של תהליך בחירת הרשת על סמך העלות בפועל לאלף חשיפות (eCPM) של הצעות המחיר למודעות מצד ראשון. ב-Protected Audience API, הצעות המחיר על מודעות הן מוצפנות. כדי ש-SDK לבחירת רשת יוכל להשוות בין הצעת מחיר של מודעה נתונה של צד ראשון לבין סכום רצפה של הצעת מחיר ברשת הצד השלישי הבאה בשרשרת, צריך להשתמש ב-AdSelectionFromOutcomesConfig. אם הצעת המחיר של הצד ה-1 גבוהה מסף הצעות המחיר, המשמעות היא ש-SDK של תהליך בחירת הרשת ממוקם לפני הרשת הזו של הצד השלישי.

הרצת הבחירה של המודעות

כדי לאחזר מודעת 1P מועמדת, רשת בחירת הרשת יכולה להפעיל מכרז במכשיר לפי השלבים שמפורטים בקטע הפעלת בחירת מודעה. הפעולה הזו יוצרת מודעת 1P מועמדת, הצעת מחיר ו-AdSelectionId שמשמש בתהליך בחירת הרשת.

יצירת AdSelectionFromOutcomesConfig

ה-AdSelectionFromOutcomesConfig מאפשר לרשת בחירת הרשתות להעביר רשימה של AdSelectionIds (תוצאות ממעשי בידינג קודמים), אותות לבחירת מודעות ו-URI לאחזור JavaScript שבוחר מודעה מבין כמה מועמדות. הרשימה של AdSelectionIds יחד עם הצעות המחיר והאותות מועברת ל-JavaScript, שיכול להחזיר את אחת מה-AdSelectionIds אם היא עומדת בסף הצעות המחיר, או אף אחת אם יש להמשיך בשרשרת בחירת הרשת.

רשתות לבחירת רשת יוצרות את הערך AdSelectionFromOutcomesConfig באמצעות הערך AdSelectionId של ה-1P מהקטע הקודם, ואת סכום התחלת הבידינג של הרשת של הצד השלישי שנלקחת בחשבון. צריך ליצור AdSelectionFromOutcomesConfig חדש לכל שלב בשרשרת בחירת הרשת.

Kotlin

fun  runSelectOutcome(
    adSelectionClient : AdSelectionClient,
    outcome1p : AdSelectionOutcome,
    network3p : NetworkAdapter) : ListenableFuture<AdSelectionOutcome?> {
    val config = AdSelectionFromOutcomesConfig.Builder()
        .setSeller(seller)
        .setAdSelectionIds(listOf(outcome1p))
        .setSelectionSignals({"bid_floor": bid_floor})
        .setSelectionLogicUri(selectionLogicUri)
        .build()
    return adSelectionClient.selectAds(config)
}

Java

public ListenableFuture<AdSelectionOutcome> runSelectOutcome(AdSelectionOutcome outcome1p,
                                              NetworkAdapter network3p) {
    AdSelectionFromOutcomesConfig config = new AdSelectionFromOutcomesConfig.Builder()
            .setSeller(seller)
            .setAdSelectionIds(Collection.singletonList(outcome1p))
            .setSelectionSignals({"bid_floor": bid_floor})
            .setSelectionLogicUri(selectionLogicUri)
            .build();

    return adSelectionClient.selectAds(config){}
}

כדי לשנות את השיטה selectAds() לבחירת רשת ב-Waterfall, צריך להזין את הקלט AdSelectionFromOutcomesConfig, שבו צריך לציין את הפרמטרים הנדרשים הבאים:

  • Seller: מזהה של רשת המודעות של המוכר שמפעילה את בחירת המודעות.
  • AdSelectionIds: רשימה של אירוע selectAds() קודם למודעה של צד ראשון.
  • אותות לבחירת מודעות: אובייקט JSON שעבר סריאליזציה למחרוזת, ומכיל אותות שישמשו את הלוגיקה של הבידינג של הקונה. במקרה כזה, צריך לכלול את סכום רצפת הבידינג שאוחזר עבור רשת הצד השלישי הנתונה.
  • Selection Logic URI: כתובת URL מסוג HTTPS שמופיעה בשאילתה במהלך בחירת המודעה כדי לאחזר את ה-JavaScript של רשת בחירת הרשתות לצורך בחירת המודעה הזוכה. חתימות הפונקציות הנדרשות מפורטות בקוד ה-JavaScript הזה. קוד ה-JavaScript צריך להחזיר את המודעה של הצד השלישי אם הצעת המחיר גבוהה מהסף המינימלי להצעת מחיר, או אחרת להחזיר את הערך null. כך ה-SDK של תהליך בחירת הרשת יכול לקצר את שרשרת תהליך בחירת הרשת כשנמצאת רשת מנצחת.

אחרי שיוצרים את AdSelectionOutcomesConfig, קוראים לשיטה selectAds() של רשת הצד השלישי שנמצאת בראש שרשרת הרשתות.

Kotlin

val adSelectionManager = context.getSystemService(AdSelectionManager::class.java)

// Initialize AdSelectionFromOutcomesConfig
AdSelectionFromOutcomesConfig adSelectionFromOutcomesConfig =
  AdSelectionFromOutcomesConfig.Builder()
    .setSeller(seller)
    .setAdSelectionIds(listof(outcome1p))
    .setSelectionSignals({"bid_floor": bid_floor})
    .setSelectionLogicUri(selectionLogicUri)
    .setAdSelectionIds(outcomeIds)
    .build()

// Run ad selection with AdSelectionConfig
adSelectionManager.selectAds(
    adSelectionFromOutcomesConfig,
    executor,
    outcomeReceiver)

Java

AdSelectionManager adSelectionManager =
    context.getSystemService(AdSelectionManager.class);

// Initialize AdSelectionFromOutcomesConfig
AdSelectionFromOutcomesConfig adSelectionFromOutcomesConfig =
        new AdSelectionFromOutcomesConfig.Builder()
            .setSeller(seller)
            .setAdSelectionIds(Collection.singletonList(outcome1p))
            .setSelectionSignals({"bid_floor": bid_floor})
            .setSelectionLogicUri(selectionLogicUri)
            .setAdSelectionIds(outcomeIds)
            .build();

// Run ad selection with AdSelectionConfig
adSelectionManager.selectAds(
    adSelectionFromOutcomesConfig,
    executor,
    outcomeReceiver);

תזמור של רשימת רשתות בתהליך בחירת הרשת

זהו סדר הפעולות בתהליך בחירת הרשת:

  1. מריצים את האפשרות 'בחירת מודעות מצד ראשון'.
  2. חזרה על שרשרת בחירת הרשת. בכל רשת של צד שלישי, מבצעים את הפעולות הבאות:
    1. גרסה AdSelectionFromOutcomeConfig, כולל outcomeId של הצד הראשון וסכום מינימום להצעת המחיר של ה-SDK של הצד השלישי.
    2. קוראים ל-selectAds() עם ההגדרות מהשלב הקודם.
    3. אם התוצאה לא ריקה, מחזירים את המודעה.
    4. קוראים לשיטה selectAds() של מתאם הרשת הנוכחי של ה-SDK. אם התוצאה לא ריקה, מחזירים את המודעה.
  3. אם לא נמצא זוכה בשרשרת, המערכת מחזירה את המודעה מצד הלקוח.

Kotlin

fun runWaterfallMediation(mediationChain : List<NetworkAdapter>)
  : Pair<AdSelectionOutcome, NetworkAdapter> {
    val outcome1p = runAdSelection()

    var outcome : AdSelectionOutcome
    for(network3p in mediationChain) {
      outcome = runSelectOutcome(outcome1p, network3p)
      if (outcome1p.hasOutcome() && outcome.hasOutcome()) {
          return Pair(outcome, this)
      }

      outcome = network3p.runAdSelection()
      if(outcome.hasOutcome()) {
          return Pair(outcome, network3p)
      }
    }
  return Pair(outcome1p, this)
}

Java

class MediationNetwork {
    AdSelectionManager adSelectionManager;

    public MediationNetwork() {
        AdSelectionManager adSelectionManager =
            context.getSystemService(AdSelectionManager.class);
    }

    public void runAdSelection() {...}

    public void reportImpressions() {...}

    public Pair<AdSelectionOutcome, NetworkAdapter> runWaterfallMediation(
            List<NetworkAdapter> mediationChain) {
        AdSelectionOutcome outcome1p = runAdSelection();

        AdSelectionOutcome outcome;
        for(NetworkAdapter network3p: mediationChain) {
            if (outcome1p.hasOutcome() &&
              (outcome = runSelectOutcome(outcome1p, network3p)).hasOutcome()) {
                return new Pair<>(outcome, this);
            }

            if((outcome = network3p.runAdSelection()).hasOutcome()) {
                return new Pair<>(outcome, network3p);
            }
        }
        return new Pair<>(outcome1p, this);
    }

    /* Runs comparison by creating an AdSelectionFromOutcomesConfig */
    public AdSelectionOutcome runSelectOutcome(AdSelectionOutcome outcome1p,
                                              NetworkAdapter network3p) { ... }
}

דיווח על חשיפות של מודעות

יש שני תהליכים לדיווח על חשיפת מודעה, בהתאם לאופן שבו המכרז מתנהל. אם אתם ספקי SSP שמפעילים מכרז יחיד, עליכם לפעול לפי ההוראות שבקטע הזה. אם אתם מתכננים להטמיע תהליך בחירת רשת (Mediation) מסוג מפל מים, עליכם לפעול לפי השלבים שמפורטים בקטע 'דיווח על חשיפות בתהליך בחירת רשת (Mediation) מסוג מפל מים'.

דיווח על חשיפות ב-SSP יחיד

אחרי שבוחרים מודעה מנצחת בתהליך הבחירה של המודעות, אפשר לדווח על החשיפות חזרה לפלטפורמות בצד הקונה ובצד המוכר שמשתתפות בתוכנית באמצעות השיטה AdSelectionManager.reportImpression(). כדי לדווח על חשיפת מודעה:

  1. מאתחלים אובייקט AdSelectionManager.
  2. יוצרים אובייקט ReportImpressionRequest עם מזהה בחירת המודעה.
  3. קוראים ל-method reportImpression() האסינכרוני עם האובייקט ReportImpressionRequest והאובייקטים הרלוונטיים Executor ו-OutcomeReceiver.

Java

AdSelectionManager adSelectionManager =
    context.getSystemService(AdSelectionManager.class);

// Initialize a ReportImpressionRequest
ReportImpressionRequest reportImpressionRequest =
        new ReportImpressionRequest.Builder()
                .setAdSelectionId(adSelectionId)
                .setAdSelectionConfig(adSelectionConfig)
                .build();

// Request to report the impression with the ReportImpressionRequest
adSelectionManager.reportImpression(
    reportImpressionRequest,
    executor,
    outcomeReceiver);

Kotlin

val adSelectionManager = context.getSystemService(AdSelectionManager::class.java)

// Initialize a ReportImpressionRequest
val adSelectionConfig: ReportImpressionRequest =
    ReportImpressionRequest.Builder()
        .setAdSelectionId(adSelectionId)
        .setAdSelectionConfig(adSelectionConfig)
        .build()

// Request to report the impression with the ReportImpressionRequest
adSelectionManager.reportImpression(
    reportImpressionRequest,
    executor,
    outcomeReceiver)

מאתחלים את ReportImpressionRequest עם הפרמטרים הנדרשים הבאים:

  • מזהה בחירת מודעה: מזהה ייחודי למשתמש במכשיר שמזהה בחירת מודעה מוצלחת.
  • Ad selection config: אותה הגדרה ששימשה בקריאה ל-selectAds() שמזוהה לפי מזהה בחירת המודעות שצוין.

השיטה האסינכרונית reportImpression() משתמשת באובייקט OutcomeReceiver כדי לסמן את התוצאה של קריאת ה-API.

  • הקריאה החוזרת (callback) של onResult() מציינת אם נוצרו כתובות URL לדיווח על חשיפות והבקשה תוזמנה.
  • בקריאה החוזרת onError() מצוינים התנאים האפשריים הבאים:
    • אם הקריאה מופעלת עם ארגומנט קלט לא חוקי, הערך של AdServicesException יהיה IllegalArgumentException.
    • כל שאר השגיאות מקבלות את הערך AdServicesException עם הערך IllegalStateException כגורם.

דיווח על חשיפות בתהליך בחירת הרשת (Mediation) ב-Waterfall

ערכת ה-SDK לבחירת הרשת צריכה לעקוב אחרי ערכת ה-SDK הזוכה כדי להפעיל את תהליכי הדיווח שלה. ספריות ה-SDK שמשתתפות בשרשרת בחירת הרשת צריכות לספק שיטה שדרכה המערכת לבחירת הרשת תוכל להפעיל את תהליך הדיווח שלה. כדי להטמיע דיווח משלכם ב-SDK שמשתתף במכרזים שמנוהלים על ידי צד שלישי, תוכלו לפעול לפי השלבים שלמעלה.

בעלי פלטפורמות SSP יכולים להשתמש בדוגמה הזו לקוד SDK של צד שלישי בתור אב טיפוס לאופן שבו אפשר להצטרף לתהליכי בחירת הרשת:

Pair<AdSelectionOutcome, NetworkAdapter> winnerOutcomeAndNetwork =
         mediationSdk.orchestrateMediation(mediationChain);

if (winner.first.hasOutcome()) {
      winner.second.reportImpressions(winner.first.getAdSelectionId());

נקודות קצה לדיווח על חשיפות

ה-API של חשיפות הדוח שולח בקשות HTTPS GET לנקודות קצה שסופקו על ידי הפלטפורמה בצד המוכר ועל ידי הפלטפורמה הזוכה בצד הקונה:

נקודת הקצה (endpoint) של הפלטפורמה בצד הקונה:

  • ה-API משתמש בכתובת ה-URL של לוגיקת הבידינג שצוינה בקהל המותאם אישית כדי לאחזר את ה-JavaScript שסופק על ידי הקונה, שכולל לוגיקה להחזרת כתובת URL לדיווח על חשיפות.
  • מפעילים את פונקציית ה-JavaScript‏ reportWin(), שאמורה להחזיר את כתובת ה-URL של דוח החשיפות של הקונה.

נקודת הקצה (endpoint) של הפלטפורמה בצד המוכר:

  • משתמשים בכתובת ה-URL של לוגיקה של החלטה שצוינה באובייקט AdSelectionConfig כדי לאחזר את ה-JavaScript של לוגיקה של החלטה של המוכר.
  • קוראים לפונקציית ה-JavaScript‏ reportResult(), שאמורה להחזיר את כתובת ה-URL של דוח החשיפות של המוכר.

דיווח על שירותי בידינג ומכרזים

במכרז שמתבצע בשירותי בידינג ומכרזים ייכללו בתגובה המוצפנת מהמכרז בצד השרת כל פרטי הדיווח הנדרשים, כולל כתובות URL שנוצרו לצורך דיווח על אינטראקציות עם מודעות. כשהתגובה מפענחת, כתובות ה-URL המתאימות נרשמות בפלטפורמה, כך שדיווח על מודעות ועל חשיפות מתבצע לפי אותם שלבים.

דיווח על חשיפות לפי יכולת

השיטה reportImpression() נועדה לספק את הדיווח הטוב ביותר האפשרי.

דיווח על אינטראקציות עם מודעות

Protected Audience API מספק תמיכה בדיווח על אינטראקציות מפורטות יותר עם מודעה שעבר רינדור. האינטראקציות האלה יכולות לכלול נתונים כמו משך הצפייה, קליקים, מעברים עם העכבר מעל התמונה או כל מדד שימושי אחר שאפשר לאסוף. התהליך לקבלת הדוחות האלה מורכב משני שלבים. קודם כל, הקונים והמוכרים צריכים להירשם לקבלת הדוחות האלה בקוד ה-JavaScript שלהם לדיווח. לאחר מכן, הלקוח יצטרך לדווח על האירועים האלה.

הרשמה לקבלת אירועי אינטראקציה

ההרשמה לאירועי אינטראקציה מתבצעת בפונקציות ה-JavaScript‏ reportWin() של הקונה ובפונקציות ה-JavaScript‏ reportResult() של המוכר באמצעות פונקציית JavaScript שסופקו על ידי הפלטפורמה: registerAdBeacon. כדי להירשם לקבלת דוח אירועים, צריך להפעיל את פונקציית JavaScript של הפלטפורמה מתוך הקוד של JavaScript לדיווח. בקטע הקוד הבא נעשה שימוש ב-reportWin() של הקונה, אבל הגישה זהה גם ל-reportResult().

reportWin(
  adSelectionSignals,
  perBuyerSignals,
  signalsForBuyer,
  contextualSignals,
  customAudienceSignals) {
    ...
    // Calculate reportingUri, clickUri, viewUri, and hoverUri

    registerAdBeacon({"click": clickUri, "view": viewUri, "hover": hoverUri});

    return reportingUri;
}

דיווח על אירועי אינטראקציה

אחרי שמדווחים על חשיפות, הלקוחות יכולים לדווח על האינטראקציות בחזרה לפלטפורמות הזוכות בצד הקונה ובצד המוכר שרשומים מראש, באמצעות השיטה AdSelectionManager.reportInteraction(). כדי לדווח על אירוע של מודעה:

  1. מאתחלים אובייקט AdSelectionManager.
  2. יוצרים אובייקט ReportInteractionRequest עם מזהה בחירת המודעה, מפתח האינטראקציה, נתוני האינטראקציה ויעד הדיווח.
  3. קוראים לשיטה reportInteraction() האסינכרונית עם האובייקט request ואת האובייקטים הרלוונטיים Executor ו-OutcomeReceiver.
AdSelectionManager adSelectionManager =
    context.getSystemService(AdSelectionManager.class);

// Initialize a ReportInteractionRequest
ReportInteractionRequest request =
  new ReportInteractionRequest.Builder()
    .setAdSelectionId(adSelectionId)
    .setInteractionKey("view")
    .setInteractionData("{ viewTimeInSeconds : 1 }") // Can be any string
    .setReportingDestinations(
      FLAG_REPORTING_DESTINATION_BUYER | FLAG_REPORTING_DESTINATION_SELLER
    )
    .build();

// Request to report the impression with the ReportImpressionRequest
adSelectionManager.reportInteraction(
  reportImpressionRequest,
  executor,
  outcomeReceiver);

מאתחלים את ReportInteractionRequest עם הפרמטרים הנדרשים הבאים:

  • Ad selection ID: מזהה של בחירת מודעה שאוחזר מ-AdSelectionOutcome שהוחזר בעבר.
  • מפתח אינטראקציה: מפתח מחרוזת שהלקוח מגדיר ומתאר את הפעולה שעליה מדווחים. המפתח הזה צריך להיות זהה למפתח שרשום על ידי המוכר או הקונה בפונקציות ה-JavaScript לדיווח.
  • נתוני אינטראקציה: מחרוזת שמכילה נתונים שייכללו בדוח האירועים, ויש להעביר אותם ב-POST חזרה לשרתי הדיווח.
  • יעדי הדיווח: מסכת ביטים שמציינת אם צריך לדווח על האירועים לקונה, למוכר או לשניהם. הדגלים האלה מסופקים על ידי הפלטפורמה, וניתן ליצור את מסכת היעד הסופית באמצעות פעולות בייט-בייט. כדי לדווח ליעד אחד, אפשר להשתמש בדגל שסופק ישירות על ידי הפלטפורמה. כדי לדווח לכמה יעדים, אפשר להשתמש ב-OR בייטבי (|) כדי לשלב בין ערכי הדגלים.

השיטה האסינכרונית reportInteraction() משתמשת באובייקט OutcomeReceiver כדי לסמן את התוצאה של קריאת ה-API.

  • קריאת החזרה (callback) של onResult() מציינת שהקריאה לדיווח על אינטראקציה תקינה.
  • בקריאה החוזרת onError() מצוינים התנאים האפשריים הבאים:
    • אם הקריאה מתבצעת כשהאפליקציה פועלת ברקע, מוחזר IllegalStateException עם תיאור של הכישלון.
    • אם הלקוח מושהה מהקריאה ל-reportInteraction(), מוחזר הערך LimitExceededException.
    • אם החבילה לא רשומה לקריאה לממשקי ה-API לשמירה על הפרטיות, מוחזר הערך SecurityException().
    • אם האפליקציה שמדווחת על אינטראקציות שונה מהאפליקציה שקראה ל-selectAds(), המערכת מחזירה את הערך IllegalStateException.
  • אם המשתמש לא הביע הסכמה להפעלת ממשקי ה-API של ארגז החול לפרטיות, הקריאה תיכשל ללא הודעה.

נקודות קצה לדיווח על אינטראקציות

ה-API של אינטראקציית הדוח מנפיק בקשות HTTPS POST לנקודות קצה שסופקו על ידי הפלטפורמה של הצד המוכר והפלטפורמה הזוכה של הצד הקונה. Protected Audience יתאים את מפתחות האינטראקציה למזהי ה-URI שהוצהרו ב-JavaScript לדיווח, וישלח בקשת POST לכל נקודת קצה לכל אינטראקציה שמדווחת. השדה Content-Type של הבקשה הוא טקסט פשוט, והגוף הוא נתוני האינטראקציה.

דיווח על אינטראקציות – ניסיון כמיטב יכולתנו

ה-reportInteraction() נועד לספק דיווח כמיטב יכולתו באמצעות HTTP POST.

עדכון יומי ברקע

כשאתם יוצרים קהל בהתאמה אישית, האפליקציה או ה-SDK יכולים לאתחל את המטא-נתונים של הקהל בהתאמה אישית. בנוסף, הפלטפורמה יכולה לעדכן את החלקים הבאים של מטא-נתונים מותאמים אישית של קהלים באמצעות תהליך עדכון ברקע שמתבצע מדי יום.

  • אותות בידינג של משתמשים
  • נתוני בידינג מהימנים
  • רשימה אחת (AdData)

התהליך הזה שולח שאילתות לכתובת ה-URL לעדכון יומי שמוגדרת בקהל המותאם אישית, וייתכן שכתובת ה-URL תחזיר תגובה בפורמט JSON.

  • תגובת ה-JSON עשויה להכיל כל אחד משדות המטא-נתונים הנתמכים שצריך לעדכן.
  • כל שדה JSON מאומת בנפרד. הלקוח מתעלם משדות בפורמט שגוי, וכתוצאה מכך לא מתבצעים עדכונים בשדה הספציפי הזה בתשובה.
  • תגובת HTTP ריקה או אובייקט JSON ריק מסוג '{}' לא יגרמו לעדכוני מטא-נתונים.
  • גודל הודעת התגובה חייב להיות מוגבל ל-10KB.
  • חובה להשתמש ב-HTTPS בכל מזהי ה-URI.
  • trusted_bidding_uri חייב להיות בעל אותו ETLD+1 כמו הקונה.

דוגמה: תגובת JSON לעדכון יומי ברקע

{
    "user_bidding_signals" : { ... },  // Valid JSON object
    "trusted_bidding_data" : {
        "trusted_bidding_uri" : 'example-dsp1-key-value-service.com',
        "trusted_bidding_keys" : [ 'campaign123', 'campaign456', ... ]
    },
    'ads' : [
        {
            "render_uri" : 'www.example-dsp1.com/.../campaign123.html',
            'metadata' : { ... }  // Valid JSON object
        },
        {
            "render_uri" : 'www.example-dsp1.com/.../campaign456.html',
            'metadata' : { ... }  // Valid JSON object
        },
        ...
    ]
}

JavaScript לבחירת מודעות

תהליך העבודה של בחירת המודעות מרכז את ההפעלה של קוד JavaScript שסופק על ידי הקונה וקוד JavaScript שסופק על ידי המוכר.

ה-JavaScript שסופק על ידי הקונה מאוחזר מכתובת ה-URL של לוגיקה הבידינג שצוינה בקהל המותאם אישית. קוד ה-JavaScript המוחזר צריך לכלול את הפונקציות הבאות:

JavaScript שסופק על ידי המוכר מאוחזר מכתובת ה-URL של לוגיקה ההחלטה שצוינה בפרמטר AdSelectionConfig ב-API לבחירת מודעות. קוד ה-JavaScript המוחזר צריך לכלול את הפונקציות הבאות:

generateBid()‎

function generateBid(
  ad,
  auction_signals,
  per_buyer_signals,
  trusted_bidding_signals,
  contextual_signals,
  user_signals,
  custom_audience_bidding_signals) {
  return {'status': 0, 'ad': ad, 'bid': ad.metadata.result };
}

פרמטרים של קלט:

  • ad: אובייקט JSON בפורמט var ad = { 'render_url': url, 'metadata': json_metadata };
  • auction_signals, per_buyer_signals: אובייקטי JSON שצוינו באובייקט ההגדרות של המכרז
  • custom_audience_bidding_signals: אובייקט JSON שנוצר על ידי הפלטפורמה. הפורמט של אובייקט ה-JSON הזה הוא:

    var custom_audience_signals = {
      "owner":"ca_owner",
      "buyer":"ca_buyer",
      "name":"ca_name",
      "activation_time":"ca_activation_time_epoch_ms",
      "expiration_time":"ca_expiration_time_epoch_ms",
      "user_bidding_signals":"ca_user_bidding_signals"
    }
    

    כאשר:

    • owner,‏ buyer ו-name הן מחרוזות שנלקחות מהנכסים עם אותו שם של הקהל בהתאמה אישית שמשתתף בבחירת המודעות
    • activation_time ו-expiration_time הם זמן ההפעלה ותוקף התפוגה של הקהל המותאם אישית, שמוצגים בשניות מאז ראשית זמן יוניקס
    • ca_user_bidding_signals היא מחרוזת JSON שצוינה בשדה userBiddingSignals של CustomAudience בזמן היצירה
    • trusted_bidding_signals, contextual_signals ו-user_signals הם אובייקטים של JSON. הם מועברים כאובייקטים ריקים, והם יאוכלסו בגרסאות עתידיות. הפלטפורמה לא אוכפת את הפורמט שלהם, והוא מנוהל על ידי טכנולוגיית הפרסום.

תוצאה:

  • ad: זו המודעה שהצעת המחיר מתייחסת אליה. הסקריפט רשאי להחזיר עותק של המודעה שהוא קיבל עם מטא-נתונים שונים. המאפיין render_url של המודעה אמור להישאר ללא שינוי.
  • bid: ערך של float שמייצג את ערך הצעת המחיר של המודעה הזו
  • status: ערך שלם שיכול להיות:
    • 0: להרצה מוצלחת
    • 1: (או כל ערך שאינו אפס) אם אחד מאותות הקלט לא תקין. אם הפונקציה generate-bid מחזירה ערך שאינו אפס, תהליך הבידינג לא חוקי לכל המודעות בקמפיינים לרשת המדיה.

scoreAd()

function scoreAd(
  ad,
  bid,
  ad_selection_config,
  seller_signals,
  trusted_scoring_signals,
  contextual_signal,
  user_signal,
  custom_audience_signal) {
    return {'status': 0, 'score': score };
}

פרמטרים של קלט:

  • ad: מסמכי התיעוד של generateBid
  • bid: ערך הצעת המחיר למודעה
  • ad_selection_config: אובייקט JSON שמייצג את הפרמטר AdSelectionConfig של ה-API‏ selectAds. הפורמט הוא:

    var ad_selection_config = {
      'seller': 'seller',
      'decision_logic_url': 'url_of_decision_logic',
      'custom_audience_buyers': ['buyer1', 'buyer2'],
      'auction_signals': auction_signals,
      'per_buyer_signals': per_buyer_signals,
      'contextual_ads': [ad1, ad2]
    }
    
  • seller_signals: אובייקטי JSON שנקראו מהפרמטר sellerSignals AdSelectionConfig ב-API

  • trusted_scoring_signal: קריאה מהשדה adSelectionSignals בפרמטר ה-API AdSelectionConfig

  • contextual_signals, user_signals: אובייקטים מסוג JSON. הם מועברים כאובייקטים ריקים, והם יאוכלסו בגרסאות עתידיות. הפלטפורמה לא אוכפת את הפורמט שלהם, והוא מנוהל על ידי חברת טכנולוגיית הפרסום.

  • per_buyer_signals: אובייקט JSON שנקרא מהמפה perBuyerSignal בפרמטר ה-API AdSelectionConfig, כאשר המפתח הוא הקונה הנוכחי של Custom Audience. הערך יהיה ריק אם המפה לא מכילה רשומה של הקונה הנתון.

פלט:

  • score: ערך של float שמייצג את ערך הציון של המודעה הזו
  • status: ערך שלם שיכול להיות:
    • 0: להרצה מוצלחת
    • 1: אם הערכים של customAudienceSignals לא חוקיים
    • 2: אם הערך של AdSelectionConfig לא חוקי
    • 3: אם אחד מהאותות האחרים לא תקף
    • כל ערך שאינו אפס גורם לכישלון התהליך, והערך קובע את סוג החריגה שתופעל

selectOutcome()

function selectOutcome(
  outcomes,
  selection_signals) {
    return {'status': 0, 'result': null};
}

פרמטרים של קלט:

  • outcomes: אובייקט JSON {"id": id_string, "bid": bid_double}
  • selection_signals: אובייקטי JSON שצוינו באובייקט התצורה של המכרז

פלט:

  • status: 0 אם הפעולה בוצעה בהצלחה, ערך שאינו אפס אם הפעולה נכשלה
  • result: אחת מהתוצאות שהועברו או null

reportResult()

function reportResult(ad_selection_config, render_url, bid, contextual_signals) {
   return {
      'status': status,
      'results': {'signals_for_buyer': signals_for_buyer, 'reporting_url': reporting_url }
   };
}

פרמטרים של קלט:

  • ad_selection_config: עיינו במסמכי התיעוד של scoreAds
  • render_url: כתובת ה-URL של ה-render של המודעה הזוכה
  • bid: הצעת המחיר שהוגשה עבור המודעה הזוכה
  • contextual_signals: עיינו במסמכי התיעוד של generateBid

פלט:

  • status: 0 עבור הצלחה ומספר שאינו אפס עבור כישלון
  • results: אובייקט JSON שמכיל:
    • signals_for_buyer: אובייקט JSON שמוענק לפונקציה reportWin
    • reporting_url: כתובת URL שבה הפלטפורמה משתמשת כדי להודיע על החשיפות לקונה

reportWin()‎

function reportWin(
   ad_selection_signals,
   per_buyer_signals,
   signals_for_buyer,
   contextual_signals,
   custom_audience_signals) {
   return {'status': 0, 'results': {'reporting_url': reporting_url } };
}

פרמטרים של קלט:

  • ad_selection_signals, per_buyer_signals: עיינו במסמכי התיעוד של scoreAd
  • signals_for_buyer: אובייקט JSON שמוחזר על ידי reportResult
  • contextual_signals, custom_audience_signals: ראו את המסמכים של generateBid

פלט:

  • status: 0 עבור הצלחה ומספר שאינו אפס עבור כישלון
  • results: אובייקט JSON שמכיל:
    • reporting_url: כתובת URL שבה הפלטפורמה משתמשת כדי להודיע למוכרים על החשיפות

registerAdBeacon()

function registerAdBeacon(
  beacons
)

פרמטרים של קלט:

  • beacons: אובייקט שמכיל צמדי מפתח/ערך של מפתחות אינטראקציה ומזהי URI לדיווח. הפורמט הוא:

    let beacons = {
      'interaction_key': 'reporting_uri',
      'interaction_key': 'reporting_uri',
      ...
    }
    
    • interaction_key: מחרוזת שמייצגת את האירוע. הפלטפורמה משתמשת בו מאוחר יותר, כשהיא מדווחת על אינטראקציות עם אירועים, כדי לחפש את reporting_uri שצריך לשלוח אליו התראה. המפתח הזה צריך להתאים למה שהקונה או המוכר רושמים ולמה שהמוכר מדווח.
    • reporting_uri: URI לקבלת דוחות אירועים. הוא צריך להיות ספציפי לסוג האירוע שעליו מדווחים. הוא צריך לקבל בקשת POST כדי לטפל בכל הנתונים שדווחו יחד עם האירוע.

    לדוגמה:

      let beacons = {
        'click': 'https://reporting.example.com/click_event',
        'view': 'https://reporting.example.com/view_event'
      }
    

מזהי URI מוכנים מראש לבחירת מודעות

כתובות URI מוכנות מראש מאפשרות לטכנולוגיות הפרסום להקצות פונקציות JavaScript ללוגיקה של קבלת ההחלטות לגבי בחירת מודעות בכיתות AdSelectionConfig ו-AdSelectionFromOutcomesConfig. מזהי URI שנוצרו מראש לא דורשים קריאות לרשת כדי להוריד את ה-JavaScript התואם. טכנולוגיות הפרסום יכולות להשתמש במזהי URI שנוצרו מראש, בלי שתצטרכו להגדיר דומיין רשום לאירוח ה-JavaScript.

URI שנוצר מראש נוצר לפי הפורמט הבא:

ad-selection-prebuilt:<use-case>/<name>?<required-script-generation-parameters>

פלטפורמת ארגז החול לפרטיות מספקת JavaScript באמצעות המידע מה-URI הזה בסביבת זמן הריצה.

IllegalArgumentException יושלח אם:

  • אחד מהפרמטרים הנדרשים לא נמצא ב-URI
  • יש פרמטרים לא מזוהים ב-URI

שמות ותרחישי שימוש נתמכים של URI מובנה

תרחיש לדוגמה 1: בחירת מודעות

בתרחישים לדוגמה ad-selection ו-selectAds(AdSelectionConfig) יש תמיכה במזהי URI שנוצרו מראש.

שם URI שנוצר מראש: highest-bid-wins

ה-URI שנוצר מראש מספק JavaScript שבוחר את המודעה עם הצעת המחיר הגבוהה ביותר אחרי הבידינג. הוא גם מספק פונקציית דיווח בסיסית לדיווח על הערכים של render_uri ו-bid של המנצח.

פרמטרים נדרשים

reportingUrl: כתובת ה-URL הבסיסית לדיווח, שמכילה את הפרמטרים render_uri ו-bid של המודעה הזוכה:

<reportingUrl>?render_uri=<renderUriOfWinnigAd>&bid=<bidOfWinningAd>

שימוש

אם כתובת ה-URL הבסיסית לדיווח היא https://www.ssp.com/reporting, ה-URI שנוצר מראש יהיה:

`ad-selection-prebuilt://ad-selection/highest-bid-wins/?reportingUrl=https://www.ssp.com/reporting`

תרחיש לדוגמה 2: ad-selection-from-outcomes

כתובות URI מוכנות מראש במסגרת תרחיש השימוש ad-selection-from-outcomes תומכות בתהליך העבודה של selectAds(AdSelectionFromOutcomesConfig).

שם URI שנוצר מראש: waterfall-mediation-truncation

ה-URI המובנה מראש waterfall-mediation-truncation מספק JavaScript שמטמיע לוגיקה של קיצור רשימת הרשתות בתהליך בחירת הרשת, שבה ה-JavaScript מחזיר מודעה מצד ראשון אם הערך של bid גבוה מ-bid floor או שווה לו, ובמקרים אחרים מחזיר את הערך null.

פרמטרים נדרשים

bidFloor: המפתח של ערך סכום המינימום של הצעת המחיר שהועברו ב-getSelectionSignals(), שמשויך למודעה של ה-SDK לבחירת רשת.

שימוש

אם אותות בחירת המודעות נראים כך: {"bid_floor": 10}, ה-URI שנוצר מראש יהיה:

`ad-selection-prebuilt://ad-selection-from-outcomes/waterfall-mediation-truncation/?bidFloor=bid_floor`

בדיקה

כדי לעזור לכם להתחיל להשתמש ב-Protected Audience API, יצרנו אפליקציות לדוגמה ב-Kotlin וב-Java. אפשר למצוא אותן ב-GitHub.

דרישות מוקדמות

כדי להשתמש ב-Protected Audience API, צריך להשתמש ב-JavaScript במהלך בחירת המודעות ובדיווח על חשיפות. יש שתי שיטות להוספת הקוד של JavaScript בסביבת בדיקה:

  • מריצים שרת עם נקודות הקצה הנדרשות מסוג HTTPS שמחזירות את ה-JavaScript
  • שינוי ברירת המחדל של אחזור מרחוק על ידי מתן הקוד הנדרש ממקור מקומי

בשני המקרים צריך להגדיר נקודת קצה מסוג HTTPS לדיווח על חשיפות.

נקודות קצה מסוג HTTPS

כדי לבדוק את בחירת המודעות ואת הדיווח על חשיפות, צריך להגדיר 7 נקודות קצה מסוג HTTPS שיהיו נגישות למכשיר הבדיקה או למהדר:

  1. נקודת קצה של קונה שמציגה את קוד ה-JavaScript של לוגיקת הבידינג.
  2. נקודת קצה שמציגה את אותות הבידינג.
  3. נקודת קצה של המוכר שמציגה את JavaScript של לוגיקה ההחלטה.
  4. נקודת קצה שמציגה אותות דירוג.
  5. נקודת הקצה לדיווח על חשיפות של הקונה המנצח.
  6. נקודת קצה לדיווח על חשיפות של מוכרים.
  7. נקודת קצה (endpoint) להצגת העדכונים היומיים של קהל מותאם אישית.

לנוחותכם, במאגר GitHub יש קוד JavaScript בסיסי למטרות בדיקה. הוא כולל גם הגדרות שירות של OpenAPI שאפשר לפרוס בפלטפורמה נתמכת של מיקרו-שירותים או של מודל לדוגמה. פרטים נוספים זמינים בקובץ README של הפרויקט.

שינוי אוטומטי של אחזור JavaScript מרחוק

התכונה הזו מיועדת לבדיקה מקצה לקצה. כדי לשנות את הגדרת האחזור מרחוק, האפליקציה צריכה לפעול במצב ניפוי באגים עם אפשרויות למפתחים מופעלות.

כדי להפעיל את מצב ניפוי הבאגים באפליקציה, מוסיפים את השורה הבאה למאפיין application בקובץ AndroidManifest.xml:

<application
  android:debuggable="true">

דוגמה לשימוש בהחרגות האלה מופיעה באפליקציית Protected Audience API לדוגמה ב-GitHub.

צריך להוסיף קוד JavaScript מותאם אישית כדי לטפל בתהליכים של בחירת מודעות, כמו בידינג, החלטות לגבי ניקוד ודיווח. במאגר GitHub תוכלו למצוא דוגמאות לקוד JavaScript בסיסי שמטפל בכל הבקשות הנדרשות. באפליקציית הדוגמה של Protected Audience API מוסבר איך לקרוא קוד מהקובץ הזה ולהכין אותו לשימוש כביטול.

אפשר לשנות את ברירת המחדל של אחזור JavaScript בצד המכירה ובצד הקנייה בנפרד, אבל צריך נקודת קצה מסוג HTTPS כדי להציג כל JavaScript שלא סיפקת עבורו שינוי ברירת מחדל. במאמר README מוסבר איך מגדירים שרת שיטפל בבקשות כאלה.

אפשר לשנות את ברירת המחדל של אחזור JavaScript רק לגבי קהלים מותאמים אישית שבבעלות החבילה שלכם.

שינוי של JavaScript בצד המכירה

כדי להגדיר שינוי של JavaScript בצד המכירה, מבצעים את הפעולות הבאות, כפי שמתואר בדוגמת הקוד הבאה:

  1. מאתחלים אובייקט AdSelectionManager.
  2. אחזור הפניה אל TestAdSelectionManager מהאובייקט AdSelectionManager.
  3. יוצרים אובייקט AdSelectionConfig.
  4. יוצרים AddAdSelectionOverrideRequest עם האובייקט AdSelectionConfig ועם String שמייצג את ה-JavaScript שבו אתם מתכוונים להשתמש כביטול.
  5. קוראים לשיטה האסינכרונית overrideAdSelectionConfigRemoteInfo() עם האובייקט AddAdSelectionOverrideRequest והאובייקטים הרלוונטיים Executor ו-OutcomeReceiver.

Kotlin

val testAdSelectionManager: TestAdSelectionManager =
  context.getSystemService(AdSelectionManager::class.java).getTestAdSelectionManager()

// Initialize AdSelectionConfig =
val adSelectionConfig = new AdSelectionConfig.Builder()
    .setSeller(seller)
    .setDecisionLogicUrl(decisionLogicUrl)
    .setCustomAudienceBuyers(customAudienceBuyers)
    .setAdSelectionSignals(adSelectionSignals)
    .setSellerSignals(sellerSignals)
    .setPerBuyerSignals(perBuyerSignals)
    .build()

// Initialize AddAddSelectionOverrideRequest
val request = AddAdSelectionOverrideRequest.Builder()
    .setAdSelectionConfig(adSelectionConfig)
    .setDecisionLogicJs(decisionLogicJS)
    .build()

// Run the call to override the JavaScript for the given AdSelectionConfig
// Note that this only takes effect in apps marked as debuggable
testAdSelectionManager.overrideAdSelectionConfigRemoteInfo(
    request,
    executor,
    outComeReceiver)

Java

TestAdSelectionManager testAdSelectionManager =
  context.getSystemService(AdSelectionManager.class).getTestAdSelectionManager();

// Initialize AdSelectionConfig =
AdSelectionConfig adSelectionConfig = new AdSelectionConfig.Builder()
    .setSeller(seller)
    .setDecisionLogicUrl(decisionLogicUrl)
    .setCustomAudienceBuyers(customAudienceBuyers)
    .setAdSelectionSignals(adSelectionSignals)
    .setSellerSignals(sellerSignals)
    .setPerBuyerSignals(perBuyerSignals)
    .build();

// Initialize AddAddSelectionOverrideRequest
AddAdSelectionOverrideRequest request = AddAdSelectionOverrideRequest.Builder()
    .setAdSelectionConfig(adSelectionConfig)
    .setDecisionLogicJs(decisionLogicJS)
    .build();

// Run the call to override the JavaScript for the given AdSelectionConfig
// Note that this only takes effect in apps marked as debuggable
testAdSelectionManager.overrideAdSelectionConfigRemoteInfo(
    request,
    executor,
    outComeReceiver);

בקטע הפעלת בחירת מודעות מוסבר מה מייצג כל אחד מהשדות ב-AdSelectionConfig. ההבדל העיקרי הוא שאפשר להגדיר את decisionLogicUrl לערך placeholder כי הוא יתעלם.

כדי לשנות את ה-JavaScript שמשמש במהלך בחירת המודעה, ה-decisionLogicJs צריך להכיל את חתימות הפונקציות המתאימות בצד המוכר. דוגמה לקריאת קובץ JavaScript כמחרוזת מופיעה באפליקציה לדוגמה של Protected Audience API ב-GitHub.

השיטה האסינכרונית overrideAdSelectionConfigRemoteInfo() משתמשת באובייקט OutcomeReceiver כדי לסמן את התוצאה של קריאת ה-API.

קריאת החזרה (callback) של onResult() מציינת שהשינוי הוגדר בהצלחה. בקריאות עתידיות ל-selectAds(), המערכת תשתמש בלוגיקה של ההחלטה והדיווח שהעברתם כעקיפה.

קריאת החזרה (call back) של onError() מציינת שני תנאים אפשריים:

  • אם תנסו לשנות את ההגדרה באמצעות ארגומנטים לא חוקיים, הערך AdServiceException יציין ש-IllegalArgumentException הוא הסיבה לכך.
  • אם ניסיתם לבטל את ההגדרה המקורית באפליקציה שלא פועלת במצב ניפוי באגים עם אפשרויות הפיתוח מופעלות, הערך AdServiceException יציין את הערך IllegalStateException כגורם.

איפוס שינויים מברירת המחדל בצד המכירה

בקטע הזה נניח שהחרגתם את ה-JavaScript בצד המכירה ושיש לכם הפניה למשתנים TestAdSelectionManager ו-AdSelectionConfig ששימשו בקטע הקודם.

כדי לאפס את ההחרגות לכל AdSelectionConfigs:

  1. קוראים ל-method resetAllAdSelectionConfigRemoteOverrides() האסינכרוני עם האובייקט הרלוונטי OutcomeReceiver.

Kotlin

// Resets overrides for all AdSelectionConfigs
testAadSelectionManager.resetAllAdSelectionConfigRemoteOverrides(
  outComeReceiver)

Java

// Resets overrides for all AdSelectionConfigs
testAdSelectionManager.resetAllAdSelectionConfigRemoteOverrides(
    outComeReceiver);

אחרי שמאפסים את ההחרגות בצד המכירה, הקריאות ל-selectAds() משתמשות ב-decisionLogicUrl ששמור ב-AdSelectionConfig כדי לנסות לאחזר את ה-JavaScript הנדרש.

אם הקריאה ל-resetAllAdSelectionConfigRemoteOverrides() נכשלת, הקריאה החוזרת (callback) של OutComeReceiver.onError() תספק AdServiceException. אם מנסים להסיר את ההחרגות כשהאפליקציה לא פועלת במצב ניפוי באגים עם אפשרויות הפיתוח מופעלות, הערך IllegalStateException יופיע ב-AdServiceException כסימן לכך שזו הסיבה.

שינוי של JavaScript בצד הקונה

  1. פועלים לפי השלבים להצטרפות לקהל בהתאמה אישית
  2. יוצרים את הפרמטר AddCustomAudienceOverrideRequest עם הקונה והשם של הקהל המותאם אישית שרוצים לשנות, בנוסף ללוגיקה של הבידינג ולנתונים שבהם רוצים להשתמש כשינוי מברירת המחדל.
  3. קוראים ל-method overrideCustomAudienceRemoteInfo() האסינכרוני עם האובייקט AddCustomAudienceOverrideRequest והאובייקטים הרלוונטיים Executor ו-OutcomeReceiver.

Kotlin

val testCustomAudienceManager: TestCustomAudienceManager =
  context.getSystemService(CustomAudienceManager::class.java).getTestCustomAudienceManager()

// Join custom audience

// Build the AddCustomAudienceOverrideRequest
val request = AddCustomAudienceOverrideRequest.Builder()
    .setBuyer(buyer)
    .setName(name)
    .setBiddingLogicJs(biddingLogicJS)
    .setTrustedBiddingSignals(trustedBiddingSignals)
    .build()

// Run the call to override JavaScript for the given custom audience
testCustomAudienceManager.overrideCustomAudienceRemoteInfo(
    request,
    executor,
    outComeReceiver)

Java

TestCustomAudienceManager testCustomAudienceManager =
  context.getSystemService(CustomAudienceManager.class).getTestCustomAudienceManager();

// Join custom audience

// Build the AddCustomAudienceOverrideRequest
AddCustomAudienceOverrideRequest request =
    AddCustomAudienceOverrideRequest.Builder()
        .setBuyer(buyer)
        .setName(name)
        .setBiddingLogicJs(biddingLogicJS)
        .setTrustedBiddingSignals(trustedBiddingSignals)
        .build();

// Run the call to override JavaScript for the given custom audience
testCustomAudienceManager.overrideCustomAudienceRemoteInfo(
    request,
    executor,
    outComeReceiver);

הערכים של buyer ו-name הם אותם ערכים ששימשו ליצירת הקהל המותאם אישית. מידע נוסף על השדות האלה

בנוסף, אפשר לציין שני פרמטרים נוספים:

  • biddingLogicJs: JavaScript שמכיל את הלוגיקה של הקונה שמשמש במהלך בחירת המודעה. חתימות הפונקציות הנדרשות מפורטות בקוד ה-JavaScript הזה.
  • trustedBiddingSignals: אותות בידינג שישמשו לבחירת מודעות. למטרות בדיקה, אפשר להשתמש במחרוזת ריקה.

השיטה האסינכרונית overrideCustomAudienceRemoteInfo() משתמשת באובייקט OutcomeReceiver כדי לסמן את התוצאה של קריאת ה-API.

קריאת החזרה (callback) של onResult() מציינת שהשינוי הוגדר בהצלחה. בקריאות הבאות ל-selectAds() נעשה שימוש בלוגיקה של הבידינג והדיווח שהעברתם כעקיפה.

קריאת החזרה (callback) של onError() מציינת שני תנאים אפשריים.

  • אם תנסו לשנות את ההגדרה באמצעות ארגומנטים לא חוקיים, הערך AdServiceException יציין ש-IllegalArgumentException הוא הסיבה לכך.
  • אם ניסיתם לבטל את ההגדרה המקורית באפליקציה שלא פועלת במצב ניפוי באגים עם אפשרויות הפיתוח מופעלות, הערך AdServiceException יציין את הערך IllegalStateException כגורם.

איפוס שינויים מצד הקונה

בקטע הזה נניח שהחרגתם את JavaScript בצד הקונה ושיש לכם הפניה ל-TestCustomAudienceManager שנעשה בו שימוש בקטע הקודם.

כדי לאפס את ההחרגות לכל הקהלים המותאמים אישית:

  1. קוראים לשיטה האסינכרונית resetAllCustomAudienceOverrides() עם אובייקטים רלוונטיים של Executor ו-OutcomeReceiver.

Kotlin

// Resets overrides for all custom audiences
testCustomAudienceManager.resetCustomAudienceRemoteInfoOverride(
    executor,
    outComeReceiver)

Java

// Resets overrides for all custom audiences
testCustomAudienceManager.resetCustomAudienceRemoteInfoOverride(
    executor,
    outComeReceiver)

אחרי שמאפסים את ההחרגות מצד הקונה, קריאות חוזרות ל-selectAds() משתמשות ב-biddingLogicUrl וב-trustedBiddingData ששמורים ב-CustomAudience כדי לנסות לאחזר את ה-JavaScript הנדרש.

אם הקריאה ל-resetCustomAudienceRemoteInfoOverride() נכשלת, הקריאה החוזרת (callback) של OutComeReceiver.onError() תספק AdServiceException. אם מנסים להסיר את ההחרגות כשהאפליקציה לא פועלת במצב ניפוי באגים עם אפשרויות הפיתוח מופעלות, הערך IllegalStateException יופיע ב-AdServiceException כסימן לכך שזו הסיבה.

הגדרת שרת דיווח

כשמשתמשים בשינויים אוטומטיים של אחזור מרחוק, עדיין צריך להגדיר שרת שהמכשיר או הסימולטור יוכלו לגשת אליו כדי להגיב לאירועי הדיווח. מספיק להשתמש בנקודת קצה שמחזירה 200 לצורך בדיקה. המאגר ב-GitHub כולל הגדרות שירות של OpenAPI שאפשר לפרוס בפלטפורמת מודל או בפלטפורמת מיקרו-שירותים נתמכת. פרטים נוספים זמינים בקובץ README של הפרויקט.

כשמחפשים את הגדרות OpenAPI, מחפשים את הקובץ reporting-server.json. הקובץ הזה מכיל נקודת קצה שמחזירה את הערך 200, שמייצג קוד תגובה של HTTP. נקודת הקצה הזו משמשת במהלך selectAds() ומאותתת ל-Protected Audience API שהדיווח על החשיפות הושלם בהצלחה.

הפונקציונליות לבדיקה

  • תרגול של הצטרפות או עזיבה והגדרה של קהל בהתאמה אישית על סמך פעולות קודמות של משתמשים.
  • איך מפעילים את בחירת המודעות במכשיר באמצעות קוד JavaScript שמתארח מרחוק.
  • לבדוק איך השיוך של אפליקציה להגדרות של קהלים מותאמים אישית עשוי להשפיע על תוצאות בחירת המודעות.
  • להפעיל דיווח על חשיפות אחרי בחירת המודעה.

מגבלות

בטבלה הבאה מפורטות המגבלות על העיבוד של Protected Audience API. המגבלות המוצגות עשויות להשתנות על סמך משוב. בנתוני הגרסה תוכלו לקרוא על יכולות שעדיין נמצאות בתהליך פיתוח.

רכיב תיאור המגבלה ערך המגבלה
קהל בהתאמה אישית (CA) המספר המקסימלי של מודעות לכל רשות אישורים 100
המספר המקסימלי של רשויות אישורים לכל אפליקציה 1000
המספר המקסימלי של אפליקציות שיכולות ליצור רשות אישורים 1000
העיכוב המקסימלי בזמן ההפעלה של רשות אישורים ממועד היצירה שלה 60 ימים
מועד התפוגה המקסימלי של רשות אישורים מרגע ההפעלה שלה 60 ימים
המספר המקסימלי של רשויות אישורים במכשיר 4000
הגודל המקסימלי של שם הרשות 200 בייטים
הגודל המקסימלי של URI לאחזור יומי 400 בייטים
הגודל המקסימלי של URI של לוגיקה של בידינג 400 בייטים
הגודל המקסימלי של נתוני בידינג מהימנים 10 KB
הגודל המקסימלי של אותות בידינג של משתמשים 10 KB
שיעור השיחות המקסימלי ל-leaveCustomAudience לכל קונה 1 לשנייה
שיעור השיחות המקסימלי ל-joinCustomAudience לכל קונה 1 לשנייה
אחזור ברקע ב-CA פג הזמן הקצוב של החיבור ‫5 שניות
הזמן הקצוב לתפוגת הקריאה ב-HTTP ‫30 שניות
גודל ההורדה הכולל המקסימלי 10 KB
משך הזמן המקסימלי של מחזור אחזור 5 דקות
המספר המקסימלי של רשויות אישורים שמתעדכנות בכל משימה 1000
בחירת מודעות מספר הקונים המקסימלי טרם נקבע
המספר המקסימלי של רשויות אישורים לכל קונה טרם נקבע
המספר המקסימלי של מודעות במכרז טרם נקבע
זמן קצוב לתפוגה של חיבור ראשוני ‫5 שניות
הזמן הקצוב לתפוגת הקריאה בחיבור ‫5 שניות
משך ההפעלה המקסימלי של AdSelection הכולל ‫10 שניות
משך ההפעלה המקסימלי של הבידינג לכל חשבון ניהול ב-AdSelection 5 שניות
משך ההפעלה המקסימלי של הניקוד ב-AdSelection 5 שניות
משך ההפעלה המקסימלי לכל קונה ב-AdSelection טרם נקבע
הגודל המקסימלי של אותות לבחירת מודעות/למוכר/לכל קונה טרם נקבע
הגודל המקסימלי של סקריפטים של מוכרים/קונים טרם נקבע
שיעור השיחות המקסימלי עבור selectAds 1 QPS
דיווח על חשיפות משך הזמן המינימלי לפני הסרת בחירת המודעות מהתגובה לזיהוי 24 שעות
מספר הבחירות המקסימלי של מודעות אחסון טרם נקבע
הגודל המקסימלי של כתובת ה-URL של הפלט לדיווח טרם נקבע
פרק הזמן המקסימלי לדיווח על חשיפות טרם נקבע
מספר הניסיונות החוזרים המקסימלי לשיחות התראה טרם נקבע
תם פרק הזמן שהוקצב להתחברות ‫5 שניות
משך ההפעלה הכולל המקסימלי של reportImpression 2 שניות
שיעור השיחות המקסימלי עבור reportImpressions 1 QPS
דיווח על אירועים המספר המקסימלי של סמנים לכל קונה בכל מכרז 10

המספר המקסימלי של סמנים לכל מוכר בכל מכרז

10

הגודל המקסימלי של מפתח אירוע

40 בייטים

הגודל המקסימלי של נתוני האירועים

64KB

מודעות הגודל המקסימלי של רשימת מודעות 10KB ששותפים על ידי כל AdData ב-CA יחיד לצורך מודעות לפי הקשר
URLs האורך המקסימלי של מחרוזת כתובת URL שנלקחת כקלט טרם נקבע
JavaScript משך ההפעלה המקסימלי שנייה אחת לבידינג ולניקוד לצורך דיווח על חשיפות
השימוש המקסימלי בזיכרון ‎10 MB

דיווח על באגים ובעיות

המשוב שלכם הוא חלק חיוני מארגז החול לפרטיות ב-Android. אנחנו מזמינים אתכם לדווח לנו על בעיות שמצאתם או על רעיונות לשיפור ארגז החול לפרטיות ב-Android.