راهنمای توسعه‌دهنده API Reporting Attribution

همانطور که مستندات Privacy Sandbox را در اندروید مطالعه می‌کنید، از دکمه Developer Preview یا Beta برای انتخاب نسخه برنامه‌ای که با آن کار می‌کنید استفاده کنید، زیرا دستورالعمل‌ها ممکن است متفاوت باشند.


API گزارش‌دهی انتساب (Attribution Reporting API) به گونه‌ای طراحی شده است که با حذف وابستگی به شناسه‌های کاربری بین‌طرفی، حریم خصوصی کاربر را بهبود بخشد و از موارد استفاده کلیدی برای اندازه‌گیری انتساب و تبدیل در برنامه‌ها پشتیبانی کند. این راهنمای توسعه‌دهنده، نحوه پیکربندی و آزمایش APIهای گزارش‌دهی انتساب را برای ثبت کلیک‌ها، بازدیدها و تبدیل‌های تبلیغاتی با فراخوانی روش‌هایی که محرک‌ها و منابع مربوطه را برای چنین رویدادهایی ثبت می‌کنند، شرح می‌دهد.

این راهنما به شما آموزش می‌دهد که چگونه نقاط پایانی سرور را راه‌اندازی کنید و یک برنامه کلاینت بسازید که این سرویس‌ها را فراخوانی کند. برای کسب اطلاعات بیشتر در مورد طراحی کلی API گزارش‌دهی نسبت‌دهی، به طرح پیشنهادی مراجعه کنید.

اصطلاحات کلیدی

  • منابع انتساب به کلیک‌ها یا بازدیدها اشاره دارند.
  • محرک‌ها رویدادهایی هستند که می‌توان آنها را به تبدیل‌ها نسبت داد.
  • گزارش‌ها حاوی داده‌هایی درباره یک محرک و منبع انتساب مربوطه هستند. این گزارش‌ها در پاسخ به رویدادهای محرک ارسال می‌شوند. API گزارش‌دهی انتساب از گزارش‌های سطح رویداد و گزارش‌های تجمیعی پشتیبانی می‌کند.

قبل از اینکه شروع کنی

برای استفاده از API گزارش‌دهی انتساب، وظایف سمت سرور و سمت کلاینت ذکر شده در بخش‌های زیر را انجام دهید.

نقاط پایانی API گزارش‌دهی انتساب را تنظیم کنید

API گزارش‌دهی انتساب به مجموعه‌ای از نقاط پایانی نیاز دارد که می‌توانید از یک دستگاه آزمایشی یا شبیه‌ساز به آنها دسترسی داشته باشید. برای هر یک از وظایف سمت سرور زیر، یک نقطه پایانی ایجاد کنید:

چندین روش برای تنظیم نقاط پایانی مورد نیاز وجود دارد:

  • سریع‌ترین راه برای راه‌اندازی و اجرا، استقرار تعاریف سرویس OpenAPI v3 از مخزن کد نمونه ما در یک پلتفرم شبیه‌سازی یا میکروسرویس است. می‌توانید از Postman ، Prism یا هر پلتفرم سرور شبیه‌سازی دیگری که این فرمت را می‌پذیرد استفاده کنید. هر نقطه پایانی را مستقر کنید و URIها را برای استفاده در برنامه خود پیگیری کنید. برای تأیید تحویل گزارش، به فراخوانی‌های قبلی انجام شده در پلتفرم شبیه‌سازی یا بدون سرور مراجعه کنید.
  • سرور مستقل خود را با استفاده از نمونه کاتلین مبتنی بر Spring Boot اجرا کنید. این سرور را روی ارائه دهنده ابری یا زیرساخت داخلی خود مستقر کنید.
  • از تعاریف سرویس به عنوان مثال برای ادغام نقاط پایانی در سیستم موجود خود استفاده کنید.

پذیرش ثبت منبع

این نقطه پایانی باید از طریق یک URI مشابه زیر قابل آدرس‌دهی باشد:

https://adtech.example/attribution_source

وقتی یک برنامه‌ی کلاینت یک منبع انتساب را ثبت می‌کند ، URI مربوط به این نقطه‌ی پایانی سرور را ارائه می‌دهد. سپس API گزارش‌دهی انتساب، درخواستی ارسال می‌کند و یکی از هدرهای زیر را در آن قرار می‌دهد:

  • برای رویدادهای کلیک:

    Attribution-Reporting-Source-Info: navigation
    
  • برای مشاهده رویدادها:

    Attribution-Reporting-Source-Info: event
    

نقطه پایانی سرور خود را برای پاسخگویی با موارد زیر پیکربندی کنید:

// Metadata associated with attribution source.
Attribution-Reporting-Register-Source: {
  "destination": "[app package name]",
  "web_destination": "[eTLD+1]",
  "source_event_id": "[64 bit unsigned integer]",
  "expiry": "[64 bit signed integer]",
  "event_report_window": "[64-bit signed integer]",
  "aggregatable_report_window": "[64-bit signed integer]",
  "priority": "[64 bit signed integer]",
  "filter_data": {
    "[key name 1]": ["key1 value 1", "key1 value 2"],
    "[key name 2]": ["key2 value 1", "key2 value 2"],
    // Note: "source_type" key will be automatically generated as
    // one of {"navigation", "event"}.
  },
  // Attribution source metadata specifying histogram contributions in aggregate
  // report.
  "aggregation_keys": {
    "[key1 name]": "[key1 value]",
    "[key2 name]": "[key2 value]",
  },

    "debug_key": "[64-bit unsigned integer]",
    "debug_reporting": [boolean]
}
// Specify additional ad tech URLs to register this source with.
Attribution-Reporting-Redirect: <Ad Tech Partner URI 1>
Attribution-Reporting-Redirect: <Ad Tech Partner URI 2>

در اینجا مثالی با مقادیر نمونه اضافه شده آورده شده است:

Attribution-Reporting-Register-Source: {
  "destination": "android-app://com.example.advertiser",
  "source_event_id": "234",
  "expiry": "259200",
  "event_report_window": "172800",
  "aggregatable_report_window": "172800",
  "priority": "5",
  "filter_data": {
    "product_id": ["1234"]
  },
  "aggregation_keys": {
  // Generates a "0x159" key piece named (low order bits of the key) for the key
  // named "campaignCounts".
  // User saw an ad from campaign 345 (out of 511).
    "campaignCounts": "0x159",

  // Generates a "0x5" key piece (low order bits of the key) for the key named
  // "geoValue".
  // Source-side geo region = 5 (US), out of a possible ~100 regions.
    "geoValue": "0x5",
  },
  // Opts in to receiving verbose debug reports
  "debug_reporting": true
}

Attribution-Reporting-Redirect:
https://adtechpartner1.example?their_ad_click_id=567
Attribution-Reporting-Redirect:
https://adtechpartner2.example?their_ad_click_id=890

اگر Attribution-Reporting-Redirects شامل URI های شرکای فناوری تبلیغات باشد، API گزارش‌دهی Attribution درخواست مشابهی را برای هر URI ارسال می‌کند. هر شریک فناوری تبلیغات باید سروری را پیکربندی کند که با این هدرها پاسخ دهد:

Attribution-Reporting-Register-Source: {
  "destination": "[app package name]",
  "web_destination": "[eTLD+1]",
  "source_event_id": "[64 bit unsigned integer]",
  "expiry": "[64 bit signed integer]",
  "event_report_window": "[64-bit signed integer]",
  "aggregatable_report_window": "[64-bit signed integer]",
  "priority": "[64 bit signed integer]",
  "filter_data": {
    "[key name 1]": ["key1 value 1", "key1 value 2"],
    "[key name 2]": ["key2 value 1", "key2 value 2"],
    // Note: "source_type" key will be automatically generated as
    // one of {"navigation", "event"}.
  },
  "aggregation_keys": {
    "[key1 name]": "[key1 value]",
    "[key2 name]": "[key2 value]",
  }
}
// The Attribution-Reporting-Redirect header is ignored for ad tech partners.

ثبت نام تریگر تبدیل را بپذیرید

این نقطه پایانی باید از طریق یک URI مشابه زیر قابل آدرس‌دهی باشد:

https://adtech.example/attribution_trigger

وقتی یک برنامه‌ی کلاینت یک رویداد trigger ثبت می‌کند ، URI مربوط به این نقطه‌ی پایانی سرور را فراهم می‌کند. سپس API گزارش‌دهی Attribution یک درخواست ارسال می‌کند و یکی از هدرهای زیر را در آن قرار می‌دهد:

نقطه پایانی سرور خود را برای پاسخگویی با موارد زیر پیکربندی کنید:

