دليل المطوّر لواجهة برمجة التطبيقات Attribution Reporting API

أثناء قراءة مستندات "مبادرة حماية الخصوصية على Android"، استخدِم الزر الإصدار التجريبي من البرنامج أو الإصدار التجريبي لاختيار إصدار البرنامج الذي تستخدمه، لأنّ التعليمات قد تختلف.


تمّ تصميم Attribution Reporting API لتعزيز خصوصية المستخدمين من خلال إنهاء الاعتماد على معرّفات المستخدمين من الجهات المختلفة، إضافةً إلى توفير حالات استخدام مهمّة تتيح قياس الإحالات الناجحة وتحديد المصدر على التطبيقات. يوضّح دليل المطوّرين هذا كيفية إعداد واجهات برمجة التطبيقات الخاصة بميزة "إعداد التقارير لتحديد المصدر" واختبارها لتسجيل النقرات على الإعلانات ومرّات مشاهدتها والإحالات الناجحة من خلال استدعاء الطرق التي تسجّل عوامل التشغيل والمصادر ذات الصلة بهذه الأحداث.

يعلّمك هذا الدليل كيفية إعداد نقاط نهاية الخادم وإنشاء تطبيق عميل يستدعي هذه الخدمات. يمكنك الاطّلاع على مزيد من المعلومات حول التصميم العام لواجهة برمجة التطبيقات Attribution Reporting API في اقتراح التصميم.

العبارات الرئيسية

  • تشير مصادر تحديد المصدر إلى النقرات أو المشاهدات.
  • المشغّلات هي الأحداث التي يمكن إسنادها إلى الإحالات الناجحة.
  • تحتوي التقارير على بيانات حول مشغّل ومصدر الإحالة الناجحة المقابل. يتم إرسال هذه التقارير استجابةً لأحداث مشغِّلة. تتيح واجهة برمجة التطبيقات Attribution Reporting API التقارير على مستوى الحدث والتقارير القابلة للتجميع.

قبل البدء

لاستخدام واجهة برمجة التطبيقات Attribution Reporting API، عليك إكمال المهام من جهة الخادم ومن جهة العميل المدرَجة في الأقسام التالية.

إعداد نقاط نهاية Attribution Reporting API

تتطلّب Attribution Reporting API مجموعة من نقاط النهاية التي يمكنك الوصول إليها من جهاز اختباري أو محاكي. أنشئ نقطة نهاية واحدة لكل من المهام التالية من جهة الخادم:

تتوفّر عدة طرق لإعداد نقاط النهاية المطلوبة:

  • أسرع طريقة للبدء هي نشر تعريفات خدمة OpenAPI الإصدار 3 من مستودع نماذج الرموز البرمجية إلى منصة محاكاة أو منصة خدمات مصغّرة. يمكنك استخدام Postman أو Prism أو أي منصة أخرى لخادم تجريبي تقبل هذا التنسيق. انشر كل نقطة نهاية وتتبَّع معرّفات الموارد الموحّدة لاستخدامها في تطبيقك. وللتأكّد من تسليم التقارير، راجِع الطلبات التي تم إجراؤها سابقًا إلى المنصة الوهمية أو التي لا تحتاج إلى خادم.
  • يمكنك تشغيل خادم مستقل باستخدام نموذج Kotlin المستند إلى Spring Boot. يمكنك نشر هذا الخادم على مقدّم الخدمات السحابية أو البنية الأساسية الداخلية.
  • استخدِم تعريفات الخدمة كأمثلة لدمج نقاط النهاية في نظامك الحالي.

قبول تسجيل المصدر

يجب أن تكون نقطة النهاية هذه قابلة للعنونة من خلال معرّف موارد موحّد مشابه لما يلي:

https://adtech.example/attribution_source

عندما يسجّل تطبيق العميل مصدر تحديد المصدر، يقدّم معرّف الموارد المنتظم (URI) لنقطة نهاية الخادم هذه. بعد ذلك، تُرسِل Attribution Reporting 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) لشركاء تكنولوجيا الإعلان، ستُرسِل واجهة برمجة التطبيقات Attribution Reporting API طلبًا مشابهًا إلى كل معرّف موارد منتظم. على كل شريك في تكنولوجيا الإعلان إعداد خادم يستجيب باستخدام العناوين التالية:

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.

قبول تسجيل مشغّل الإحالات الناجحة

يجب أن تكون نقطة النهاية هذه قابلة للعنونة من خلال معرّف موارد موحّد مشابه لما يلي:

