FLEDGE hiện là Đối tượng được bảo vệ. Tìm hiểu thêm!

Hướng dẫn dành cho nhà phát triển về API Báo cáo phân bổ

Khi bạn đọc tài liệu Hộp cát về quyền riêng tư trên Android, hãy sử dụng nút Bản dùng thử cho nhà phát triển hoặc Beta để chọn phiên bản chương trình bạn đang làm việc, vì hướng dẫn có thể khác nhau.


Gửi ý kiến phản hồi

API Báo cáo phân bổ được thiết kế nhằm tăng cường quyền riêng tư của người dùng, thông qua việc loại bỏ sự phụ thuộc vào giá trị nhận dạng người dùng giữa nhiều bên, đồng thời hỗ trợ các trường hợp sử dụng chính để phân bổ và đo lường lượt chuyển đổi trên các ứng dụng. Hướng dẫn cho nhà phát triển này mô tả cách định cấu hình và kiểm thử các API Báo cáo phân bổ để đăng ký lượt nhấp, lượt xem và lượt chuyển đổi quảng cáo bằng các phương thức gọi giúp đăng ký điều kiện kích hoạt và nguồn có liên quan cho các sự kiện đó.

Hướng dẫn này sẽ chỉ cho bạn cách thiết lập điểm cuối của máy chủ và xây dựng một ứng dụng khách để gọi các dịch vụ này. Tìm hiểu thêm về thiết kế tổng thể của API Báo cáo phân bổ trong phần đề xuất thiết kế.

Từ khoá

  • Nguồn phân bổ đề cập đến số lượt nhấp hoặc số lượt xem.
  • Trình kích hoạt là các sự kiện có thể phân bổ cho các lượt chuyển đổi.
  • Báo cáo chứa dữ liệu về một trình kích hoạt và nguồn phân bổ tương ứng. Các báo cáo này được gửi để phản hồi lại các sự kiện kích hoạt. API Báo cáo phân bổ hỗ trợ các báo cáo cấp sự kiệnbáo cáo tổng hợp.

Trước khi bắt đầu

Để sử dụng API Báo cáo phân bổ, hãy hoàn thành các tác vụ phía máy chủ và phía máy khách được liệt kê trong những phần sau đây.

Thiết lập điểm cuối của API Báo cáo phân bổ

API Báo cáo phân bổ yêu cầu một tập hợp các điểm cuối mà bạn có thể truy cập từ một thiết bị kiểm thử hoặc trình mô phỏng. Tạo một điểm cuối cho mỗi thao tác phía máy chủ sau đây:

Có một số phương pháp để thiết lập các điểm cuối bắt buộc:

  • Cách nhanh nhất để thiết lập và chạy đó là triển khai các định nghĩa dịch vụ OpenAPI phiên bản 3 trong kho lưu trữ mã mẫu của chúng tôi cho nền tảng mô phỏng hoặc nền tảng vi dịch vụ. Bạn có thể sử dụng Postman, Prism hoặc bất kỳ nền tảng máy chủ mô phỏng nào khác chấp nhận định dạng này. Triển khai từng điểm cuối và theo dõi các URI để dùng trong ứng dụng của bạn. Để xác minh việc phân phối báo cáo, hãy tham khảo các lệnh gọi đã thực hiện trước đó đến nền tảng mô phỏng hoặc nền tảng không máy chủ.
  • Chạy máy chủ độc lập của bạn bằng mẫu Kotlin dựa trên Spring Boot. Triển khai máy chủ này trên nhà cung cấp dịch vụ đám mây hoặc cơ sở hạ tầng có trong máy của bạn.
  • Sử dụng định nghĩa dịch vụ làm ví dụ để tích hợp điểm cuối vào hệ thống hiện tại của bạn.

Chấp nhận đăng ký nguồn

Có thể xác định điểm cuối này từ một URI tương tự như sau:

https://adtech.example/attribution_source