// Metadata associated with trigger.
Attribution-Reporting-Register-Trigger: {
  "event_trigger_data": [{
    // "trigger_data returned" in event reports is truncated to
    // the last 1 or 3 bits, based on conversion type.
    "trigger_data": "[unsigned 64-bit integer]",
    "priority": "[signed 64-bit integer]",
    "deduplication_key": "[signed 64-bit integer]",
    // "filter" and "not_filters" are optional fields which allow configuring
    // event trigger data based on source's filter_data. They consist of a
    // filter set, which is a list of filter maps. An event_trigger_data object
    // is ignored if none of the filter maps in the set match the source's
    // filter data.
    // Note: "source_type" can be used as a key in a filter map to filter based
    // on the source's "navigation" or "event" type. The first
    // Event-Trigger that matches (based on the filters/not_filters) will be
    // used for report generation. If none of the event-triggers match, no
    // event report will be generated.
    "filters": [{
      "[key name 1]": ["key1 value 1", "key1 value 2"],
      // If a key is missing from filters or source's filter_data, it won't be
      // used during matching.
      "[key name 2]": ["key2 value 1", "key2 value 2"],
    }],
    "not_filters":  [{
      "[key name 1]": ["key1 value 1", "key1 value 2"],
      // If a key is missing from not_filters or source's filter_data, it won't
      // be used during matching.
      "[key name 2]": ["key2 value 1", "key2 value 2"],
    }]
  }],
  // Specify a list of dictionaries that generates aggregation keys.
  "aggregatable_trigger_data": [
    // Each dictionary entry independently adds pieces to multiple source keys.
    {
      "key_piece": "[key piece value]",
      "source_keys": ["[key name the key piece value applies to]",
      ["list of IDs in source to match. Non-matching IDs are ignored"]]
      // filters/not_filters are optional fields similar to event trigger data
      // filter fields.
      "filters": [{
        "[key name 1]": ["key1 value 1", "key1 value 2"]
      }],
      "not_filters":  [{
          "[key name 1]": ["key1 value 1", "key1 value 2"],
          "[key name 2]": ["key2 value 1", "key2 value 2"],
      }]
    },
    ..
  ],
  // Specify an amount of an abstract value which can be integers in [1, 2^16]
  // to contribute to each key that is attached to aggregation keys in the
  // order they are generated.
  "aggregatable_values": [
     // Each source event can contribute a maximum of L1 = 2^16 to the
     // aggregate histogram.
    {
     "[key_name]": [value]
    },
    ..
  ],
  aggregatable_deduplication_keys: [{
  deduplication_key": [unsigned 64-bit integer],
    "filters": {
        "category": [filter_1, …, filter_H]
      },
    "not_filters": {
        "category": [filter_1, …, filter_J]
      }
  },
  ...
  {
  "deduplication_key": [unsigned 64-bit integer],
    "filters": {
        "category": [filter_1, …, filter_D]
      },
    "not_filters": {
        "category": [filter_1, …, filter_J]
      }
    }
  ]

  "debug_key": "[64-bit unsigned integer]",
  "debug_reporting": [boolean]

}
// Specify additional ad tech URLs to register this trigger with.
// Repeated Header field "Attribution-Reporting-Redirect"
Attribution-Reporting-Redirect: <Ad Tech Partner URI 1>
Attribution-Reporting-Redirect: <Ad Tech Partner URI 2>

در اینجا مثالی با مقادیر نمونه اضافه شده آورده شده است:

Attribution-Reporting-Register-Trigger: {
  "event_trigger_data": [{
    "trigger_data": "1122", // Returns 010 for CTCs and 0 for VTCs in reports.
    "priority": "3",
    "deduplication_key": "3344"
    "filters": [{ // Filter strings can't exceed 25 characters
      "product_id": ["1234"],
      "source_type": ["event"]
    }]
  },
  {
    "trigger_data": "4", // Returns 100 for CTCs and 0 for VTCs in reports.
    "priority": "3",
    "deduplication_key": "3344"
    "filters": [{ // Filter strings can't exceed 25 characters
      "product_id": ["1234"],
      "source_type": ["navigation"]
    }]
  }],
  "aggregatable_trigger_data": [
    // Each dictionary independently adds pieces to multiple source keys.
    {
      // Conversion type purchase = 2 at a 9-bit offset, i.e. 2 << 9.
      // A 9-bit offset is needed because there are 511 possible campaigns,
      // which takes up 9 bits in the resulting key.
      "key_piece": "0x400",// Conversion type purchase = 2
      // Apply this key piece to:
      "source_keys": ["campaignCounts"]
       // Filter strings can't exceed 25 characters
    },
    {
      // Purchase category shirts = 21 at a 7-bit offset, i.e. 21 << 7.
      // A 7-bit offset is needed because there are ~100 regions for the geo
      // key, which takes up 7 bits of space in the resulting key.
      "key_piece": "0xA80",
      // Apply this key piece to:
      "source_keys": ["geoValue", "nonMatchingIdsAreIgnored"]
      // source_key values must not exceed the limit of 25 characters
    }
  ],
  "aggregatable_values":
    {
      // Privacy budget for each key is L1 / 2 = 2^15 (32768).
      // Conversion count was 1.
      // Scale the count to use the full budget allocated: 1 * 32768 = 32768.
      "campaignCounts": 32768,

      // Purchase price was $52.
      // Purchase values for the app range from $1 to $1,024 (integers only).
      // Scaling factor applied is 32768 / 1024 = 32.
      // For $52 purchase, scale the value by 32 ($52 * 32 = $1,664).
      "geoValue": 1664
    }
  ,
  // aggregatable_deduplication_keys is an optional field. Up to 50 "keys"
  // can be included in the aggregatable_deduplication_keys list. Filters, not
  // filters, and deduplication_key are optional fields. If deduplication_key
  // is omitted, it will be treated as a null value. See
  // https://wicg.github.io/attribution-reporting-api/#triggering-aggregatable-attribution
  aggregatable_deduplication_keys:
  [
    {
    deduplication_key": 3,
        "filters": {
          "category": [A]
        }
    },
    {
    "deduplication_key": 4,
        "filters": {
          "category": [C, D]
        },
        "not_filters": {
          "category": [F]
        }
    }
  ]
  // Opts into receiving verbose debug reports
  "debug_reporting": true
}
Attribution-Reporting-Redirect:https://adtechpartner.example?app_install=567

محدودیتی به اندازه ۲۵ بایت برای هر شناسه کلید تجمیع و رشته فیلتر وجود دارد. این بدان معناست که شناسه‌های کلید تجمیع و رشته‌های فیلتر شما نباید از ۲۵ کاراکتر بیشتر شوند. در این مثال، campaignCounts برابر با ۱۴ کاراکتر است، بنابراین یک شناسه کلید تجمیع معتبر است و 1234 با ۴ کاراکتر است، بنابراین یک رشته فیلتر معتبر است. اگر شناسه کلید تجمیع یا رشته فیلتر بیش از ۲۵ کاراکتر باشد، تریگر نادیده گرفته می‌شود.

اگر Attribution-Reporting-Redirect شامل URI های شرکای فناوری تبلیغات باشد، API گزارش‌دهی Attribution درخواست مشابهی را برای هر URI ارسال می‌کند. هر شریک فناوری تبلیغات باید سروری را پیکربندی کند که با این هدرها پاسخ دهد:

// Metadata associated with trigger.
Attribution-Reporting-Register-Trigger: {
  "event_trigger_data": [{
    // "trigger_data" returned in event reports is truncated to
    // the last 1 or 3 bits, based on conversion type.
    "trigger_data": "[unsigned 64-bit integer]",
    "priority": "[signed 64-bit integer]",
    "deduplication_key": "[signed 64-bit integer]",
    // filter and not_filters are optional fields which allow configuring
    // different event trigger data based on source's filter_data. They
    // consist of a filter set, which is a list of filter maps. An
    // event_trigger_data object is ignored if none of the filter maps in the
    // set match the source's filter data. Note: "source_type" can be used as
    // a key in a filter map to filter based on the source's "navigation" or
    // "event" type. The first Event-Trigger that matches (based on the
    // filters/not_filters) will be used for report generation. If none of the
    // event-triggers match, no report will be generated.
    "filters": [{
      "[key name 1]": ["key1 value 1", "key1 value 2"],
      // If a key is missing from filters or source's filter_data, it won't be
      // used during matching.
      "[key name 2]": ["key2 value 1", "key2 value 2"],
    }],
    "not_filters":  [{
      "[key name 1]": ["key1 value 1", "key1 value 2"],
      // If a key is missing from not_filters or source's filter_data, it won't
      // be used during matching.
      "[key name 2]": ["key2 value 1", "key2 value 2"],
    }]
  }],
  "aggregatable_trigger_data": [
    // Each dictionary entry independently adds pieces to multiple source keys.
    {
      "key_piece": "[key piece value]",
      "source_keys": ["[key name the key piece value applies to]",
      ["list of IDs in source to match. Non-matching IDs are ignored"]],
      // filters/not_filters are optional fields similar to event trigger data
      // filter fields.
      "filters": [{
        "[key name 1]": ["key1 value 1", "key1 value 2"]
      }],
      "not_filters":  [{
          "[key name 1]": ["key1 value 1", "key1 value 2"],
          "[key name 2]": ["key2 value 1", "key2 value 2"],
      }]
    },
    ..
  ],
  // Specify an amount of an abstract value which can be integers in [1, 2^16] to
  // contribute to each key that is attached to aggregation keys in the order they
  // are generated.
  "aggregatable_values": [
    // Each source event can contribute a maximum of L1 = 2^16 to the aggregate
    // histogram.
    {
     "[key_name]": [value]
    }
  ]
}
// The Attribution-Reporting-Redirect header is ignored for ad tech partners.