https://adtech.example/attribution_trigger

عندما يسجّل تطبيق عميل حدثًا مشغّلاً، يقدّم معرّف الموارد المنتظم (URI) لنقطة نهاية الخادم هذه. بعد ذلك، تقدّم Attribution Reporting API طلبًا وتتضمّن أحد العناوين التالية:

اضبط نقطة نهاية الخادم للاستجابة بما يلي:

// 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

يبلغ الحدّ الأقصى 25 بايت لكلّ من معرّف مفتاح التجميع وسلسلة الفلتر. وهذا يعني أنّه يجب ألا تتجاوز أرقام تعريف مفاتيح التجميع وسلاسل الفلتر 25 حرفًا. في هذا المثال، يبلغ طول campaignCounts 14 حرفًا، لذا فهو معرّف صالح لمفتاح التجميع، ويبلغ طول 1234 4 أحرف، لذا فهو سلسلة فلتر صالحة. إذا تجاوز معرّف مفتاح التجميع أو سلسلة الفلتر 25 حرفًا، سيتم تجاهل المشغّل.

إذا كان الحقل Attribution-Reporting-Redirect يحتوي على معرّفات موارد منتظمة (URI) لشركاء تكنولوجيا الإعلان، ستُرسِل واجهة برمجة التطبيقات Attribution Reporting API طلبًا مشابهًا إلى كل معرّف موارد منتظم. على كل شريك في تكنولوجيا الإعلان إعداد خادم يستجيب باستخدام العناوين التالية:

// 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) من مصدر الخوادم المستخدَمة لقبول تسجيل المصدر وتسجيل المشغّل). باستخدام مثالَي معرّفَي الموارد المنتظم (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) من مصدر الخوادم المستخدَمة لقبول تسجيل المصدر وتسجيل المشغّل). باستخدام مثالَي معرّفَي الموارد المنتظم (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]"
}

تتيح مفاتيح تصحيح الأخطاء الحصول على إحصاءات إضافية في تقارير تحديد المصدر، ويمكنك الاطّلاع على مزيد من المعلومات حول كيفية إعدادها.

إعداد تطبيق Android

يسجّل تطبيق العميل مصادر تحديد المصدر وعوامل التشغيل، ويتيح إنشاء تقارير على مستوى الحدث وتقارير قابلة للتجميع. لإعداد جهاز أو محاكي Android لاستخدام Attribution Reporting API، اتّبِع الخطوات التالية:

  1. إعداد بيئة التطوير لـ "مبادرة حماية الخصوصية" على Android
  2. تثبيت صورة نظام على جهاز متوافق أو إعداد محاكي يتوافق مع "مبادرة حماية الخصوصية" على Android
  3. فعِّل إمكانية الوصول إلى Attribution Reporting API من خلال تنفيذ أمر ADB التالي. (تكون واجهة برمجة التطبيقات غير مفعّلة تلقائيًا).

    adb shell device_config put adservices ppapi_app_allow_list \"\*\"
  4. إذا كنت تختبر واجهة Attribution Reporting API محليًا (مثل الاختبار على جهاز يمكنك الوصول إليه فعليًا)، شغِّل الأمر التالي لإيقاف التسجيل:

    adb shell device_config put adservices disable_measurement_enrollment_check "true"
  5. أدرِج الإذن ACCESS_ADSERVICES_ATTRIBUTION في ملف Android Manifest وأنشئ إعدادات لخدمات الإعلانات كي يتمكّن تطبيقك من استخدام واجهات برمجة التطبيقات الخاصة بميزة "إعداد التقارير حول تحديد المصدر":

    <uses-permission android:name="android.permission.ACCESS_ADSERVICES_ATTRIBUTION" />
    
  6. (اختياري) إذا كنت تخطّط لتلقّي تقارير تصحيح الأخطاء، أدرِج الإذن ACCESS_ADSERVICES_AD_ID في ملف بيان Android:

    <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() لتسجيل مصدر تحديد المصدر على النحو الموضّح في مقتطف الرمز.

تتيح واجهة برمجة التطبيقات Attribution Reporting API أنواع أحداث مصدر تحديد المصدر التالية:

  • النقرات، التي تسجّلها عادةً ضمن طريقة ردّ اتصال مشابهة لما يلي: onClick() يحدث حدث التفعيل المقابل عادةً بعد حدث النقر بوقت قصير. يقدّم هذا النوع من الأحداث المزيد من المعلومات حول تفاعل المستخدِم، وبالتالي فهو نوع جيد من مصادر تحديد المصدر لمنحه أولوية عالية.
  • عدد المشاهدات، الذي يتم تسجيله عادةً ضمن طريقة ردّ الاتصال المشابهة لما يلي: onAdShown() قد يحدث حدث التشغيل المقابل بعد ساعات أو أيام من حدث المشاهدة.