Khi ứng dụng khách đăng ký một nguồn phân bổ, ứng dụng đó sẽ cung cấp URI cho điểm cuối của máy chủ này. Sau đó, API Báo cáo phân bổ sẽ gửi yêu cầu và dùng một trong các tiêu đề sau đây:

  • Đối với sự kiện nhấp chuột:

    Attribution-Reporting-Source-Info: navigation
    
  • Đối với sự kiện xem:

    Attribution-Reporting-Source-Info: event
    

Định cấu hình điểm cuối của máy chủ để phản hồi những nội dung sau:

// 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]"
}
// 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>

Dưới đây là một ví dụ về các giá trị mẫu được thêm vào:

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"
  }
}
Attribution-Reporting-Redirect:
https://adtechpartner1.example?their_ad_click_id=567
Attribution-Reporting-Redirect:
https://adtechpartner2.example?their_ad_click_id=890

Nếu Attribution-Reporting-Redirects chứa URI của các đối tác công nghệ quảng cáo, thì API báo cáo phân bổ sẽ thực hiện một yêu cầu tương tự cho từng URI. Mỗi đối tác công nghệ quảng cáo phải định cấu hình một máy chủ phản hồi bằng các tiêu đề sau:

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.

Chấp nhận đăng ký trình kích hoạt chuyển đổi

Có thể xác định điểm cuối này từ một URI tương tự như sau:

https://adtech.example/attribution_trigger

Khi một ứng dụng khách đăng ký một sự kiện kích hoạt, ứng dụng đó sẽ cung cấp URI cho điểm cuối của máy chủ này. Sau đó, API Báo cáo phân bổ sẽ gửi yêu cầu và dùng một trong các tiêu đề sau đây:

Định cấu hình điểm cuối của máy chủ để phản hồi những nội dung sau:

// 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.
  "aggregabtable_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.
  "aggregabtable_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]"

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

Dưới đây là một ví dụ về các giá trị mẫu được thêm vào:

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]
        }
    }
  ]
}
Attribution-Reporting-Redirect:https://adtechpartner.example?app_install=567

Tồn tại giới hạn 25 byte cho mỗi mã nhận dạng khoá tổng hợp và chuỗi bộ lọc. Điều này có nghĩa là mã nhận dạng khoá tổng hợp và chuỗi bộ lọc không được vượt quá 25 ký tự. Trong ví dụ này, campaignCounts có 14 ký tự nên đây là một mã nhận dạng khoá tổng hợp hợp lệ và 1234 có 4 ký tự nên đây là một chuỗi bộ lọc hợp lệ. Nếu mã nhận dạng khoá tổng hợp hoặc chuỗi bộ lọc vượt quá 25 ký tự, thì điều kiện kích hoạt sẽ bị bỏ qua.

Nếu Attribution-Reporting-Redirect chứa URI của các đối tác công nghệ quảng cáo, thì API Báo cáo phân bổ sẽ gửi một yêu cầu tương tự đến từng URI. Mỗi đối tác công nghệ quảng cáo phải định cấu hình một máy chủ phản hồi bằng các tiêu đề sau:

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

Chấp nhận báo cáo ở cấp sự kiện

Phải xác định được điểm cuối này từ URI. Hãy xem bài viết Đăng ký tài khoản Hộp cát về quyền riêng tư để biết thêm thông tin về cách đăng ký URI. (URI được suy ra từ eTLD+1 của máy chủ dùng để chấp nhận hoạt động đăng ký nguồn và đăng ký điều kiện kích hoạt). Sử dụng URI mẫu cho các điểm cuối chấp nhận hoạt động đăng ký nguồnchấp nhận hoạt động đăng ký điều kiện kích hoạt, URI của điểm cuối này là:

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

Định cấu hình máy chủ này để chấp nhận các yêu cầu JSON sử dụng định dạng sau:

{
  "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]",
}

Với khoá gỡ lỗi, bạn có thể xem thêm thông tin chi tiết về các báo cáo phân bổ; hãy tìm hiểu thêm về cách định cấu hình những khoá này.

Chấp nhận báo cáo tổng hợp