گزارش‌های سطح رویداد را بپذیرید

این نقطه پایانی باید از طریق یک URI قابل آدرس‌دهی باشد. برای اطلاعات بیشتر در مورد ثبت URIها ، به بخش ثبت نام برای حساب کاربری Privacy Sandbox مراجعه کنید. (URI از مبدا سرورهایی که برای پذیرش ثبت منبع و ثبت تریگر استفاده می‌شوند، استنباط می‌شود.) با استفاده از URIهای مثال برای نقاط پایانی که ثبت منبع و ثبت تریگر را می‌پذیرند، URI این نقطه پایانی عبارت است از:

https://adtech.example/.well-known/attribution-reporting/report-event-attribution

این سرور را طوری پیکربندی کنید که درخواست‌های JSON با فرمت زیر را بپذیرد:

{
  "attribution_destination": "android-app://com.advertiser.example",
  "source_event_id": "12345678",
  "trigger_data": "2",
  "report_id": "12324323",
  "source_type": "navigation",
  "randomized_trigger_rate": "0.02"
   [Optional] "source_debug_key": "[64-bit unsigned integer]",
   [Optional] "trigger_debug_key": "[64-bit unsigned integer]",
}

کلیدهای اشکال‌زدایی امکان درک بیشتر از گزارش‌های انتساب شما را فراهم می‌کنند؛ درباره پیکربندی آنها بیشتر بدانید .

گزارش‌های تجمیعی را بپذیرید

این نقطه پایانی باید از طریق یک URI قابل آدرس‌دهی باشد. برای اطلاعات بیشتر در مورد ثبت URIها ، به بخش ثبت نام برای حساب کاربری Privacy Sandbox مراجعه کنید. (URI از مبدا سرورهایی که برای پذیرش ثبت منبع و ثبت تریگر استفاده می‌شوند، استنباط می‌شود.) با استفاده از URIهای مثال برای نقاط پایانی که ثبت منبع و ثبت تریگر را می‌پذیرند، URI این نقطه پایانی عبارت است از:

https://adtech.example/.well-known/attribution-reporting/report-aggregate-attribution

هر دو فیلد رمزگذاری شده و رمزگذاری نشده برای گزارش‌های قابل تجمیع پر می‌شوند. گزارش‌های رمزگذاری شده به شما امکان می‌دهند آزمایش را با سرویس تجمیع شروع کنید، در حالی که فیلد رمزگذاری نشده بینشی در مورد نحوه ساختاردهی داده‌ها توسط جفت‌های کلید-مقدار ارائه می‌دهد.

این سرور را طوری پیکربندی کنید که درخواست‌های JSON با فرمت زیر را بپذیرد:

{
  // Info that the aggregation services also need encoded in JSON
  // for use with AEAD. Line breaks added for readability.
  "shared_info": "{
     \"api\":\"attribution-reporting\",
     \"attribution_destination\": \"android-app://com.advertiser.example.advertiser\",
     \"scheduled_report_time\":\"[timestamp in seconds]\",
     \"source_registration_time\": \"[timestamp in seconds]\",
     \"version\":\"[api version]\",
     \"report_id\":\"[UUID]\",
     \"reporting_origin\":\"https://reporter.example\" }",

  // In the current Developer Preview release, The "payload" and "key_id" fields
  // are not used because the platform doesn't yet encrypt aggregate reports.
  // The "debug_cleartext_payload" field holds unencrypted reports.
  "aggregation_service_payloads": [
    {
      "payload": "[base64 HPKE encrypted data readable only by the aggregation service]",
      "key_id": "[string identifying public key used to encrypt payload]",

      "debug_cleartext_payload": "[unencrypted payload]"
    },
  ],

  "source_debug_key": "[64 bit unsigned integer]",
  "trigger_debug_key": "[64 bit unsigned integer]"
}

کلیدهای اشکال‌زدایی امکان درک بیشتر از گزارش‌های انتساب شما را فراهم می‌کنند؛ درباره پیکربندی آنها بیشتر بدانید .

راه اندازی کلاینت اندروید

برنامه کلاینت، منابع و تریگرهای انتساب را ثبت می‌کند و تولید گزارش در سطح رویداد و تجمیع‌پذیر را فعال می‌کند. برای آماده‌سازی یک دستگاه کلاینت اندروید یا شبیه‌ساز برای استفاده از API گزارش‌دهی انتساب، موارد زیر را انجام دهید:

  1. محیط توسعه خود را برای Privacy Sandbox در اندروید تنظیم کنید .
  2. یک تصویر سیستم را روی یک دستگاه پشتیبانی‌شده نصب کنید یا یک شبیه‌ساز راه‌اندازی کنید که شامل پشتیبانی از Privacy Sandbox در اندروید باشد.
  3. با اجرای دستور ADB زیر، دسترسی به API گزارش‌دهی انتساب را فعال کنید . (این API به طور پیش‌فرض غیرفعال است.)

    adb shell device_config put adservices ppapi_app_allow_list \"\*\"
  4. اگر به صورت محلی در حال آزمایش API گزارش‌دهی Attribution هستید (مانند آزمایش روی دستگاهی که به صورت فیزیکی به آن دسترسی دارید)، این دستور را برای غیرفعال کردن ثبت‌نام اجرا کنید:

    adb shell device_config put adservices disable_measurement_enrollment_check "true"
  5. مجوز ACCESS_ADSERVICES_ATTRIBUTION را در فایل Manifest اندروید خود وارد کنید و یک پیکربندی سرویس‌های تبلیغاتی برای برنامه خود ایجاد کنید تا از APIهای گزارش‌دهی Attribution استفاده کند:

    <uses-permission android:name="android.permission.ACCESS_ADSERVICES_ATTRIBUTION" />
    
  6. (اختیاری) اگر قصد دریافت گزارش‌های اشکال‌زدایی را دارید، مجوز ACCESS_ADSERVICES_AD_ID را در فایل Manifest اندروید خود وارد کنید:

    <uses-permission android:name="android.permission.ACCESS_ADSERVICES_AD_ID" />
    
  7. به پیکربندی سرویس‌های تبلیغاتی در عنصر <application> مانیفست خود ارجاع دهید:

    <property android:name="android.adservices.AD_SERVICES_CONFIG"
              android:resource="@xml/ad_services_config" />
    
  8. منبع XML مربوط به سرویس‌های تبلیغاتی که در مانیفست به آن ارجاع داده شده است را مشخص کنید، مانند res/xml/ad_services_config.xml . درباره مجوزهای سرویس‌های تبلیغاتی و کنترل دسترسی SDK بیشتر بدانید.

    <ad-services-config>
        <attribution allowAllToAccess="true" />
    </ad-services-config>
    

رویدادهای تبلیغاتی را ثبت کنید

برنامه شما باید منابع و تبدیل‌ها را به محض وقوع ثبت کند تا تأیید شود که به درستی گزارش می‌شوند. کلاس MeasurementManager متدهایی را ارائه می‌دهد که به شما در ثبت رویدادهای منبع انتساب و محرک‌های تبدیل کمک می‌کند.

ثبت یک رویداد منبع انتساب

وقتی یک تبلیغ مشاهده یا کلیک می‌شود، برنامه‌ی ناشر، تابع registerSource() را فراخوانی می‌کند تا یک منبع انتساب را همانطور که در قطعه کد نشان داده شده است، ثبت کند.

API گزارش‌دهی انتساب از انواع رویدادهای منبع انتساب زیر پشتیبانی می‌کند:

  • کلیک‌ها، که معمولاً در یک متد فراخوانی مشابه onClick() ثبت می‌شوند. رویداد trigger مربوطه معمولاً کمی پس از رویداد کلیک رخ می‌دهد. این نوع رویداد اطلاعات بیشتری در مورد تعامل کاربر ارائه می‌دهد و بنابراین نوع خوبی از منبع انتساب برای اولویت بالا دادن است.
  • نماها (Views)، که معمولاً آنها را در یک متد فراخوانی مشابه onAdShown() ثبت می‌کنید. رویداد محرک مربوطه ممکن است ساعت‌ها یا روزها پس از رویداد نما رخ دهد.

کاتلین

companion object {
    private val CALLBACK_EXECUTOR = Executors.newCachedThreadPool()
}

val measurementManager = context.getSystemService(MeasurementManager::class.java)
var exampleClickEvent: InputEvent? = null

// Use the URI of the server-side endpoint that accepts attribution source
// registration.
val attributionSourceUri: Uri =
  Uri.parse("https://adtech.example/attribution_source?AD_TECH_PROVIDED_METADATA")

val future = CompletableFuture<Void>()

adView.setOnTouchListener(_: View?, event: MotionEvent?)) ->
    exampleClickEvent = event
    true
}

// Register Click Event
measurementManager.registerSource(
        attributionSourceUri,
        exampleClickEvent,
        CALLBACK_EXECUTOR,
        future::complete)

// Register View Event
measurementManager.registerSource(
        attributionSourceUri,
        null,
        CALLBACK_EXECUTOR,
        future::complete)

جاوا