Kotlin

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)

Java

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);

بعد التسجيل، ترسل واجهة برمجة التطبيقات طلب HTTP POST إلى نقطة نهاية الخدمة على العنوان المحدّد بواسطة attributionSourceUri. يتضمّن ردّ نقطة النهاية قيمًا للسمتَين destination, source_event_id, expiry وsource_priority.

إذا أرادت تكنولوجيا الإعلان الأصلية مشاركة عمليات تسجيل المصدر، يمكن أن يتضمّن معرّف الموارد المنتظم لمصدر تحديد المصدر الأصلي عمليات إعادة توجيه إلى نقاط نهاية أخرى لتكنولوجيا الإعلان. يمكنك الاطّلاع على تفاصيل الحدود والقواعد التي تنطبق على عمليات إعادة التوجيه في الاقتراح الفني.

تمت إضافة إمكانية استخدام عمليات إعادة التوجيه المتسلسلة لـ registerSource وregisterTrigger. بالإضافة إلى عنوان التسجيل، يمكن لمستهلك واجهة برمجة التطبيقات الآن تقديم عملية إعادة توجيه HTTP كاستجابة الخادم التي تتضمّن رمز الحالة 302 وعنوان "الموقع الجغرافي" مع عنوان URL التالي الذي يجب الانتقال إليه لإجراء عملية تسجيل إضافية.

يتم استخدام حقل "الوجهة" المقدَّم في الزيارة الأولى فقط في جميع مراحل التسلسل. يخضع عدد الزيارات للحدّ نفسه الذي تخضع له عناوين "Attribution-Reporting-Redirect". تتوفّر ميزة إعادة التوجيه هذه بالإضافة إلى ميزة "Attribution-Reporting-Redirect" الحالية، وفي حال توفّرهما معًا، ستكون الأولوية لميزة "Attribution-Reporting-Redirect".

تسجيل حدث مشغّل إحالة ناجحة

لتسجيل حدث مشغّل إحالة ناجحة، استخدِم registerTrigger() في تطبيقك:

Kotlin

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)

Java

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)

بعد التسجيل، ترسل واجهة برمجة التطبيقات طلب HTTP POST إلى نقطة نهاية الخدمة على العنوان المحدّد بواسطة attributionTriggerUri. تتضمّن استجابة نقطة النهاية قيمًا لتقارير الأحداث والتقارير المجمّعة.

إذا كانت منصة تكنولوجيا الإعلان الأصلية تسمح بمشاركة عمليات تسجيل المشغّلات، يمكن أن يتضمّن معرّف الموارد المنتظم عمليات إعادة توجيه إلى معرّفات موارد منتظمة تابعة لمنصات تكنولوجيا إعلان أخرى. يمكن الاطّلاع على الحدود والقواعد السارية على عمليات إعادة التوجيه بالتفصيل في الاقتراح الفني.

تسجيل ميزة القياس على التطبيقات والويب

في حال تأثير كلّ من التطبيق والمتصفّح في رحلة المستخدِم من المصدر إلى الحدث المشغِّل، هناك اختلافات طفيفة في طريقة تنفيذ تسجيل الأحداث الإعلانية. إذا شاهد مستخدم إعلانًا على تطبيق وتمت إعادة توجيهه إلى متصفّح لإجراء إحالة ناجحة، يسجّل التطبيق المصدر، ويسجّل متصفّح الويب الإحالة الناجحة. وبالمثل، إذا بدأ المستخدم رحلته على متصفّح ويب وتم توجيهه إلى تطبيق لإجراء إحالة ناجحة، سيسجّل المتصفّح المصدر، وسيسجّل التطبيق الإحالة الناجحة.

بما أنّ هناك اختلافات في طريقة تنظيم تكنولوجيات الإعلان على الويب وعلى Android، أضفنا واجهات برمجة تطبيقات جديدة لتسجيل المصادر والمشغّلات عند حدوثها على المتصفّحات. يتمثّل الاختلاف الرئيسي بين واجهات برمجة التطبيقات هذه وواجهات برمجة التطبيقات المستندة إلى التطبيقات المقابلة في أنّنا نتوقّع من المتصفّح اتّباع عمليات إعادة التوجيه وتطبيق أي فلاتر خاصة بالمتصفّح وتمرير عمليات التسجيل الصالحة إلى المنصة من خلال استدعاء registerWebSource() أو registerWebTrigger().