Phải xác định được điểm cuối này từ URI. Hãy xem bài viết Đăng ký tài khoản Hộp cát về quyền riêng tư để biết thêm thông tin về cách đăng ký URI. (URI được suy ra từ nguồn gốc của máy chủ được dùng để chấp nhận hoạt động đăng ký nguồn và đăng ký điều kiện kích hoạt). Sử dụng URI mẫu cho các điểm cuối chấp nhận hoạt động đăng ký nguồnchấp nhận hoạt động đăng ký điều kiện kích hoạt, URI của điểm cuối này là:

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

Cả những trường đã mã hoá và chưa mã hoá đều được điền sẵn dữ liệu cho các báo cáo tổng hợp. Với báo cáo đã mã hoá, bạn có thể bắt đầu kiểm thử bằng dịch vụ tổng hợp, còn trường chưa mã hoá cung cấp thông tin chi tiết về cách các cặp giá trị/khoá đã đặt đang xây dựng cấu trúc dữ liệu.

Định cấu hình máy chủ này để chấp nhận các yêu cầu JSON sử dụng định dạng sau:

{
  // 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]"
}

Với khoá gỡ lỗi, bạn có thể xem thêm thông tin chi tiết về các báo cáo phân bổ; hãy tìm hiểu thêm về cách định cấu hình những khoá này.

Thiết lập ứng dụng khách Android

Ứng dụng khách này đăng ký các nguồn và điều kiện kích hoạt phân bổ, đồng thời giúp tạo báo cáo cấp sự kiện và báo cáo tổng hợp. Để chuẩn bị một thiết bị khách hoặc trình mô phỏng cho ứng dụng Android nhằm sử dụng API Báo cáo phân bổ, hãy làm như sau:

  1. Thiết lập môi trường phát triển cho Hộp cát về quyền riêng tư trên Android.
  2. Cài đặt hình ảnh hệ thống trên một thiết bị được hỗ trợ hoặc thiết lập một trình mô phỏng có hỗ trợ Hộp cát về quyền riêng tư trên Android.
  3. Cấp quyền truy cập vào API Báo cáo phân bổ bằng cách chạy lệnh ADB sau đây. (Theo mặc định, API bị tắt.)

    adb shell device_config put adservices ppapi_app_allow_list \"*\"
    
  4. Cung cấp quyền ACCESS_ADSERVICES_ATTRIBUTION và tạo cấu hình dịch vụ quảng cáo cho ứng dụng của bạn để sử dụng các API Báo cáo phân bổ, như minh hoạ trong đoạn mã sau đây:

    <uses-permission android:name="android.permission.ACCESS_ADSERVICES_ATTRIBUTION" />
    
  5. Chỉ định tài nguyên XML của dịch vụ quảng cáo được tham chiếu trong tệp kê khai, chẳng hạn như res/xml/ad_services_config.xml. Hãy tìm hiểu thêm về việc kiểm soát quyền truy cập vào SDK và dịch vụ quảng cáo.

    <property android:name="android.adservices.AD_SERVICES_CONFIG"
          android:resource="@xml/ad_services_config" />
    
  6. Tham chiếu một cấu hình dịch vụ quảng cáo trong phần tử <application> của tệp kê khai:

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

Đăng ký sự kiện quảng cáo

Ứng dụng của bạn phải đăng ký các nguồn và lượt chuyển đổi khi những nguồn và lượt chuyển đổi này xuất hiện để đảm bảo báo cáo chính xác. Lớp MeasurementManager có các phương thức giúp bạn đăng ký sự kiện nguồn phân bổđiều kiện kích hoạt chuyển đổi.

Đăng ký một sự kiện nguồn phân bổ

Khi người dùng xem hoặc nhấp vào quảng cáo, ứng dụng của nhà phát hành sẽ gọi registerSource() để đăng ký nguồn phân bổ, như minh hoạ trong đoạn mã.

API Báo cáo phân bổ hỗ trợ các loại sự kiện nguồn phân bổ sau đây:

  • Lượt nhấp mà bạn thường đăng ký trong phương pháp gọi lại tương tự như onClick(). Sự kiện kích hoạt tương ứng thường xảy ra ngay sau sự kiện nhấp chuột. Loại sự kiện này cung cấp thêm thông tin về hoạt động tương tác của người dùng, do đó, đây là loại nguồn phân bổ tốt để có mức độ ưu tiên cao.
  • Lượt xem mà bạn thường đăng ký trong phương pháp gọi lại tương tự như onAdShown(). Sự kiện kích hoạt tương ứng có thể xảy ra sau vài giờ hoặc vài ngày kể từ sự kiện xem.

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