private static final Executor CALLBACK_EXECUTOR = Executors.newCachedThreadPool();
private InputEvent exampleClickEvent;

MeasurementManager measurementManager =
        context.getSystemService(MeasurementManager.class);

// Use the URI of the server-side endpoint that accepts attribution source
// registration.
Uri attributionSourceUri =
Uri.parse("https://adtech.example/attribution_source?AD_TECH_PROVIDED_METADATA");

CompletableFuture<Void> future = new CompletableFuture<>();

adView.setOnTouchListener(v, event)) -> {
    exampleClickEvent = event;
    return true;
}

// Register Click Event
measurementManager.registerSource(attributionSourceUri, exampleClickEvent,
        CALLBACK_EXECUTOR, future::complete);

// Register View Event
measurementManager.registerSource(attributionSourceUri, null,
        CALLBACK_EXECUTOR, future::complete);

پس از ثبت، API یک درخواست HTTP POST به نقطه پایانی سرویس در آدرسی که توسط attributionSourceUri مشخص شده است، ارسال می‌کند. پاسخ نقطه پایانی شامل مقادیری برای destination, source_event_id, expiry و source_priority .

اگر شرکت تبلیغاتی مبدأ بخواهد ثبت منابع را به اشتراک بگذارد، URI منبع انتساب اصلی می‌تواند شامل تغییر مسیرها به سایر نقاط پایانی شرکت تبلیغاتی باشد. محدودیت‌ها و قوانین مربوط به تغییر مسیرها در پیشنهاد فنی به تفصیل شرح داده شده است.

پشتیبانی از تغییر مسیرهای زنجیره‌ای برای registerSource و registerTrigger اضافه شده است. علاوه بر هدر ثبت‌نام، مصرف‌کننده API اکنون می‌تواند یک تغییر مسیر HTTP را به عنوان پاسخ سرور ارائه دهد که شامل یک کد وضعیت 302 و یک هدر "مکان" با URL بعدی برای بازدید جهت ثبت‌نام اضافی است.

فقط فیلد "مقصد" که در اولین بازدید ارائه می‌شود، در سراسر زنجیره‌ی daisy استفاده می‌شود. تعداد بازدیدها همان محدودیت هدرهای "Attribution-Reporting-Redirect" را دارد. این پشتیبانی از ریدایرکت علاوه بر پشتیبانی موجود از "Attribution-Reporting-Redirect" است و اگر هر دو موجود باشند، "Attribution-Reporting-Redirect" اولویت پیدا می‌کند.

یک رویداد محرک تبدیل ثبت کنید

برای ثبت یک رویداد محرک تبدیل، در برنامه خود registerTrigger() را فراخوانی کنید:

کاتلین

companion object {
    private val CALLBACK_EXECUTOR = Executors.newCachedThreadPool()
}

val measurementManager = context.getSystemService(MeasurementManager::class.java)

// Use the URI of the server-side endpoint that accepts trigger registration.
val attributionTriggerUri: Uri =
    Uri.parse("https://adtech.example/trigger?AD_TECH_PROVIDED_METADATA")

val future = CompletableFuture<Void>()

// Register trigger (conversion)
measurementManager.registerTrigger(
        attributionTriggerUri,
        CALLBACK_EXECUTOR,
        future::complete)

جاوا

private static final Executor CALLBACK_EXECUTOR = Executors.newCachedThreadPool();

MeasurementManager measurementManager =
        context.getSystemService(MeasurementManager.class);

// Use the URI of the server-side endpoint that accepts trigger registration.
Uri attributionTriggerUri =
        Uri.parse("https://adtech.example/trigger?AD_TECH_PROVIDED_METADATA");

CompletableFuture<Void> future = new CompletableFuture<>();

// Register trigger (conversion)
measurementManager.registerTrigger(
        attributionTriggerUri,
        CALLBACK_EXECUTOR,
        future::complete)

پس از ثبت، API یک درخواست HTTP POST به نقطه پایانی سرویس در آدرسی که توسط attributionTriggerUri مشخص شده است، ارسال می‌کند. پاسخ نقطه پایانی شامل مقادیری برای گزارش‌های رویداد و تجمیع است.

اگر پلتفرم فناوری تبلیغات مبدا اجازه اشتراک‌گذاری ثبت نام‌های تریگر را بدهد، URI می‌تواند شامل تغییر مسیر به URIهایی باشد که متعلق به سایر پلتفرم‌های فناوری تبلیغات هستند. محدودیت‌ها و قوانین مربوط به تغییر مسیرها در پیشنهاد فنی به تفصیل آمده است.

ثبت نام در سنجش بین برنامه‌ای و تحت وب

در مواردی که هم برنامه و هم مرورگر در سفر کاربر از منبع تا تریگر نقش دارند ، تفاوت‌های ظریفی در پیاده‌سازی ثبت رویدادهای تبلیغاتی وجود دارد. اگر کاربری تبلیغی را در یک برنامه ببیند و برای تبدیل به مرورگر هدایت شود، منبع توسط برنامه و تبدیل توسط مرورگر وب ثبت می‌شود. به طور مشابه، اگر کاربری از یک مرورگر وب شروع کند و برای تبدیل به یک برنامه هدایت شود، مرورگر منبع را ثبت می‌کند و برنامه تبدیل را ثبت می‌کند.

از آنجایی که تفاوت‌هایی در نحوه سازماندهی تکنسین‌های تبلیغات در وب و اندروید وجود دارد، ما APIهای جدیدی برای ثبت منابع و تریگرها هنگام وقوع آنها در مرورگرها اضافه کرده‌ایم. تفاوت کلیدی بین این APIها و APIهای مبتنی بر برنامه مربوطه این است که ما انتظار داریم مرورگر از تغییر مسیرها پیروی کند، فیلترهای خاص مرورگر را اعمال کند و ثبت‌های معتبر را با فراخوانی registerWebSource() یا registerWebTrigger() به پلتفرم منتقل کند.

قطعه کد زیر نمونه‌ای از فراخوانی API را نشان می‌دهد که مرورگر برای ثبت منبع ارجاع قبل از هدایت کاربر به یک برنامه انجام می‌دهد:

کاتلین

companion object {
    private val CALLBACK_EXECUTOR = Executors.newCachedThreadPool()
}

val measurementManager =
        context.getSystemService(MeasurementManager::class.java)
var exampleClickEvent: InputEvent? = null

// Use the URIs of the server-side endpoints that accept attribution source
// registration.
val sourceParam1 = WebSourceParams.Builder(Uri.parse(
        "https://adtech1.example/attribution_source?AD_TECH_PROVIDED_METADATA"))
// True, if debugging is allowed for the ad tech.
    .setDebugKeyAllowed(true)
    .build()

val sourceParam2 = WebSourceParams.Builder(Uri.parse(
        "https://adtech2.example/attribution_source?AD_TECH_PROVIDED_METADATA"))
    .setDebugKeyAllowed(false)
    .build()

val sourceParam3 = WebSourceParams.Builder(Uri.parse(
        "https://adtech3.example/attribution_source?AD_TECH_PROVIDED_METADATA"))
    .build()

val sourceParams = Arrays.asList(sourceParam1, sourceParam2, sourceParam3)
val publisherOrigin = Uri.parse("https://publisher.example")
val appDestination = Uri.parse("android-app://com.example.store")
val webDestination = Uri.parse("https://example.com")

val future = CompletableFuture<Void>()

adView.setOnTouchListener {_: View?, event: MotionEvent? ->
    exampleClickEvent = event
    true
}
val clickRegistrationRequest = WebSourceRegistrationRequest.Builder(
          sourceParams,
          publisherOrigin)
      .setAppDestination(appDestination)
      .setWebDestination(webDestination)
      .setInputEvent(event)
      .build()
val viewRegistrationRequest = WebSourceRegistrationRequest.Builder(
          sourceParams,
          publisherOrigin)
      .setAppDestination(appDestination)
      .setWebDestination(webDestination)
      .setInputEvent(null)
      .build()

// Register a web source for a click event.
measurementManager.registerWebSource(
        clickRegistrationRequest,
        CALLBACK_EXECUTOR,
        future::complete)

// Register a web source for a view event.
measurementManager.registerWebSource(
        viewRegistrationRequest,
        CALLBACK_EXECUTOR,
        future::complete)

جاوا

private static final Executor CALLBACK_EXECUTOR =
        Executors.newCachedThreadPool();
private InputEvent exampleClickEvent;

MeasurementManager measurementManager =
        context.getSystemService(MeasurementManager.class);

// Use the URIs of the server-side endpoints that accept attribution source
// registration.
WebSourceParams sourceParam1 = WebSourceParams.Builder(Uri.parse(
        "https://adtech1.example/attribution_source?AD_TECH_PROVIDED_METADATA"))
    // True, if debugging is allowed for the ad tech.
    .setDebugKeyAllowed(true)
    .build();

WebSourceParams sourceParam2 = WebSourceParams.Builder(Uri.parse(
        "https://adtech2.example/attribution_source?AD_TECH_PROVIDED_METADATA"))
    .setDebugKeyAllowed(false)
    .build();