يعرض مقتطف الرمز التالي مثالاً على طلب البيانات من واجهة برمجة التطبيقات الذي يرسله المتصفّح لتسجيل مصدر تحديد المصدر قبل توجيه المستخدم إلى تطبيق:

Kotlin

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)

Java

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);

يعرض مقتطف الرمز التالي مثالاً على طلب البيانات من واجهة برمجة التطبيقات الذي يرسله المتصفّح لتسجيل إحالة ناجحة بعد أن يتم توجيه المستخدم من التطبيق:

Kotlin

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)

Java

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);

إضافة تشويش لحماية الخصوصية

تحتوي التقارير على مستوى الحدث على بيانات الوجهة ورقم تعريف مصدر تحديد المصدر والمشغّل. ويتم إرسالها بالتنسيق الأصلي (غير المشفّر) إلى مصدر الإبلاغ. لحماية خصوصية المستخدم، يمكن إضافة تشويش لجعل تحديد هوية مستخدم فردي أكثر صعوبة. يتم إنشاء تقارير مشوّشة على مستوى الحدث وإرسالها وفقًا لإطار عمل الخصوصية التفاضلية. في ما يلي قيم النسبة المئوية التلقائية للتشويش في السيناريوهات المختلفة:

نوع المصدر

قيمة الوجهة المصدر

احتمالية إعداد تقرير مشوّش لكل عملية تسجيل مصدر

عرض

التطبيق أو الويب

0.0000025

عرض

التطبيقات والإنترنت

0.0000042

النقر

التطبيق أو الويب

0.0024263

النقر

التطبيقات والإنترنت

0.0170218

في قياس تحديد المصدر من التطبيق إلى الويب، حيث يمكن للمصادر أن تؤدي إلى إحالات ناجحة في كلّ من وجهات التطبيق والويب، يمكن لتقارير مستوى الحدث أن تحدّد ما إذا كان المشغّل قد حدث على التطبيق أو الويب. وللتعويض عن هذه التفاصيل الإضافية، تصل التقارير التي تم تشويشها إلى 7 أضعاف بالنسبة إلى النقرات و1.7 ضعف بالنسبة إلى مرات المشاهدة.

لا تتطلّب بعض تكنولوجيات الإعلان تقارير على مستوى الحدث لتحديد ما إذا كان المشغّل قد حدث في التطبيق أو على الموقع الإلكتروني. يمكن لتكنولوجيات الإعلان استخدام الحقل coarse_event_report_destinations ضمن العنوان Attribution-Reporting-Register-Source للحدّ من التشويش. إذا فاز مصدر تم تحديد الحقل coarse_event_report_destinations فيه بعملية تحديد المصدر، سيتضمّن التقرير الناتج كلاً من وجهات التطبيق والويب بدون تمييز بين مكان حدوث المشغّل الفعلي.

في الأمثلة التالية، ينقر مستخدم على إعلان، ويتم تسجيل المصدر باستخدام واجهة برمجة التطبيقات. بعد ذلك، يُجري المستخدِم إحالة ناجحة على كلّ من تطبيق المعلِن وموقعه الإلكتروني. يتم تسجيل كلتا الإحالتَين الناجحتَين كإجراءات تؤدي إلى إحالات ناجحة، ويتم تحديد مصدرهما على أنّه النقرة الأولية.

عنوان 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
  }

إنشاء التقارير وتسليمها

ترسل Attribution Reporting API التقارير إلى نقاط النهاية على خادمك التي تقبل التقارير على مستوى الحدث والتقارير القابلة للتجميع.

فرض تشغيل مهام إعداد التقارير

بعد تسجيل حدث مصدر تحديد المصدر أو تسجيل حدث مشغِّل، يجدول النظام مهمة إعداد التقارير لتنفيذها. يتم تنفيذ هذه المهمة تلقائيًا كل 4 ساعات. لأغراض الاختبار، يمكنك فرض تشغيل مهام إعداد التقارير أو تقصير الفواصل الزمنية بين المهام.

فرض تنفيذ مهمة تحديد المصدر:

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);
});

الاختبار