Sau khi đăng ký, API sẽ gửi một yêu cầu POST qua HTTP tới điểm cuối của dịch vụ tại địa chỉ do attributionSourceUri chỉ định. Phản hồi của điểm cuối bao gồm các giá trị cho destination, source_event_id, expirysource_priority.

Nếu công nghệ quảng cáo ban đầu muốn chia sẻ các lượt đăng ký nguồn, thì URI nguồn phân bổ ban đầu có thể bao gồm các lệnh chuyển hướng đến điểm cuối khác của công nghệ quảng cáo. Giới hạn và quy tắc áp dụng cho các lệnh chuyển hướng sẽ được nêu chi tiết trong đề xuất kỹ thuật.

Chúng tôi đã thêm tính năng hỗ trợ cho các lần chuyển hướng chuỗi kết nối cho registerSourceregisterTrigger. Ngoài tiêu đề đăng ký, giờ đây, người dùng API có thể cung cấp lệnh chuyển hướng HTTP dưới dạng phản hồi của máy chủ. Lệnh chuyển hướng này bao gồm mã trạng thái 302 và tiêu đề "Vị trí" có URL tiếp theo cần truy cập để đăng ký bổ sung.

Hiện tại, chỉ có trường "destination" (đích đến) đã cung cấp trong lượt truy cập đầu tiên là được dùng trên chuỗi kết nối. Số lượt truy cập có cùng giới hạn với tiêu đề "Attribution-Reporting-Redirect" (Chuyển hướng báo cáo phân bổ). Tính năng hỗ trợ chuyển hướng này bổ sung cho tính năng hỗ trợ "Attribution-Reporting-Redirect" hiện có và nếu có cả hai, tính năng "Attribution-Reporting-Redirect" sẽ được ưu tiên.

Đăng ký một sự kiện cho điều kiện kích hoạt lượt chuyển đổi

Để đăng ký một sự kiện kích hoạt lượt chuyển đổi, hãy gọi registerTrigger() trong ứng dụng của bạn:

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)

Sau khi đăng ký, API sẽ gửi một yêu cầu POST HTTP tới điểm cuối của dịch vụ tại địa chỉ do attributionTriggerUri chỉ định. Phản hồi của điểm cuối bao gồm các giá trị cho báo cáo sự kiện và báo cáo tổng hợp.

Nếu nền tảng công nghệ quảng cáo ban đầu cho phép chia sẻ lượt đăng ký điều kiện kích hoạt, URI có thể bao gồm các lệnh chuyển hướng đến URI thuộc nền tảng khác của công nghệ quảng cáo. Giới hạn và quy tắc áp dụng cho các lệnh chuyển hướng được nêu chi tiết trong đề xuất kỹ thuật.

Đăng ký hoạt động đo lường trên nhiều ứng dụng và web

Trong trường hợp cả ứng dụng và trình duyệt đều đóng vai trò trong hành trình của người dùng từ nguồn đến điều kiện kích hoạt, sẽ có những khác biệt nhỏ khi triển khai hoạt động đăng ký sự kiện quảng cáo. Nếu người dùng nhìn thấy một quảng cáo trên ứng dụng và được chuyển hướng đến trình duyệt để chuyển đổi, thì nguồn sẽ được ứng dụng đăng ký và lượt chuyển đổi sẽ được trình duyệt web đăng ký. Tương tự, nếu người dùng khởi động trên trình duyệt web và được chuyển đến một ứng dụng để chuyển đổi, thì trình duyệt sẽ đăng ký nguồn, còn ứng dụng đó sẽ đăng ký lượt chuyển đổi.

