دليل مطوّري برامج Attribution Reporting API

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


تقديم ملاحظات

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

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

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

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

قبل البدء

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

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

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

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

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

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

يجب أن تكون نقطة النهاية هذه قابلة للمعالجة من معرف موارد منتظم (URI) مشابه لما يلي:

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.

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

يجب أن تكون نقطة النهاية هذه قابلة للمعالجة من معرف موارد منتظم (URI) مشابه لما يلي:

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 not 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 not 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 not 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 will not 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 will not
      // 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) لنقاط النهاية التي تقبل تسجيل المصدر وتقبل تسجيل المشغِّل، يكون معرِّف الموارد المنتظم (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) لنقاط النهاية التي تقبل تسجيل المصدر وتقبل تسجيل المشغِّل، يكون معرِّف الموارد المنتظم (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 does not yet encrypt aggregate reports.
  // Currently, 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 وإنشاء إعداد للخدمات الإعلانية لتطبيقك من أجل استخدام Attribution Reporting API:

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

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

تمت إضافة الدعم لعمليات إعادة التوجيه من سلسلة العلامات المتتالية للنطاقَين 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. يتضمّن استجابة نقطة النهاية قيمًا للأحداث والتقارير المجمَّعة.

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

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

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

نظرًا لاختلاف طريقة تنظيم تقنيات الإعلان على الويب و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 API عمليات ضبط اختيارية أكثر مرونة بحيث تزيد تقنيات الإعلانات من التحكّم في بنية التقارير على مستوى الحدث وتتمكّن من الاستفادة إلى أقصى حد من البيانات. سيتم طرح هذه المرونة الإضافية في Attribution Reporting API على مرحلتين:

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

المرحلة 1: مستوى الحدث المرن في 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
  }
}

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

سنضيف أيضًا مَعلمة اختيارية trigger_specs إلى JSON في Attribution-Reporting-Register-Source، فضلاً عن المَعلمات التي تمّت إضافتها في المرحلة 1.

{
  // 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 ensures 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>,
}

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

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

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

يوفّر نموذج الإعداد هذا مطوّرًا يريد معرفة ما إذا كانت إحالة ناجحة واحدة على الأقل قد حدثت في أول 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
}

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

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

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

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

يمكن لتكنولوجيا الإعلانات الاختيار من بين 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 أو العملية مع العنصر الرئيسي المشغِّل
مثال:
"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 AdTech identifier
   // bits. eg. If AdTechA's sources wins the attribution then 0x1 here will be
   // OR'd with the trigger key pieces to generate the final key piece.
    "AdTechA-enrollment_id": "0x1", // Identifier bits in hex for A
    "AdTechB-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"، يمكنك الاطّلاع على ملاحظات الإصدار.

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

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