لمساعدتك في بدء استخدام واجهة برمجة التطبيقات Attribution Reporting API، يمكنك استخدام مشروع MeasurementSampleApp على GitHub. يوضّح هذا التطبيق النموذجي عملية تسجيل مصدر تحديد المصدر وتسجيل المشغّل.

بالنسبة إلى نقاط نهاية الخادم، يمكنك الاطّلاع على مراجع الموارد التالية أو الحلّ المخصّص:

  • يتضمّن MeasurementAdTechServerSpec تعريفات خدمة OpenAPI، التي يمكن نشرها على منصات محاكاة أو خدمات مصغّرة متوافقة.
  • يتضمّن MeasurementAdTechServer عملية تنفيذ مرجعية لخادم وهمي يستند إلى تطبيق Spring Boot على Google App Engine.

المتطلبات الأساسية

نشر واجهات برمجة تطبيقات وهمية على نقاط نهاية بعيدة يمكن الوصول إليها من جهازك الاختباري أو المحاكي لتسهيل الاختبار، يمكنك الرجوع إلى مشروعي MeasurementAdTechServerSpec وMeasurementAdTechServer النموذجيين.

الوظيفة التي سيتم اختبارها

  • تسجيل مصادر تحديد المصدر ومشغّلات الإحالات الناجحة الخاصة بالتمارين الرياضية تأكَّد من أنّ نقاط النهاية من جهة الخادم تستجيب بالتنسيق الصحيح.
  • تنفيذ مهام إعداد التقارير
  • تأكَّد من تسليم التقارير على الخلفية أو وحدة التحكّم في خادم الاختبار.

الميزات القادمة

إعدادات مرنة على مستوى الحدث

ننصح باستخدام الإعداد التلقائي لإعداد التقارير على مستوى الحدث عند بدء اختبار الأداة المساعدة، ولكن قد لا يكون هذا الإعداد مناسبًا لجميع حالات الاستخدام. ستتيح واجهة برمجة التطبيقات Attribution Reporting إعدادات اختيارية أكثر مرونة، ما يمنح تكنولوجيات الإعلان تحكّمًا أكبر في بنية التقارير على مستوى الحدث، كما يتيح لها الاستفادة إلى أقصى حدّ من البيانات. سيتم توفير هذه المرونة الإضافية في Attribution Reporting API على مرحلتَين:

  • المرحلة 1: إعدادات مرنة بسيطة على مستوى الحدث، وهي مجموعة فرعية من المرحلة 2.
  • المرحلة 2: الإصدار الكامل من إعدادات مرنة على مستوى الحدث.

المرحلة 1: مستوى الحدث المرن البسيط

سنضيف المَعلمتَين الاختياريتَين التاليتَين إلى 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
  }
}

المرحلة 2: مستوى الحدث المرن الكامل

بالإضافة إلى المَعلمات التي تمت إضافتها في المرحلة 1، سنضيف مَعلمة اختيارية إضافية 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 ليس إحدى القيم في إعدادات المصدر، سيتم تجاهل المشغّل.
    • عندما يتطابق مشغّل معيّن مع هذا المواصفات (باستخدام event_report_windows)، يُرجى العِلم أنّه يمكن أن يتطابق المشغّل مع مصدر لإنشاء تقارير مجمّعة حتى في حال عدم استيفائه لمعيارَي التطابق المذكورَين سابقًا.
  • خوارزمية محدّدة لتلخيص جميع المشغّلات وتجميعها في فئات ضمن فترة تحديد المصدر يسمح ذلك للمشغّلات بتحديد المَعلمة 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 لأحد المواصفات، سنربط قيمة الملخّص بمجموعة، وسنرسل تقريرًا على مستوى الحدث لكل زيادة في مجموعة الملخّص ناتجة عن قيم مشغِّل محدّدة المصدر. ستتضمّن التقارير حقلاً إضافيًا واحدًا، وهو trigger_summary_bucket.

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

الإعدادات التي تتطابق مع الإصدار الحالي

في ما يلي إعدادات مكافئة لمصادر الأحداث والتنقّل الحالية في واجهات برمجة التطبيقات، على التوالي. ويوضّح ذلك سبب ارتفاع مستويات التشويش بشكل كبير مقارنةً بمصادر الأحداث، خاصةً بالنسبة إلى مصادر التنقّل، وذلك للحفاظ على قيم إبسيلون نفسها، لأنّ مصادر التنقّل تتضمّن مساحة نواتج أكبر بكثير.

من المحتمل أن تكون هناك إعدادات متعدّدة مكافئة، علمًا بأنّه يمكن ضبط بعض المَعلمات كإعدادات تلقائية أو حذفها.