Vì có sự khác biệt về cách sắp xếp công nghệ quảng cáo trên web và trên Android, chúng tôi đã thêm các API mới để đăng ký nguồn và điều kiện kích hoạt khi chúng diễn ra trên trình duyệt. Điểm khác biệt chính giữa các API này và các API dựa trên ứng dụng tương ứng là chúng tôi mong muốn trình duyệt tuân theo các lệnh chuyển hướng, áp dụng bất kỳ bộ lọc nào dành riêng cho trình duyệt và truyền các lượt đăng ký hợp lệ cho nền tảng bằng cách gọi registerWebSource() hoặc registerWebTrigger().

Đoạn mã sau đây cho thấy ví dụ về lệnh gọi API mà trình duyệt thực hiện để đăng ký nguồn phân bổ trước khi chuyển người dùng đến ứng dụng:

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

Đoạn mã sau đây cho thấy ví dụ về lệnh gọi API mà trình duyệt thực hiện để đăng ký lượt chuyển đổi sau khi người dùng được chuyển từ ứng dụng:

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

Tạo và phân phối báo cáo

API Báo cáo phân bổ gửi báo cáo đến các điểm cuối trên máy chủ của bạn để chấp nhận báo cáo cấp sự kiệnbáo cáo tổng hợp.

Buộc báo cáo các công việc cần chạy

Sau khi bạn đăng ký một sự kiện nguồn phân bổ hoặc đăng ký một sự kiện kích hoạt, hệ thống sẽ lên lịch chạy công việc báo cáo. Theo mặc định, công việc này sẽ chạy 4 giờ một lần. Đối với mục đích kiểm thử, bạn có thể buộc các công việc báo cáo chạy hoặc rút ngắn khoảng thời gian giữa các công việc.

Buộc thực hiện công việc phân bổ:

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

Buộc chạy công việc báo cáo ở cấp sự kiện:

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

Buộc thực hiện công việc báo cáo tổng hợp:

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

Kiểm tra đầu ra trong logcat để xem thời điểm các công việc đã thực hiện. Quy trình này sẽ diễn ra như sau:

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

Buộc phân phối các báo cáo

Ngay cả khi công việc báo cáo buộc phải chạy, hệ thống vẫn gửi báo cáo theo thời gian phân phối theo lịch, khoảng từ vài giờ đến vài ngày. Đối với mục đích kiểm thử, bạn có thể đặt trước thời gian hệ thống của thiết bị sau độ trễ đã lên lịch để bắt đầu gửi báo cáo.

Xác minh các báo cáo trên máy chủ của bạn

Sau khi báo cáo được gửi, hãy xác minh việc phân phối bằng cách kiểm tra các báo cáo đã nhận, nhật ký máy chủ có liên quan (chẳng hạn như nhật ký của máy chủ mô phỏng) hoặc hệ thống tuỳ chỉnh của bạn.

Giải mã báo cáo tổng hợp

Khi nhận được một báo cáo tổng hợp, trường debug_cleartext_payload sẽ lưu giữ phiên bản không mã hoá của báo cáo tổng hợp đó. Mặc dù phiên bản báo cáo này không được mã hoá, nhưng bạn vẫn cần giải mã phiên bản đó.

Dưới đây là ví dụ về cách giải mã nội dung của trường debug_cleartext_payload theo hai bước: bước đầu tiên sử dụng phương thức giải mã Base 64 và bước thứ hai sử dụng phương thức giải mã 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);
});

Kiểm thử

Để bắt đầu dùng API Báo cáo phân bổ, bạn có thể sử dụng dự án MeasurementSampleApp trên GitHub. Ứng dụng mẫu này minh hoạ việc đăng ký nguồn phân bổ và đăng ký điều kiện kích hoạt.

Đối với điểm cuối của máy chủ, hãy xem xét các tài nguyên tham chiếu sau đây hoặc giải pháp tuỳ chỉnh của bạn:

  • MeasurementAdTechServerSpec cung cấp các định nghĩa dịch vụ OpenAPI, có thể triển khai cho các nền tảng mô phỏng hoặc nền tảng dịch vụ vi mô được hỗ trợ.
  • MeasurementAdTechServer cung cấp cách triển khai tham chiếu đối với một máy chủ mô phỏng dựa trên ứng dụng Spring Boot dành cho Google App Engine.