WebSourceParams sourceParam3 = WebSourceParams.Builder(Uri.parse(
        "https://adtech3.example/attribution_source?AD_TECH_PROVIDED_METADATA"))
    .build();

List<WebSourceParams> sourceParams =
        Arrays.asList(sourceParam1, sourceParam2, sourceParam3);
Uri publisherOrigin = Uri.parse("https://publisher.example");
Uri appDestination = Uri.parse("android-app://com.example.store");
Uri webDestination = Uri.parse("https://example.com");

CompletableFuture<Void> future = new CompletableFuture<>();

adView.setOnTouchListener(v, event) -> {
    exampleClickEvent = event;
    return true;
}

WebSourceRegistrationRequest clickRegistrationRequest =
        new WebSourceRegistrationRequest.Builder(sourceParams, publisherOrigin)
    .setAppDestination(appDestination)
    .setWebDestination(webDestination)
    .setInputEvent(event)
    .build();
WebSourceRegistrationRequest viewRegistrationRequest =
        new WebSourceRegistrationRequest.Builder(sourceParams, publisherOrigin)
    .setAppDestination(appDestination)
    .setWebDestination(webDestination)
    .setInputEvent(null)
    .build();

// Register a web source for a click event.
measurementManager.registerWebSource(clickRegistrationRequest,
        CALLBACK_EXECUTOR, future::complete);

// Register a web source for a view event.
measurementManager.registerWebSource(viewRegistrationRequest,
        CALLBACK_EXECUTOR, future::complete);

قطعه کد زیر نمونه‌ای از فراخوانی API را نشان می‌دهد که مرورگر پس از هدایت کاربر از برنامه، برای ثبت تبدیل انجام می‌دهد:

کاتلین

companion object {
    private val CALLBACK_EXECUTOR = Executors.newCachedThreadPool()
}

val measurementManager = context.getSystemService(MeasurementManager::class.java)

// Use the URIs of the server-side endpoints that accept trigger registration.
val triggerParam1 = WebTriggerParams.Builder(Uri.parse(
        "https://adtech1.example/trigger?AD_TECH_PROVIDED_METADATA"))
    // True, if debugging is allowed for the ad tech.
    .setDebugKeyAllowed(true)
    .build()

val triggerParam2 = WebTriggerParams.Builder(Uri.parse(
        "https://adtech2.example/trigger?AD_TECH_PROVIDED_METADATA"))
    .setDebugKeyAllowed(false)
    .build()

val triggerParams = Arrays.asList(triggerParam1, triggerParam2)
val advertiserOrigin = Uri.parse("https://advertiser.example")

val future = CompletableFuture<Void>()

val triggerRegistrationRequest = WebTriggerRegistrationRequest.Builder(
        triggerParams,
        advertiserOrigin)
    .build()

// Register the web trigger (conversion).
measurementManager.registerWebTrigger(
    triggerRegistrationRequest,
    CALLBACK_EXECUTOR,
    future::complete)

جاوا

private static final Executor CALLBACK_EXECUTOR =
        Executors.newCachedThreadPool();

MeasurementManager measurementManager =
        context.getSystemService(MeasurementManager.class);

// Use the URIs of the server-side endpoints that accept trigger registration.
WebTriggerParams triggerParam1 = WebTriggerParams.Builder(Uri.parse(
        "https://adtech1.example/trigger?AD_TECH_PROVIDED_METADATA"))
    // True, if debugging is allowed for the ad tech.
    .setDebugKeyAllowed(true)
    .build();

WebTriggerParams triggerParam2 = WebTriggerParams.Builder(Uri.parse(
        "https://adtech2.example/trigger?AD_TECH_PROVIDED_METADATA"))
    .setDebugKeyAllowed(false)
    .build();

List<WebTriggerParams> triggerParams =
        Arrays.asList(triggerParam1, triggerParam2);
Uri advertiserOrigin = Uri.parse("https://advertiser.example");

CompletableFuture<Void> future = new CompletableFuture<>();

WebTriggerRegistrationRequest triggerRegistrationRequest =
        new WebTriggerRegistrationRequest.Builder(
            triggerParams, advertiserOrigin)
    .build();

// Register the web trigger (conversion).
measurementManager.registerWebTrigger( triggerRegistrationRequest,
        CALLBACK_EXECUTOR, future::complete);

افزودن نویز برای حفظ حریم خصوصی

گزارش‌های سطح رویداد شامل داده‌های مقصد، شناسه منبع انتساب و محرک هستند. آن‌ها در قالب اصلی (رمزگذاری نشده) به مبدا گزارش ارسال می‌شوند. برای محافظت از حریم خصوصی کاربر، می‌توان نویز اضافه کرد تا شناسایی یک کاربر خاص دشوارتر شود. گزارش‌های سطح رویداد نویزدار مطابق با چارچوب حریم خصوصی تفاضلی تولید و ارسال می‌شوند. اینها مقادیر درصد نویز پیش‌فرض برای سناریوهای مختلف هستند:

نوع منبع

مقدار مبدا مقصد

احتمال گزارش نویز به ازای هر ثبت منبع

مشاهده

یا اپلیکیشن یا وب

۰.۰۰۰۰۰۲۵

مشاهده

اپلیکیشن و وب

۰.۰۰۰۰۰۴۲

کلیک

یا اپلیکیشن یا وب

۰.۰۰۲۴۲۶۳

کلیک

اپلیکیشن و وب

۰.۰۱۷۰۲۱۸

در اندازه‌گیری نسبت‌دهی برنامه به وب، که در آن منابع می‌توانند تبدیل را هم به مقصد برنامه و هم به مقصد وب هدایت کنند، گزارش‌های سطح رویداد می‌توانند مشخص کنند که آیا این محرک در برنامه رخ داده است یا در وب. برای جبران این جزئیات اضافی، گزارش‌های نویزدار تولید شده برای کلیک‌ها تا حدود ۷ برابر و برای بازدیدها تا حدود ۱.۷ برابر هستند.

برخی از تکنسین‌های تبلیغات، نیازی به گزارش‌های سطح رویداد برای مشخص کردن اینکه آیا تریگر در مقصد برنامه یا وب رخ داده است، ندارند. تکنسین‌های تبلیغات می‌توانند از فیلد coarse_event_report_destinations در زیر هدر Attribution-Reporting-Register-Source برای کاهش نویز استفاده کنند. اگر منبعی با فیلد coarse_event_report_destinations مشخص شده، attribution را کسب کند، گزارش حاصل شامل هر دو مقصد برنامه و وب بدون تمایز در مورد محل وقوع تریگر واقعی است.

در مثال‌های زیر، یک کاربر روی یک تبلیغ کلیک می‌کند و آن منبع در API ثبت می‌شود. سپس کاربر هم در اپلیکیشن تبلیغ‌کننده و هم در وب‌سایت تبلیغ‌کننده تبدیل (convert) انجام می‌دهد. هر دوی این تبدیل‌ها به عنوان محرک ثبت می‌شوند و به کلیک اولیه نسبت داده می‌شوند.

یک هدر HTTP ثبت منبع مبتنی بر کلیک:

Attribution-Reporting-Register-Source: {
    "destination": "android-app://com.advertiser.example",
    "web_destination": "https://advertiser.com",
    "source_event_id": "234",
    "expiry": "60000",
    "priority": "5",
    // Ad tech opts out of receiving app-web destination distinction
    // in event report, avoids additional noise
    "coarse_event_report_destinations": "true"
}

یک تریگر از برنامه با نام بسته com.advertiser.example ثبت شده است:

Attribution-Reporting-Register-Trigger: {
    "event_trigger_data": [{
    "trigger_data": "1",
    "priority": "1"
    }],
}

یک تریگر از مرورگری از وب‌سایتی با دامنه eTLD+1 به https://advertiser.com ثبت می‌شود:

Attribution-Reporting-Register-Trigger: {
    "event_trigger_data": [{
    "trigger_data": "2",
    "priority": "2"
    }],
}

گزارش‌های سطح رویداد حاصل تولید می‌شوند. با فرض اینکه هر دو تریگر به منبع نسبت داده شوند، گزارش‌های سطح رویداد زیر تولید می‌شوند:

  {
    "attribution_destination": ["android-app://com.advertiser.example,https://advertiser.com"],
    "scheduled_report_time": "800176400",
    "source_event_id": "53234",
    "trigger_data": "1",
    // Can be "event" if source were registered by user viewing the ad
    "source_type": "navigation",
    // Would be 0.0170218 without coarse_event_report_destinations as true in the source
    "randomized_trigger_rate": 0.0024263
  }

تولید و ارائه گزارش‌ها

رابط برنامه‌نویسی کاربردی گزارش‌دهی انتساب، گزارش‌ها را به نقاط انتهایی روی سرور شما ارسال می‌کند که گزارش‌های سطح رویداد و گزارش‌های تجمیعی را می‌پذیرند.

اجرای گزارش‌های شغلی را اجباری کنید

پس از ثبت یک رویداد منبع انتساب یا ثبت یک رویداد محرک، سیستم، اجرای گزارش‌دهی را زمان‌بندی می‌کند. به طور پیش‌فرض، این گزارش‌دهی هر ۴ ساعت یکبار اجرا می‌شود. برای اهداف آزمایشی، می‌توانید گزارش‌دهی را مجبور به اجرا کنید یا فواصل بین گزارش‌دهی را کوتاه کنید.