مصادر الأحداث المكافئة
// 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>,
}

أمثلة على الإعدادات المخصّصة

في ما يلي بعض الإعدادات الإضافية التي تختلف عن الإعدادات التلقائية. في كل هذه الأمثلة، تشمل المفاضلات التي يجريها المطوّر ما يلي:

  • تقليل بعض جوانب الإعدادات التلقائية (عدد المشغّلات، وعدد القيم الفريدة لبيانات المشغّلات، وعدد النوافذ) لزيادة جانب آخر من أجل الحفاظ على مستوى التشويش
  • تقليل بعض أبعاد الإعداد التلقائي (#triggers، وعدد القيم المميزة لبيانات المشغّل، و#windows) لتقليل مستوى التشويش

حِزم قيم مشغّلات التقارير

يتيح إعداد المثال هذا للمطوّر تحسين القيمة الخاصة بفترة إعداد تقارير واحدة فقط (مثل 7 أيام)، مع تقليل عدد فترات إعداد التقارير لتقليل التشويش. في هذا المثال، يكون أي مشغّل يضبط trigger_data على قيمة غير 0 غير مؤهَّل لتحديد المصدر.

{
  "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، ويتم جمعها وتصنيفها. على سبيل المثال، إذا كانت هناك ثلاث مشغّلات خلال 7 أيام من عمليات تسجيل المصدر بقيم 1 و3 و4.

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

يتم جمع القيم لتصبح 8، ويتم عرضها في التقارير التالية بعد 7 أيام + ساعة واحدة:

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

في الأيام السبعة اللاحقة، يتم تسجيل المشغّلات التالية:

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

يتم جمع القيم لتصبح 8 + 50 + 45 = 103. يؤدي ذلك إلى إنشاء التقارير التالية بعد 14 يومًا وساعة واحدة:

// 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 على 0، ويتم تحديد الحد الأقصى لها بـ 10. يتم تجاهل قيمة المشغّل لأنّ summary_window_operator مضبوط على "عدد". في حال تسجيل 4 مشغّلات وتحديد مصدرها، سيبدو التقرير كما يلي:

// 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]
}
ثنائي مع إعداد تقارير أكثر تكرارًا

يتيح إعداد المثال هذا للمطوّر معرفة ما إذا حدثت إحالة ناجحة واحدة على الأقل في الأيام العشرة الأولى (بغض النظر عن القيمة)، ولكنّه يريد تلقّي التقارير على فترات زمنية أكثر تكرارًا من الإعدادات التلقائية. مرة أخرى، في هذا المثال، أي مشغّل يضبط 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
}

نشجّع المطوّرين على اقتراح حالات استخدام مختلفة قد تكون لديهم لهذا الامتداد لواجهة برمجة التطبيقات، وسنعدّل هذا المستند التوضيحي ليشمل نماذج إعدادات لحالات الاستخدام هذه.

الإحالة على جميع الشبكات بدون عمليات إعادة توجيه

على تكنولوجيات الإعلان استخدام عمليات إعادة التوجيه لتسجيل مشغّلات متعددة لمصدر الإحالة، ولإجراء عملية تحديد المصدر على مستوى شبكات متعددة. تساعد هذه الميزة في إتاحة تحديد المصدر على مستوى شبكات متعدّدة عندما لا يكون من الممكن استخدام عمليات إعادة التوجيه على مستوى الشبكات. مزيد من المعلومات

يمكن أن ترسل تقنيات الإعلان إعدادات في ردّ تسجيل المشغّل استنادًا إلى المصادر التي سجّلتها تقنيات إعلان أخرى والتي تم اختيارها لإنشاء مصادر مشتقة، ثم يتم استخدام هذه المصادر المشتقة لتحديد المصدر. يتم إنشاء التقارير المجمّعة إذا تم تحديد مصدر مشتق للحدث المشغِّل. لا تتوفّر إمكانية إنشاء تقرير أحداث للمصادر المشتقة.

يمكن لتقنيات الإعلان الاختيار من بين 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، يمكنك الاطّلاع على ملاحظات الإصدار.

الإبلاغ عن الأخطاء والمشاكل

تُعدّ ملاحظاتك جزءًا مهمًا من "مبادرة حماية الخصوصية" على Android. يُرجى إعلامنا بأي مشاكل تواجهك أو أفكار لديك لتحسين "مبادرة حماية الخصوصية" على Android.