Điều kiện tiên quyết

Triển khai API mô phỏng trên các điểm cuối từ xa có thể truy cập được từ thiết bị kiểm thử hoặc trình mô phỏng. Để dễ dàng kiểm thử, hãy tham khảo các dự án mẫu MeasurementAdTechServerSpecMeasurementAdTechServer.

Hàm để thử nghiệm

  • Thực hiện đăng ký nguồn phân bổ và điều kiện kích hoạt chuyển đổi. Kiểm tra để đảm bảo điểm cuối của phía máy chủ phản hồi bằng định dạng chính xác.
  • Thực thi công việc báo cáo.
  • Xác minh việc phân phối báo cáo trên bảng điều khiển hoặc chương trình phụ trợ của máy chủ kiểm thử.

Các tính năng sắp có

Phân bổ trên nhiều mạng mà không cần chuyển hướng

Công nghệ quảng cáo nên sử dụng lệnh chuyển hướng để đăng ký nhiều điều kiện kích hoạt nguồn phân bổ và để thực hiện hoạt động phân bổ trên nhiều mạng. Tính năng này giúp hỗ trợ hoạt động phân bổ trên nhiều mạng, trong đó việc chuyển hướng là không khả thi trên các mạng. Tìm hiểu thêm.

Công nghệ quảng cáo có thể gửi cấu hình trong phản hồi đăng ký điều kiện kích hoạt dựa trên những nguồn được đăng ký bởi các công nghệ quảng cáo khác được chọn để tạo nguồn phái sinh; sau đó, các nguồn phái sinh này sẽ được dùng cho hoạt động phân bổ. Hệ thống sẽ tạo báo cáo tổng hợp nếu điều kiện kích hoạt được phân bổ đến một nguồn phái sinh. Hệ thống không hỗ trợ việc tạo báo cáo sự kiện cho các nguồn phái sinh.

Các công nghệ quảng cáo có thể chọn trong số aggregation_keys trên các nguồn đã đăng ký mà họ dự định chia sẻ với công nghệ quảng cáo của đối tác. Bạn có thể khai báo các khoá này trong trường shared_aggregation_keys không bắt buộc, nằm trong tiêu đề đăng ký nguồn Attribution-Reporting-Register-Source:

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

Các nguồn phái sinh được tạo dựa trên cấu hình trong tiêu đề đăng ký điều kiện kích hoạt 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]"
    }
  ]

Dưới đây là phiên bản đã thêm giá trị mẫu:

  "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"
    }
  ]

2 trường mới (không bắt buộc) được thêm vào để kích hoạt tiêu đề đăng ký. Các trường này hỗ trợ giá trị nhận dạng của công nghệ quảng cáo chiến thắng trong các khoá của báo cáo tổng hợp:

  • x_network_bit_mapping: Mã đăng ký đến liên kết dạng bit của mã nhận dạng công nghệ quảng cáo
  • x_network_data: Mức chênh lệch (di chuyển sang trái) cho thao tác OR x_network_bit_mapping của công nghệ quảng cáo chiến thắng có phần khoá điều kiện kích hoạt
Ví dụ:
"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
  }
  …
}

Dưới đây là kết quả tính toán phần khoá của điều kiện kích hoạt khi tạo báo cáo cho nguồn của AdTechB:

  • key_piece: 0x400 (010000000000)
  • key_offset: 12
  • Giá trị enrollment_id của AdtechB: 2 (010) (từ x_network_bit_mapping)
  • Phần khoá của điều kiện kích hoạt kết quả: 0x400 | 0x2 << 12 = 0x2400

Các điểm hạn chế

Để biết danh sách các tính năng đang tiến hành cho SDK Thời gian chạy, vui lòng xem ghi chú phát hành.

Báo cáo lỗi và vấn đề

Ý kiến phản hồi của bạn đóng vai trò quan trọng đối với Hộp cát về quyền riêng tư trên Android! Vui lòng cho chúng tôi biết bất kỳ vấn đề nào hoặc ý tưởng để cải thiện Hộp cát về quyền riêng tư trên Android.