اجرای اجباری وظیفه انتساب:

adb shell cmd jobscheduler run -f com.google.android.adservices.api 5

اجرای گزارش‌دهی در سطح رویداد را اجباری کنید:

adb shell cmd jobscheduler run -f com.google.android.adservices.api 3

اجرای یک گزارش تجمیعی را اجباری کنید:

adb shell cmd jobscheduler run -f com.google.android.adservices.api 7

خروجی logcat را بررسی کنید تا ببینید چه زمانی کارها اجرا شده‌اند. باید چیزی شبیه به زیر باشد:

JobScheduler: executeRunCommand(): com.google.android.adservices.api/0 5 s=false f=true

تحویل اجباری گزارش‌ها

حتی اگر کار گزارش‌دهی مجبور به اجرا شود، سیستم همچنان گزارش‌ها را طبق زمان تحویل برنامه‌ریزی‌شده‌شان ارسال می‌کند که از چند ساعت تا چند روز متغیر است. برای اهداف آزمایشی، می‌توانید زمان سیستم دستگاه را طوری تنظیم کنید که بعد از تأخیرهای برنامه‌ریزی‌شده برای شروع تحویل گزارش باشد.

گزارش‌ها را روی سرور خود تأیید کنید

پس از ارسال گزارش‌ها، با بررسی گزارش‌های دریافتی، گزارش‌های مربوط به سرور مانند تاریخچه سرور آزمایشی یا سیستم سفارشی خود، تحویل را تأیید کنید.

گزارش کلی خود را رمزگشایی کنید

هنگام دریافت یک گزارش تجمیعی، فیلد debug_cleartext_payload نسخه رمزگذاری نشده‌ای از گزارش تجمیعی شما را در خود جای می‌دهد. اگرچه این نسخه از گزارش شما رمزگذاری نشده است، اما هنوز نیاز به رمزگشایی دارد.

در ادامه مثالی از رمزگشایی محتوای فیلد debug_cleartext_payload در دو مرحله آمده است: مرحله اول با استفاده از رمزگشایی Base 64 و مرحله دوم با استفاده از رمزگشایی CBOR.

String base64DebugPayload  = "omRkYXRhgqJldmFsdWVEAAAGgGZidWNrZXRQAAAAAAAAAAAAAAAAAAAKhaJldmFsdWVEAACAAGZidWNrZXRQAAAAAAAAAAAAAAAAAAAFWWlvcGVyYXRpb25paGlzdG9ncmFt";
byte[] cborEncoded = Base64.getDecoder().decode(base64DebugPayload);

// CbodDecoder comes from this library https://github.com/c-rack/cbor-java
final List<DataItem> dataItems = new CborDecoder(new ByteArrayInputStream(cborEncoded)).decode();

// In here you can see the contents, but the value will be something like:
// Data items: [{ data: [{ value: co.nstant.in.cbor.model.ByteString@a8b5c07a,
//   bucket: co.nstant.in.cbor.model.ByteString@f812097d },
//   { value: co.nstant.in.cbor.model.ByteString@a8b5dfc0,
//   bucket: co.nstant.in.cbor.model.ByteString@f8120934 }], operation: histogram }]
Log.d("Data items : " + dataItems);

// In order to see the value for bucket and value, you can traverse the data
// and get their values, something like this:
final Map payload = (Map) dataItems.get(0);
final Array payloadArray = (Array) payload.get(new UnicodeString("data"));

payloadArray.getDataItems().forEach(i -> {
    BigInteger value = new BigInteger(((ByteString) ((Map)i).get(new UnicodeString("value"))).getBytes());
    BigInteger bucket = new BigInteger(((ByteString) ((Map)i).get(new UnicodeString("bucket"))).getBytes());
    Log.d("value : " + value + " ;bucket : " + bucket);
});

آزمایش

برای کمک به شروع کار با API گزارش‌دهی انتساب، می‌توانید از پروژه MeasurementSampleApp در GitHub استفاده کنید. این برنامه نمونه، ثبت منبع انتساب و ثبت تریگر را نشان می‌دهد.

برای نقاط پایانی سرور، منابع مرجع زیر یا راهکار سفارشی خود را در نظر بگیرید:

  • MeasurementAdTechServerSpec شامل تعاریف سرویس OpenAPI است که می‌توانند در پلتفرم‌های mock یا microservices پشتیبانی‌شده مستقر شوند.
  • MeasurementAdTechServer شامل یک پیاده‌سازی مرجع از یک سرور آزمایشی مبتنی بر برنامه Spring Boot برای Google App Engine است.

پیش‌نیازها

APIهای آزمایشی (mock APIs) را روی نقاط انتهایی راه دور که از دستگاه آزمایشی یا شبیه‌ساز شما قابل دسترسی هستند، مستقر کنید. برای سهولت آزمایش، به پروژه‌های نمونه MeasurementAdTechServerSpec و MeasurementAdTechServer مراجعه کنید.

عملکردی برای آزمایش

ویژگی‌های آینده

پیکربندی انعطاف‌پذیر در سطح رویداد

پیکربندی پیش‌فرض برای گزارش‌دهی سطح رویداد برای شروع آزمایش سودمندی توصیه می‌شود، اما ممکن است برای همه موارد استفاده ایده‌آل نباشد. API گزارش‌دهی نسبت‌دهی از پیکربندی‌های اختیاری و انعطاف‌پذیرتر پشتیبانی می‌کند تا تکنسین‌های تبلیغات کنترل بیشتری بر ساختار گزارش‌های سطح رویداد خود داشته باشند و بتوانند سودمندی داده‌ها را به حداکثر برسانند. این انعطاف‌پذیری اضافی در دو مرحله به API گزارش‌دهی نسبت‌دهی اضافه خواهد شد:

  • فاز ۱ : پیکربندی انعطاف‌پذیر سطح رویداد Lite؛ زیرمجموعه‌ای از فاز ۲.
  • مرحله ۲ : نسخه کامل پیکربندی انعطاف‌پذیر سطح رویداد.

مرحله ۱: سطح رویداد انعطاف‌پذیر سبک

ما دو پارامتر اختیاری زیر را به JSON در Attribution-Reporting-Register-Source اضافه خواهیم کرد:

  • max_event_level_reports
  • event_report_windows
{
  ...
  // Optional. This is a parameter that acts across all trigger types for the
  // lifetime of this source. It restricts the total number of event-level
  // reports that this source can generate. After this maximum is hit, the
  // source is no longer capable of producing any new data. The use of
  // priority in the trigger attribution algorithm in the case of multiple
  // attributable triggers remains unchanged. Defaults to 3 for navigation
  // sources and 1 for event sources
  "max_event_level_reports": <int>,

  // Optional. Represents a series of time windows, starting at 0. Reports
  // for this source will be delivered an hour after the end of each window.
  // Time is encoded as seconds after source registration. If
  // event_report_windows is omitted, will use the default windows. This
  // field is mutually exclusive with the existing `event_report_window` field.
  // // End time is exclusive.
  "event_report_windows": {
    "start_time": <int>,
    "end_times": [<int>, ...]
  }
}

مثال پیکربندی سفارشی

این پیکربندی نمونه از توسعه‌دهنده‌ای پشتیبانی می‌کند که می‌خواهد دریافت گزارش‌ها را در پنجره‌های گزارش‌دهی قبلی بهینه‌سازی کند.

{
  ...
  "max_event_level_reports": 2,
  "event_report_windows": {
    "end_times": [7200, 43200, 86400] // 2 hours, 12 hours, 1 day in seconds
  }
}

مرحله ۲: سطح رویداد کاملاً انعطاف‌پذیر

علاوه بر پارامترهایی که در فاز ۱ اضافه شدند، یک پارامتر اختیاری دیگر به نام trigger_specs به JSON در Attribution-Reporting-Register-Source اضافه خواهیم کرد.

{
  // A trigger spec is a set of matching criteria, along with a scheme to
  // generate bucketized output based on accumulated values across multiple
  // triggers within the specified event_report_window. There will be a limit on
  // the number of specs possible to define for a source.
  "trigger_specs": [{
    // This spec will only apply to registrations that set one of the given
    // trigger data values (non-negative integers) in the list.
    // trigger_data will still appear in the event-level report.
    "trigger_data": [<int>, ...]

    // Represents a series of time windows, starting at the source registration
    // time. Reports for this spec will be delivered an hour after the end of
    // each window. Time is encoded as seconds after source registration.
    // end_times must consist of strictly increasing positive integers.
    //
    // Note: specs with identical trigger_data cannot have overlapping windows;
    // this makes sure that triggers match at most one spec. If
    // event_report_windows is omitted, will use the "event_report_window" or
    // "event_report_windows" field specified at the global level for the source
    // (or the default windows if none are specified). End time is exclusive.
    "event_report_windows": {
      "start_time": <int>,
      "end_times": [<int>, ...],
    }

    // Represents an operator that summarizes the triggers within a window
    // count: number of triggers attributed within a window
    // value_sum: sum of the value of triggers within a window
    // The summary is reported as an index into a bucketization scheme. Defaults
    // to "count"
    "summary_window_operator": <one of "count" or "value_sum">,

    // Represents a bucketization of the integers from [0, MAX_INT], encoded as
    // a list of integers where new buckets begin (excluding 0 which is
    // implicitly included).
    // It must consist of strictly increasing positive integers.
    //
    // e.g. [5, 10, 100] encodes the following ranges:
    // [[0, 4], [5, 9], [10, 99], [100, MAX_INT]]
    //
    // At the end of each reporting window, triggers will be summarized into an
    // integer which slots into one of these ranges. Reports will be sent for
    // every new range boundary that is crossed. Reports will never be sent for
    // the range that includes 0, as every source is initialized in this range.
    //
    // If omitted, then represents a trivial mapping
    // [1, 2, ... , MAX_INT]
    // With MAX_INT being the maximum int value defined by the browser.
    "summary_buckets": [<bucket start>, ...]
  }, {
    // Next trigger_spec
  } ...],

  // See description in phase 1.
  "max_event_level_reports": <int>
  // See description in phase 1.
  "event_report_windows": {
    "start_time": <int>,
    "end_times": [<int>, ...]
  }
}

