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

Stay organized with collections Save and categorize content based on your preferences.

API Báo cáo phân bổ được thiết kế nhằm tăng cường quyền riêng tư cho 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 trên các bên, và để hỗ trợ các trường hợp sử dụng chính nhằm phân bổ và đo lường lượt chuyển đổi trên các ứng dụng. Hướng dẫn dành cho nhà phát triển này mô tả cách định cấu hình và thử nghiệm các API Báo cáo phân bổ để đăng ký lượt nhấp chuột, lượt xem và lượt chuyển đổi quảng cáo bằng cách gọi phương thức đăng ký các trình kích hoạt và nguồn 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 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 đề 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ụ của máy chủ và máy khách được liệt kê trong các phần sau.

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ị thử nghiệm 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 quảng cáo là triển khai các định nghĩa dịch vụ OpenAPIv3 từ kho lưu trữ mã mẫu của chúng tôi cho nền tảng mô phỏng hoặc microservices. 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 riêng bạn bằng cách sử dụ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 các đ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ẽ đưa ra yêu cầu và đưa vào một trong các tiêu đề sau:

  • Đố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 máy chủ của bạn để 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]",
  "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": [{
    "id": "[key name]",
    "key_piece": "[key piece value]",
  },
  ..
  ]
}

// Specify additional ad tech URLs to register this source with.
Attribution-Reporting-Redirects: <Ad tech partner URIs; comma-separated>

Dưới đây là một ví dụ với 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": "60000",
  "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".
    "id": "campaignCounts",
  // User saw an ad from campaign 345 (out of 511).
    "key_piece": "0x159",
  },
  {
  // Generates a "0x5" key piece (low order bits of the key) for the key named
  // "geoValue".
    "id": "geoValue",
  // Source-side geo region = 5 (US), out of a possible ~100 regions.
    "key_piece": "0x5",
  }]
}
Attribution-Reporting-Redirects: https://adtechpartner1.example?their_ad_click_id=567, 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]",
  "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": [{
    "id": "[key name]",
    "key_piece": "[key piece value]",
   },
   ..
  ]
}
// The Attribution-Reporting-Redirects 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 các đ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ẽ đưa ra yêu cầu và đưa vào một trong các tiêu đề sau:

Định cấu hình điểm cuối máy chủ của bạn để 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
    // different event trigger data based on source's filter_data.
    // Note: "source_type" can be used as a key to filter based on the source's
    // type "navigation" or "event".
    // The first "Event-Trigger" that matches, based on "filters" and
    // "not_filters", is used for report generation. If there are no matches,
    // no report is generated.
    "filters": {
      "[key name 1]": ["key1 value 1", "key1 value 2"],
      // If a key is missing from "filters" or the attribution source's
      // "filter_data", it isn't 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 the attribution source's
      // "filter_data", it isn't 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" and "not_filters" are optional fields, similar to the 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
  // that they're generated.
  "aggregabtable_values": [
     // Each source event can contribute a maximum of L1 = 2^16 to the aggregate
     // histogram.
    {
     "[key_name]": [value]
    },
    ..
  ]
}
// Specify additional Adtech URLs to register this trigger with.
Attribution-Reporting-Redirects: <Ad tech partner URIs, comma-separated>

Dưới đây là một ví dụ với 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": {
      "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": {
      "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"]
    },
    {
      // 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", "nonMatchingIdsListedHereAreIgnored"]
    }
  ],
  "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
    }
  ]
}
Attribution-Reporting-Redirects:https://adtechpartner.example?app_install=567

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:

// 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]",
    // "filters" and "not_filters" are optional fields which allow configuring
    // for configuring different event trigger data based on the attribution]
    // source's "filter_data". Note that "source_type" can be used as a key to
    // filter based on the source's type "navigation" or "event".
    // The first "Event-Trigger" that matches, based on "filters" and
    // "not_filters", is used for report generation. If there are no matches,
    // no report is generated.
    "filters": {
      "[key name 1]": ["key1 value 1", "key1 value 2"],
      // If a key is missing from "filters" or the attribution source's
      // "filter_data", it isn't 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 the attribution source's
      // "filter_data", it isn't 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" and "not_filters" are optional fields, similar to the 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-Redirects 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. Cho đến khi Hộp cát về quyền riêng tư trên Android hỗ trợ đăng ký URI đăng lại của riêng bạn, URI được suy ra từ eTLD+1 của máy chủ được dùng để chấp nhận đăng ký nguồn và kích hoạt đăng ký. Sử dụng URI mẫu cho các điểm cuối chấp nhận đăng ký nguồnchấp nhận đăng ký trình kích hoạt, URI của điểm cuối này là:

https://adtech.example/.well-known/attribution-reporting/report-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"
}

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. Cho đến khi Hộp cát về quyền riêng tư trên Android hỗ trợ đăng ký URI đăng lại của riêng bạn, URI được suy ra từ điểm khởi hành của máy chủ được dùng để chấp nhận đăng ký nguồn và kích hoạt đăng ký. Sử dụng URI mẫu cho các điểm cuối chấp nhận đăng ký nguồnchấp nhận đăng ký trình kích hoạt, URI của điểm cuối này là:

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

Hiện tại, cả các trường mã hoá và không mã hoá đều được điền sẵn dữ liệu cho các báo cáo phân bổ. Báo cáo được mã hoá cho phép bạn bắt đầu kiểm thử với dịch vụ tổng hợp, trong khi trường không mã hoá cung cấp thông tin chi tiết về cách thiết lập các cặp khoá-giá trị đang 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]"
}

Thiết lập ứng dụng Android

Ứng dụng khách này đăng ký các nguồn và trình kích hoạt phân bổ, đồng thời cho phép tạo báo cáo ở cấp sự kiện và tổng hợp. Để chuẩn bị một thiết bị 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 của bạn cho Hộp cát về quyền riêng tư trên Android.
  2. Cài đặt ả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 bao gồm chức năng hỗ trợ cho 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ư được minh hoạ trong đoạn mã sau:

    <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 đến 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 sẽ cần đăng ký các nguồn và lượt chuyển đổi khi chúng xuất hiện để đảm bảo chúng được 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ổtrình 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à xuất bản sẽ gọi registerSource() để đăng ký nguồn phân bổ như được hiển thị 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 thức 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 lượt nhấp. Kiểu sự kiện này cung cấp thêm thông tin về tương tác của người dùng, do đó là kiểu 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 thức gọi lại tương tự như onAdShown(). Sự kiện kích hoạt tương ứng có thể xảy ra vài giờ hoặc vài ngày sau 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 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 đă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 của công nghệ quảng cáo khác. 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.

Đăng ký một sự 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ẻ đăng ký trình 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 công nghệ quảng cáo khác. 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.

Đăng ký đ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 một vai trò trong hành trình của người dùng từ nguồn đến trình kích hoạt, sẽ có những khác biệt nhỏ trong việc triển khai đă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à chuyển đổi bởi trình duyệt web. 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 và ứ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à trình 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à chuyển các đă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 adtech.
    .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 adtech.
    .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 adtech.
    .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 adtech.
    .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 các báo cáo

API Báo cáo phân bổ gửi báo cáo tới 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 thử nghiệm, 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. Nó sẽ trông giống 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 biểu, khoảng từ vài giờ đến vài ngày. Đối với mục đích thử nghiệm, bạn có thể đặt trước thời gian hệ thống của thiết bị sau sự độ 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 gửi bằng cách kiểm tra các báo cáo đã nhận, nhật ký máy chủ hiện hành, chẳng hạn như lịch sử máy chủ mô phỏng hoặc hệ thống tuỳ chỉnh của bạn.

Thử nghiệm

Để bắt đầu sử 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ý trình kích hoạt.

Đối với điểm cuối 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 bao gồm 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 dịch vụ vi mô được hỗ trợ).
  • MeasurementAdTechServer bao gồm cách triển khai 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 từ thiết bị thử nghiệm hoặc trình mô phỏng. Để dễ dàng thử nghiệm, 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à trình 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ác lệnh báo cáo.
  • Xác minh việc gửi các 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ủ thử nghiệm.

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

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

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

Phản hồi của bạn có vai trò quan trọng trong 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 bất ổn hoặc ý tưởng để cải thiện Hộp cát về quyền riêng tư trên Android.