این پیکربندی، فضای خروجی گزارش‌های سطح رویداد را به ازای هر ثبت منبع، به طور کامل مشخص می‌کند. برای هر مشخصات تریگر، موارد زیر را به طور کامل مشخص می‌کنیم:

  • مجموعه‌ای از معیارهای تطبیق:
    • این مشخصات برای کدام داده‌های تریگر خاص اعمال می‌شود. این منبع فقط واجد شرایط تطبیق با تریگرهایی است که یکی از مقادیر trigger_data مشخص شده در trigger_specs را داشته باشند. به عبارت دیگر، اگر تریگر با این منبع تطبیق داده می‌شد اما trigger_data آن یکی از مقادیر موجود در پیکربندی منبع نباشد، تریگر نادیده گرفته می‌شود.
    • وقتی یک trigger خاص با این مشخصات مطابقت دارد (با استفاده از event_report_windows ). توجه داشته باشید که trigger می‌تواند با وجود عدم موفقیت در دو معیار تطابق ذکر شده قبلی، همچنان با منبعی برای گزارش‌های تجمیعی مطابقت داشته باشد.
  • یک الگوریتم خاص برای خلاصه‌سازی و دسته‌بندی تمام تریگرها در یک پنجره‌ی انتساب. این به تریگرها اجازه می‌دهد تا یک پارامتر value را مشخص کنند که برای یک مشخصات خاص خلاصه می‌شود، اما به عنوان یک مقدار دسته‌بندی شده گزارش می‌شود.

تریگرها همچنین از اضافه کردن یک پارامتر مقداری اختیاری در دیکشنری‌های درون event_trigger_data پشتیبانی می‌کنند.

{
  "event_trigger_data": [
    {
      "trigger_data": "2",
      "value": 100,  // Defaults to 1
      "filters": ...
    },
    ...
  ]
}

هر ثبت تریگر حداکثر با یک مشخصات تریگر مطابقت خواهد داشت و مقدار خلاصه مرتبط با آن را به‌روزرسانی می‌کند. در سطح بالا، در زمان تریگر، ما:

  • فیلترهای انتساب سراسری را اعمال کنید.
  • برای هر مشخصه تریگر، event_trigger_data را روی آن مشخصه ارزیابی کنید تا با استفاده از event_reporting_window آن مشخصه، یک مورد منطبق پیدا کنید. event_reporting_windows سطح بالا به عنوان مقدار پیش‌فرض عمل می‌کند در صورتی که هر مشخصه تریگر، زیرفیلد event_report_windows نداشته باشد.
  • اولین مشخصات منطبق برای انتساب انتخاب می‌شود و مقدار خلاصه با value افزایش می‌یابد.

وقتی پنجره event_report_window برای یک spec تکمیل شد، مقدار خلاصه آن را به یک bucket نگاشت می‌کنیم و برای هر افزایش در summe bucket ناشی از مقادیر trigger نسبت داده شده، یک گزارش در سطح رویداد ارسال می‌کنیم. گزارش‌ها با یک فیلد اضافی، trigger_summary_bucket ، ارائه می‌شوند.

{
  ...
  "trigger_summary_bucket": [<bucket start>, <bucket end>],
}

پیکربندی‌هایی که معادل نسخه فعلی هستند

پیکربندی‌های معادل برای رویدادهای فعلی APIها و منابع ناوبری به ترتیب در زیر آمده است. به خصوص برای منابع ناوبری، این نشان می‌دهد که چرا سطوح نویز نسبت به منابع رویداد برای حفظ مقادیر اپسیلون یکسان بسیار بالا هستند: منابع ناوبری فضای خروجی بسیار بزرگتری دارند.

با توجه به اینکه برخی پارامترها می‌توانند به صورت پیش‌فرض تنظیم شوند یا هرس شوند، ممکن است چندین پیکربندی معادل وجود داشته باشد.

منابع رویداد معادل
// Note: most of the fields here are not required to be explicitly listed.
// Here we list them explicitly just for clarity.
{
  "trigger_specs": [
  {
    "trigger_data": [0, 1],
    "event_report_windows": {
      "end_times": [<30 days>]
    },
    "summary_window_operator": "count",
    "summary_buckets": [1],
  }],
  "max_event_level_reports": 1,
  ...
  // expiry must be greater than or equal to the last element of the end_times
  "expiry": <30 days>,
}
منابع ناوبری معادل
// Note: most of the fields here are not required to be explicitly listed.
// Here we list them explicitly just for clarity.
{
  "trigger_specs": [
  {
    "trigger_data": [0, 1, 2, 3, 4, 5, 6, 7],
    "event_report_windows": {
      "end_times": [<2 days>, <7 days>, <30 days>]
    },
    "summary_window_operator": "count",
    "summary_buckets": [1, 2, 3],
  }],
  "max_event_level_reports": 3,
  ...
  // expiry must be greater than or equal to the last element of the end_times
  "expiry": <30 days>,
}

مثال پیکربندی‌های سفارشی

در ادامه برخی از پیکربندی‌های اضافی خارج از پیش‌فرض‌ها آمده است. در تمام این مثال‌ها، موارد زیر از جمله مواردی هستند که توسعه‌دهنده می‌تواند به آن‌ها توجه کند:

  • کاهش برخی از ابعاد پیکربندی پیش‌فرض (#تریگرها، کاردینالیتی داده‌های تریگر، #پنجره‌ها) برای افزایش ابعاد دیگر به منظور حفظ سطح نویز
  • کاهش برخی از ابعاد پیکربندی پیش‌فرض (#تریگرها، تعداد داده‌های تریگر، #پنجره‌ها) برای کاهش سطح نویز

گزارش مقادیر ماشه

این پیکربندی نمونه از توسعه‌دهنده‌ای پشتیبانی می‌کند که می‌خواهد داده‌های ارزشی را فقط برای یک بازه زمانی گزارش‌دهی (مثلاً ۷ روز) بهینه‌سازی کند و با معامله بازه‌های زمانی گزارش‌دهی کمتر، نویز کمتری داشته باشد. در این مثال، هر تریگری که trigger_data را روی مقداری غیر از ۰ تنظیم کند، واجد شرایط انتساب نیست.

{
  "trigger_specs": [
  {
    "trigger_data": [0],
    "event_report_windows": {
      "end_times": [604800, 1209600] // 7 days, 14 days represented in seconds
    },
    "summary_window_operator": "value_sum",
    "summary_buckets": [5, 10, 100]
  }],
}

تریگرها می‌توانند با مجموعه فیلدهای value ثبت شوند که خلاصه و دسته‌بندی می‌شوند. برای مثال، اگر سه تریگر در عرض ۷ روز از ثبت منبع با مقادیر ۱، ۳ و ۴ وجود داشته باشد.

{ "event_trigger_data": [{"trigger_data": "0", "value": 1}] }
{ "event_trigger_data": [{"trigger_data": "0", "value": 3}] }
{ "event_trigger_data": [{"trigger_data": "0", "value": 4}] }

مقادیر با هم جمع شده و ۸ می‌شوند و پس از ۷ روز + ۱ ساعت در گزارش‌های زیر گزارش می‌شوند:

// Report 1
{
  ...
  "trigger_summary_bucket": [5, 9]
}

در 7 روز بعدی، محرک‌های زیر ثبت می‌شوند:

{ "event_trigger_data": [{"trigger_data": "0", "value": 50}] }
{ "event_trigger_data": [{"trigger_data": "0", "value": 45}] }

مقادیر با هم جمع می‌شوند: ۸ + ۵۰ + ۴۵ = ۱۰۳. این منجر به گزارش‌های زیر در ۱۴ روز + ۱ ساعت می‌شود:

// Report 2
{
  ...
  "trigger_summary_bucket": [10, 99]
},

// Report 3
{
  ...
  "trigger_summary_bucket": [100, MAX_INT]
}
گزارش تعداد محرک‌ها

این مثال نشان می‌دهد که چگونه یک توسعه‌دهنده می‌تواند یک منبع را طوری پیکربندی کند که تعداد تریگرها را تا 10 عدد دریافت کند.

{
  "trigger_specs": [
  {
    "trigger_data": [0],
    "event_report_windows": {
      "end_times": [604800] // 7 days represented in seconds
    },
    // This field could be omitted to save bandwidth since the default is "count"
    "summary_window_operator": "count",
    "summary_buckets": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
  }],
}

تریگرهای نسبت داده شده با trigger_data که روی ۰ تنظیم شده‌اند، شمارش می‌شوند و حداکثر تعداد آنها ۱۰ است. مقدار تریگر نادیده گرفته می‌شود زیرا summary_window_operator روی شمارش تنظیم شده است. اگر ۴ تریگر ثبت شده و به منبع نسبت داده شوند، گزارش به این شکل خواهد بود:

// Report 1
{
  ...
  "trigger_summary_bucket": [1, 1]
}
// Report 2
{
  ...
  "trigger_summary_bucket": [2, 2]
}
// Report 3
{
  ...
  "trigger_summary_bucket": [3, 3]
}
// Report 4
{
  ...
  "trigger_summary_bucket": [4, 4]
}
دودویی با گزارش‌های مکرر

این پیکربندی نمونه از توسعه‌دهنده‌ای پشتیبانی می‌کند که می‌خواهد بداند آیا حداقل یک تبدیل در 10 روز اول (صرف نظر از مقدار) رخ داده است یا خیر، اما می‌خواهد گزارش‌ها را در فواصل زمانی بیشتری نسبت به حالت پیش‌فرض دریافت کند. باز هم، در این مثال، هر تریگری که trigger_data روی مقداری غیر از 0 تنظیم کند، واجد شرایط انتساب نیست. به همین دلیل است که به این مورد استفاده، باینری گفته می‌شود.

{
  "trigger_specs": [
  {
    "trigger_data": [0],
    "event_report_windows": {
      // 1 day, 2 days, 3 days, 5 days, 7 days, 10 days represented in seconds
      "end_times": [86400, 172800, 259200, 432000, 604800, 864000]
    },
    // This field could be omitted to save bandwidth since the default is "count"
    "summary_window_operator": "count",
    "summary_buckets": [1]
  }],
}
مشخصات تریگر را از منبعی به منبع دیگر تغییر دهید
{
  "trigger_specs": [
  {
    "trigger_data": [0, 1, 2, 3],
    "event_report_windows": {
      "end_times": [172800, 604800, 2592000] // 2 days, 7 days, 30 days represented in seconds
    }
  }],
  "max_event_level_reports": 3
}
{
  "trigger_specs": [
  {
    "trigger_data": [4, 5, 6, 7],
    "event_report_windows": {
      "end_times": [172800, 604800, 2592000] // 2 days, 7 days, 30 days represented in seconds
    }
  }],
  "max_event_level_reports": 3
}

ما توسعه‌دهندگان را تشویق می‌کنیم تا موارد استفاده‌ی مختلفی را که ممکن است برای این افزونه‌ی API داشته باشند، پیشنهاد دهند و ما این توضیح را با پیکربندی‌های نمونه برای آن موارد استفاده به‌روزرسانی خواهیم کرد.

انتساب بین شبکه‌ای بدون تغییر مسیر

تکنسین‌های تبلیغات باید از ریدایرکت‌ها برای ثبت چندین منبع ارجاع و انجام ارجاع بین شبکه‌ای استفاده کنند. این ویژگی به پشتیبانی از ارجاع بین شبکه‌ای در مواردی که ریدایرکت‌ها در شبکه‌ها امکان‌پذیر نیستند، کمک می‌کند. اطلاعات بیشتر .

تکنسین‌های تبلیغات می‌توانند در پاسخ ثبت تریگر، پیکربندی ارسال کنند که بر اساس آن، منابع ثبت‌شده توسط سایر تکنسین‌های تبلیغات برای تولید منابع مشتق‌شده انتخاب می‌شوند؛ سپس از این منابع مشتق‌شده برای انتساب استفاده می‌شود. در صورتی که تریگر به یک منبع مشتق‌شده نسبت داده شود، گزارش‌های تجمیعی تولید می‌شوند. تولید گزارش رویداد برای منابع مشتق‌شده پشتیبانی نمی‌شود.

تکنسین‌های تبلیغات می‌توانند از بین aggregation_keys در منابع ثبت‌شده خود، کلیدهایی را که قصد دارند با تکنسین‌های تبلیغات شریک به اشتراک بگذارند، انتخاب کنند. این کلیدها را می‌توان در فیلد اختیاری shared_aggregation_keys ، واقع در زیر سربرگ ثبت منبع Attribution-Reporting-Register-Source اعلام کرد:

"shared_aggregation_keys": ["[key name1]", "[key name2]"]

منابع مشتق شده بر اساس پیکربندی زیر هدر ثبت تریگر Attribution-Reporting-Register-Trigger تولید می‌شوند:

  // Specifies the configuration based on which derived sources should be
  // generated. Those derived sources will be included for source matching at the
  // time of attribution. For example, if adtech2 is registering a trigger with an
  // attribution_config with source_network as adtech1, available sources
  // registered by adtech1 will be considered with additional filtering criteria
  // applied to that set as mentioned in the attribution_config. Derived
  // sources can have different values to priority, post_install_exclusivity_window
  // etc.

  "attribution_config": [
    {
      // Derived sources are created from this adtech's registered sources
      "source_network": "[original source's adtech enrollment ID]",
      //(optional) Filter sources whose priority falls in this range
      "source_priority_range": {
        "start": [priority filter lower bound],
        "end": [priority filter upper bound]
      },
      // (optional) Filter sources whose at least one of filter maps matches these
      // filters
      "source_filters": {
        "key name 1": ["key1 value 1"]
      },
      // (optional) Filter sources whose none of filter map matches these
      // filters
        "source_not_filters": {
          "key name 1": ["key1 value 1"]
        },
      // (optional) Apply this priority to the generated derived sources
      "priority": "[64 bit signed integer]",
      // (optional) The derived source will have expiry set as this or parent
      // source's, whichever is earlier
      "expiry": "[64 bit signed integer]",
      // (optional) set on the derived source
      "filter_data": {
        "key name 1": ["key1 value 1"]
      },
      // (optional) set on the derived source
      "post_install_exclusivity_window": "[64-bit unsigned integer]"
    }
  ]

در اینجا نسخه‌ای با مقادیر نمونه اضافه شده است:

  "attribution_config": [
    {
      "source_network": "adtech1-enrollment-id",
      "source_priority_range": {
        "start": 50,
        "end": 100
      },
      "source_filters": {
        "source_type": ["NAVIGATION"]
      },
      "source_not_filters": {
        "product_id": ["789"]
      },
      "priority": "30",
      "expiry": "78901",
      // (optional) set on the derived source
      "filter_data": {
        "product_id": ["1234"]
        },
      // (optional) set on the derived source
      "post_install_exclusivity_window": "7890"
    }
  ]

دو فیلد اختیاری جدید برای فعال کردن سربرگ ثبت نام اضافه شده است. این فیلدها شناسه برنده فناوری تبلیغات را در کلیدهای گزارش تجمیعی فعال می‌کنند:

  • x_network_bit_mapping : نگاشت بیتی شناسه ثبت نام به شناسه فناوری تبلیغات
  • x_network_data : آفست (شیفت به چپ) برای عملیات x_network_bit_mapping OR تکنسین تبلیغات برنده با قطعه کلید تریگر
مثال:
"Attribution-Reporting-Register-Trigger": {
  "attribution_config": [...],
  "aggregatable_trigger_data": [
    {
     "key_piece": "0x400",
     "source_keys": ["campaignCounts"]
      "x_network_data" : {
        "key_offset" : 12 // [64 bit unsigned integer]
      }
    }
    
  ]
  
  "x_network_bit_mapping": {
   // This mapping is used to generate trigger key pieces with ad tech identifier
   // bits. eg. If Ad Tech-A's sources wins the attribution then 0x1 here will be
   // OR'd with the trigger key pieces to generate the final key piece.
    "Ad-Tech-A-enrollment_id": "0x1", // Identifier bits in hex for A
    "Ad-Tech-B-enrollment_id": "0x2"  // Identifier bits in hex for B
  }
  
}

در اینجا محاسبه قطعه کلید محرک حاصل هنگام تولید گزارش برای منبع AdTechB آمده است:

  • key_piece : 0x400 (010000000000)
  • key_offset : 12
  • مقدار enrollment_id مربوط به AdtechB: 2 (010) (از x_network_bit_mapping )
  • قطعه کلید فعال کننده حاصل: 0x400 | 0x2 << 12 = 0x2400

محدودیت‌ها

برای مشاهده‌ی فهرستی از قابلیت‌های در حال توسعه برای SDK Runtime، به یادداشت‌های انتشار مراجعه کنید.

گزارش اشکالات و مشکلات

بازخورد شما بخش مهمی از Privacy Sandbox در اندروید است! هرگونه مشکلی که پیدا می‌کنید یا ایده‌هایی برای بهبود Privacy Sandbox در اندروید را با ما در میان بگذارید.