Przewodnik dla programistów interfejsu Attribution Reporting API

Podczas czytania dokumentacji dotyczącej Piaskownicy prywatności na Androida użyj przycisku Podgląd dla deweloperów lub Beta, aby wybrać wersję programu, z którą pracujesz, ponieważ instrukcje mogą się różnić.


Interfejs Attribution Reporting API ma zapewniać lepszą ochronę prywatności użytkowników wyeliminowanie polegania na identyfikatorach użytkowników w różnych firmach i kluczowych przypadków użycia. do atrybucji i pomiaru konwersji w aplikacjach. Ten przewodnik dla deweloperów opisuje, jak skonfigurować i testować interfejsy Attribution Reporting API, aby rejestrować kliknięcia reklam, wyświetlenia i konwersje przez wywoływanie metod rejestrujących odpowiednie reguły i źródła dla takich zdarzeń.

Z tego przewodnika dowiesz się, jak skonfigurować punkty końcowe serwera i utworzyć aplikację klienta, która wywołuje te usługi. Więcej informacji o ogólnej strukturze interfejsu Attribution Reporting API znajdziesz w propozycji dotyczącej projektu.

Hasła kluczowe

  • Źródła atrybucji odnoszą się do kliknięć lub wyświetleń.
  • Reguły to zdarzenia, które można przypisać do konwersji.
  • Raporty zawierają dane o regułach i odpowiadających im atrybucjach źródła. Raporty są wysyłane w odpowiedzi na zdarzenia wywołujące. Interfejs Attribution Reporting API obsługuje raporty na poziomie zdarzenia oraz raportów zbiorczych.

Zanim zaczniesz

Aby korzystać z interfejsu Attribution Reporting API, wykonaj zadania po stronie serwera i klienta wymienione w następnych sekcjach.

Konfigurowanie punktów końcowych interfejsu Attribution Reporting API

Interfejs Attribution Reporting API wymaga zestawu punktów końcowych, do których masz dostęp z urządzenia testowego lub emulatora. Utwórz po 1 punkcie końcowym dla każdej z tych zadań po stronie serwera:

Wymagane punkty końcowe można skonfigurować na kilka sposobów:

  • Najszybszym sposobem na rozpoczęcie pracy jest wdrożenie definicji usług OpenAPI v3 z naszego repozytorium przykładowego kodu na platformie mock lub mikrousług. Możesz użyć Postmana, Prisma lub innej platformy z symulowanym serwerem, która obsługuje ten format. Wdrożyć każdy punkt końcowy i śledzić URI do użycia w aplikacji. Aby sprawdzić dostarczenie raportu, sprawdź wywołania wykonane wcześniej do platformy mock lub bez serwera.
  • Uruchom własny serwer samodzielny, korzystając z przykładowego kodu Kotlin opartego na Spring Boot. Wdróż ten serwer u dostawcy usług w chmurze lub w wewnętrznej infrastrukturze.
  • Użyj definicji usług jako przykładów, aby zintegrować punkty końcowe z istniejącego systemu.
.

Akceptowanie rejestracji źródła

Ten punkt końcowy powinien być adresowany z użyciem identyfikatora URI podobnego do tego:

https://adtech.example/attribution_source

Gdy aplikacja kliencka rejestruje źródło atrybucji, podaje identyfikator URI dla: tego punktu końcowego serwera. Interfejs Attribution Reporting API wysyła następnie żądanie, zawiera jeden z następujących nagłówków:

  • W przypadku zdarzeń kliknięcia:

    Attribution-Reporting-Source-Info: navigation
    
  • W przypadku zdarzeń wyświetlania:

    Attribution-Reporting-Source-Info: event
    

Skonfiguruj punkt końcowy serwera tak, aby odpowiadał w ten sposób:

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

Oto przykład z dodanymi przykładowymi wartościami:

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

Jeśli Attribution-Reporting-Redirects zawiera identyfikatory URI partnerów oferujących technologie reklamowe, w parametrze Interfejs Attribution Reporting API wysyła następnie żądanie podobne do każdego identyfikatora URI. Każda technologia reklamowa partner musi skonfigurować serwer, który odpowiada przy użyciu tych nagłówków:

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.

Zaakceptuj rejestrację reguły konwersji

Ten punkt końcowy powinien być adresowany z użyciem identyfikatora URI podobnego do tego:

https://adtech.example/attribution_trigger

Gdy aplikacja kliencka rejestruje zdarzenie aktywujące, udostępnia identyfikator URI obiektu punktu końcowego serwera. Interfejs Attribution Reporting API wysyła żądanie, dodając jeden z tych nagłówków:

Skonfiguruj punkt końcowy serwera tak, aby odpowiadał w ten sposób:

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

Oto przykład z dodanymi przykładowymi wartościami:

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

Obowiązuje limit 25 bajtów na identyfikator klucza agregacji i ciąg filtra. Ten oznacza, że identyfikatory kluczy agregacji i ciągi filtrów nie powinny przekraczać 25 znaków. W tym przykładzie ciąg campaignCounts ma 14 znaków, więc jest prawidłowym identyfikatorem klucza agregacji, a ciąg 1234 ma 4 znaki, więc jest prawidłowym ciągiem filtra. Jeśli identyfikator klucza agregacji lub ciąg filtra przekracza 25 znaków, aktywatorem jest zignorowano.

Jeśli Attribution-Reporting-Redirect zawiera identyfikatory URI partnerów oferujących technologie reklamowe, w parametrze Interfejs Attribution Reporting API wysyła następnie żądanie podobne do każdego identyfikatora URI. Każdy partner technologiczny reklam musi skonfigurować serwer, który odpowiada tymi nagłówkami:

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

Akceptowanie raportów na poziomie zdarzenia

Ten punkt końcowy powinien być adresowalny za pomocą identyfikatora URI. Zapoznaj się z sekcją Rejestracja w programie ochrony prywatności Konto w trybie piaskownicy, w którym znajdziesz więcej informacji o rejestrowaniu identyfikatorów URI. (Identyfikator URI to wywnioskowane na podstawie pochodzenia serwerów używanych do akceptowania rejestracji źródła oraz proces rejestracji). Przykładowe identyfikatory URI punktów końcowych, które akceptują rejestrację źródeł i akceptują rejestrację wyzwalaczy:

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

Skonfiguruj ten serwer tak, aby akceptował żądania JSON w tym formacie:

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

Klucze debugowania umożliwiają uzyskanie dodatkowych statystyk w raportach atrybucji. Dowiedz się więcej o ich konfigurowaniu.

Akceptowanie raportów zbiorczych

Ten punkt końcowy powinien być adresowalny za pomocą identyfikatora URI. Zapoznaj się z sekcją Rejestracja w programie ochrony prywatności Konto w piaskownicy, gdzie znajdziesz więcej informacji o rejestrowaniu identyfikatorów URI. (Identyfikator URI jest wywnioskowany na podstawie pochodzenia serwerów używanych do akceptowania rejestracji źródła i wyzwalania rejestracji). Używanie przykładowych identyfikatorów URI punktów końcowych, które akceptują źródło rejestracja i zaakceptuj rejestrację aktywatora, identyfikator URI tego punktu końcowego to:

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

W przypadku raportów umożliwiających agregację wypełniane są zarówno pola zaszyfrowane, jak i niezaszyfrowane. Zaszyfrowane raporty umożliwiają rozpoczęcie testowania za pomocą usługi agregacji, a niezaszyfrowane pole zapewnia informacje o sposobie, w jaki zestawy par klucz-wartość strukturyzują dane.

Skonfiguruj ten serwer tak, aby akceptował żądania JSON o tym formacie:

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

Klucze debugowania umożliwiają uzyskanie dodatkowych statystyk w raportach atrybucji. Dowiedz się więcej o ich konfigurowaniu.

Skonfiguruj klienta Androida

Aplikacja kliencka rejestruje źródła i reguły atrybucji oraz umożliwia na poziomie zdarzenia i generowania raportów agregowanych. Aby przygotować klienta Androida urządzenia lub emulatora do korzystania z interfejsu Attribution Reporting API, wykonaj te czynności:

  1. Skonfiguruj środowisko programistyczne na potrzeby Piaskownicy prywatności na na urządzeniu z Androidem.
  2. Zainstaluj obraz systemu na obsługiwanym urządzeniu lub skonfiguruj emulator, który obsługuje Piaskownicę prywatności na Androidzie.
  3. Włącz dostęp do interfejsu Attribution Reporting API, uruchamiając polecenie za pomocą polecenia ADB. (domyślnie jest on wyłączony).

    adb shell device_config put adservices ppapi_app_allow_list \"\*\"
  4. Jeśli testujesz lokalnie interfejs Attribution Reporting API (np. na urządzeniu, do którego masz fizyczny dostęp), uruchom to polecenie, aby wyłączyć rejestrację:

    adb shell device_config put adservices disable_measurement_enrollment_check "true"
  5. W pliku manifestu Androida dodaj uprawnienie ACCESS_ADSERVICES_ATTRIBUTIONutwórz konfigurację usług reklamowych, aby aplikacja mogła korzystać z interfejsów Attribution Reporting API:

    <uses-permission android:name="android.permission.ACCESS_ADSERVICES_ATTRIBUTION" />
    
  6. (Opcjonalnie) Jeśli planujesz otrzymywać raporty na temat debugowania, dołącz Uprawnienie ACCESS_ADSERVICES_AD_ID w pliku manifestu Androida:

    <uses-permission android:name="android.permission.ACCESS_ADSERVICES_AD_ID" />
    
  7. Odwołuj się do konfiguracji usług reklamowych w elemencie <application> w pliku manifestu:

    <property android:name="android.adservices.AD_SERVICES_CONFIG"
              android:resource="@xml/ad_services_config" />
    
  8. Określ zasób XML usług reklamowych, do którego odwołuje się plik manifestu, np. res/xml/ad_services_config.xml Więcej informacji o uprawnieniach do usług reklamowych i kontroli dostępu do pakietów SDK.

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

Rejestrowanie zdarzeń reklamowych

Aby mieć pewność, że źródła i konwersje są prawidłowo raportowane, aplikacja powinna rejestrować je w miarę ich występowania. Klasa MeasurementManager zawiera metody, które ułatwiają rejestrowanie źródeł atrybucjiwyzwań konwersji.

Rejestrowanie zdarzenia źródła atrybucji

Gdy użytkownik wyświetla lub klika reklamę, aplikacja wydawcy wywołuje funkcję registerSource(), aby zarejestrować źródło atrybucji zgodnie z fragmentem kodu.

Interfejs Attribution Reporting API obsługuje te typy źródeł atrybucji wydarzenia:

  • kliknięcia, które zwykle rejestrujesz w ramach metody wywołania zwrotnego podobnej do onClick() Odpowiednie zdarzenie aktywujące występuje zwykle wkrótce po zdarzeniu kliknięcia. Ten typ zdarzenia dostarcza więcej informacji o użytkowniku jest więc dobrym źródłem atrybucji, o wysokim priorytecie.
  • Wyświetlenia, które zwykle rejestrujesz w ramach metody wywołania zwrotnego podobnej do onAdShown(). Odpowiednie zdarzenie aktywatora może wystąpić po kilku godzinach lub dniach od zdarzenia wyświetlenia.

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

Po rejestracji interfejs API wysyła żądanie HTTP POST do punktu końcowego usługi pod adresem określonym przez attributionSourceUri. Parametr punktu końcowego odpowiedź zawiera wartości dla destination, source_event_id, expiry oraz source_priority

Jeśli dostawca technologii reklamowej, który pierwotnie zarejestrował źródło, chce udostępnić rejestracje źródła, pierwotny identyfikator URI źródła atrybucji może zawierać przekierowania do innych punktów końcowych dostawcy technologii reklamowej. Limity i reguły dotyczące przekierowań są opisane w propozycji technicznej.

Dodaliśmy obsługę łańcuchowych przekierowań w przypadku registerSourceregisterTrigger. Oprócz nagłówka rejestracji użytkownik interfejsu API może teraz przesłać przekierowanie HTTP jako odpowiedź serwera, która zawiera kod stanu 302 i nagłówek „Location” z adresem URL, który należy odwiedzić, aby dokonać dodatkowej rejestracji.

W całym łańcuchu daisy-chain używane jest tylko pole „destination” (miejsce docelowe) podane podczas pierwszej wizyty. Liczba wizyt ma ten sam limit co nagłówki „Attribution-Reporting-Redirect”. Obsługa przekierowań jest dodatkiem do dotychczasowej obsługi „Attribution-Reporting-Redirect”. Jeśli obie są obecne, pierwszeństwo ma „Attribution-Reporting-Redirect”.

Rejestrowanie zdarzenia reguły konwersji

Aby zarejestrować zdarzenie wyzwalające konwersję, wywołaj funkcję registerTrigger() w aplikacji:

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)

Po rejestracji interfejs API wysyła żądanie HTTP POST do punktu końcowego usługi pod adresem określonym przez attributionTriggerUri. Odpowiedź punktu końcowego zawiera wartości na potrzeby raportów zbiorczych i zdarzeń.

Jeśli platforma adtech, z której pochodzą dane, umożliwia udostępnianie rejestracji zdarzeń, adres URI może zawierać przekierowania do adresów URI należących do innych platform adtech. Limity i zasady dotyczące przekierowań są opisane w propozycji technicznej.

Rejestrowanie pomiarów w różnych aplikacjach i witrynach

W przypadku, gdy aplikacja i przeglądarka odgrywają rolę w na ścieżce od źródła do aktywacji, istnieją nieznaczne różnice implementacji rejestrowania zdarzeń reklamowych. Jeśli użytkownik zobaczy reklamę w aplikacji i przekierowany do przeglądarki w celu dokonania konwersji, źródło jest rejestrowane przez aplikację, a konwersja w przeglądarce. Podobnie, jeśli użytkownik rozpoczyna korzystanie z usługi w przeglądarce, a następnie jest przekierowywany do aplikacji, w której dokonuje konwersji, przeglądarka rejestruje źródło, a aplikacja – konwersję.

Ze względu na różnice w sposobie, w jaki technologie reklamowe są zorganizowane w sieci i w internecie, na Androida, dodaliśmy nowe interfejsy API do rejestrowania źródeł i aktywatorów, nie w przeglądarce. Główna różnica między tymi interfejsami API a odpowiednimi interfejsami API opartymi na aplikacji polega na tym, że oczekujemy, że przeglądarka będzie podążać za przekierowaniami, stosować filtry specyficzne dla przeglądarki i przekazywać prawidłowe rejestracje na platformę, wywołując registerWebSource() lub registerWebTrigger().

Ten fragment kodu zawiera przykład wywołania interfejsu API, które przeglądarka rejestrują źródło atrybucji przed przekierowaniem użytkownika do aplikacji:

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

Ten fragment kodu pokazuje przykład wywołania interfejsu API, które przeglądarka wykonuje, aby zarejestrować konwersję po przekierowaniu użytkownika z aplikacji:

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

Dodawanie szumu na potrzeby prywatności

Raporty na poziomie zdarzenia zawierają dane o miejscu docelowym, identyfikatorze źródła atrybucji i wyzwalaczu. Są one wysyłane do raportu w pierwotnym (niezaszyfrowanym) formacie. pochodzeniu danych. Aby chronić prywatność użytkowników, można dodać szum, który utrudnia identyfikację pojedynczego użytkownika. Raporty na poziomie zdarzenia z dodanymi szumem są generowane i wysyłane zgodnie z ramami prywatności różnicowej. Oto domyślne wartości procentowe szumu w różnych scenariuszach:

Typ źródła

Wartość źródłowego miejsca docelowego

Prawdopodobieństwo raportu o szumieniu na podstawie rejestracji źródła

Wyświetl

Aplikacja lub witryna

0,0000025

Wyświetl

Aplikacja i internet

0,0000042

Kliknięcie

Aplikacja lub przeglądarka

0,0024263

Kliknięcie

Aplikacja i internet

0,0170218

W pomiarze atrybucji aplikacji do witryny, w którym źródła mogą zwiększać liczbę konwersji zarówno miejsc docelowych w aplikacjach, jak i w internecie, raporty na poziomie zdarzenia mogą określać, czy wystąpiło w aplikacji lub witrynie. Aby zrekompensować te dodatkowe szczegóły, generowane raporty z dodatkowymi danymi mogą zawierać do 7 razy więcej kliknięć i do 1,7 raza więcej wyświetleń.

Niektóre technologie reklamowe nie wymagają raportów na poziomie zdarzenia, aby określać, czy reguła wystąpiło w aplikacji lub miejscu docelowym w internecie. Aby zmniejszyć szum, specjaliści ds. technologii reklamowych mogą użyć pola coarse_event_report_destinations w sekcji Attribution-Reporting-Register-Source. Jeśli atrybucję otrzymuje źródło z wyspecyfikowanym polem coarse_event_report_destinations, raport zawiera zarówno miejsca docelowe w aplikacji, jak i w witrynie, bez rozróżniania, gdzie wystąpił rzeczywisty bodziec.

W poniższych przykładach użytkownik klika reklamę, a źródło jest zarejestrowane za pomocą interfejsu API. Następnie użytkownik dokonuje konwersji zarówno w aplikacji reklamodawcy, jak i w do witryny reklamodawcy. Obie te konwersje są rejestrowane jako reguły, przypisanej do pierwszego kliknięcia.

Nagłówek HTTP rejestracji źródła na podstawie kliknięć:

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

Aktywator jest zarejestrowany z aplikacji o nazwie pakietu com.advertiser.example:

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

Wyzwalacz jest rejestrowany z przeglądarki w witrynie z domeną eTLD+1:https://advertiser.com

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

Wygenerowane raporty na poziomie zdarzenia zostaną wygenerowane. Zakładając, że oba aktywatory uzyskały przypisane do źródła, generowane są te raporty na poziomie zdarzenia:

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

generować i przesyłać raporty;

Interfejs Attribution Reporting API wysyła raporty do punktów końcowych na serwerze, które akceptują raporty na poziomie zdarzenia i raporty zbiorcze.

Wymuszanie uruchomienia zadań raportowania

Gdy zarejestrujesz zdarzenie źródła atrybucji lub zdarzenie wyzwalające, system zaplanowa uruchamianie zadania raportowania. Domyślnie to zadanie jest wykonywane co 4 godziny. Na potrzeby testów możesz wymusić uruchomienie zadań raportowania lub skrócić odstępy między nimi.

Wymuś uruchomienie zadania atrybucji:

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

Wymuszanie uruchomienia zadania raportowania na poziomie zdarzenia:

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

Wymuś uruchomienie agregowanego zadania raportowania:

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

Sprawdź dane wyjściowe w logcat, aby zobaczyć, kiedy zadania zostały uruchomione. Powinien wyglądać Na przykład:

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

Wymuszanie dostarczania raportów

Nawet jeśli uruchomienie zadania raportowania będzie wymuszone, system i tak wysyła raporty zgodnie z ich zaplanowanym czasem dostawy, który wynosi od kilku godzin do kilku dni. W celu przeprowadzenia testów możesz przesunąć czas na urządzeniu, aby był on późniejszy niż zaplanowane opóźnienia, które inicjują wysyłanie raportów.

Sprawdzanie raportów na serwerze

Po wysłaniu raportów potwierdź ich dostarczenie, sprawdzając odpowiednie raporty. dzienników serwera, takich jak pozorowana historia serwera lub niestandardowy system.

Dekodowanie raportu zbiorczego

Podczas odbierania raportu zbiorczego pole debug_cleartext_payload zawiera niezaszyfrowanej wersji raportu zbiorczego. Choć ta wersja nie jest zaszyfrowany, wciąż wymaga dekodowania.

Poniżej przedstawiamy przykład dekodowania zawartości pola debug_cleartext_payload w 2 kroki: pierwszy to dekodowanie w formacie Base64, a drugi to dekodowanie w formacie 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);
});

Testowanie

Aby łatwiej zacząć korzystać z interfejsu Attribution Reporting API, możesz użyć projekt MeasurementSampleApp w GitHubie. Ta przykładowa aplikacja demonstruje rejestrację źródła atrybucji i rejestrację reguły.

W przypadku punktów końcowych serwera zapoznaj się z tymi materiałami referencyjnymi lub z własnym rozwiązaniem:

  • MeasurementAdTechServerSpec obejmuje definicje usług OpenAPI, który można wdrożyć na obsługiwanych platformach próbnych i mikroserwisach.
  • MeasurementAdTechServer zawiera referencyjną implementację przykładowej implementacji. oparty na aplikacji Spring Boot dla Google App Engine.

Wymagania wstępne

wdróż przykładowe interfejsy API w zdalnych punktach końcowych dostępnych z urządzenia testowego lub za pomocą emulatora. Aby ułatwić sobie testowanie, zapoznaj się z przykładowymi projektami MeasurementAdTechServerSpecMeasurementAdTechServer.

Funkcje do przetestowania

Nadchodzące funkcje

Elastyczna konfiguracja na poziomie zdarzenia

Domyślna konfiguracja raportowania na poziomie zdarzenia jest zalecana w przypadku testy jednostkowe, ale mogą nie być idealne we wszystkich przypadkach użycia. Interfejs Attribution Reporting API będzie obsługiwać opcjonalne, bardziej elastyczne konfiguracje, dzięki czemu firmy zajmujące się technologiami reklamowymi będą miały większą kontrolę nad strukturą raportów na poziomie zdarzenia i będą mogły w pełni wykorzystać potencjał tych danych. Ta dodatkowa elastyczność pozwoli przedstawiamy interfejs Attribution Reporting API w 2 fazach:

  • Etap 1. Elastyczna konfiguracja na poziomie zdarzenia Lite. podzbiór fazy 2.
  • Etap 2: pełna wersja elastycznej konfiguracji na poziomie zdarzenia.

Etap 1. Elastyczny poziom zdarzeń typu lite

Dodamy do pliku JSON następujące 2 opcjonalne parametry w 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>, ...]
  }
}

Przykład konfiguracji niestandardowej

Ta przykładowa konfiguracja jest przeznaczona dla dewelopera, który chce zoptymalizować kampanię pod kątem otrzymywanie raportów we wcześniejszych okresach raportowania.

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

Etap 2. W pełni elastyczny poziom zdarzenia

Oprócz parametrów dodanych w etap 1 do pliku JSON w pliku Attribution-Reporting-Register-Source dodamy dodatkowy opcjonalny parametr trigger_specs.

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

Ta konfiguracja w pełni określa przestrzeń wyjściową raportów na poziomie zdarzenia, za rejestrację źródła. Każda specyfikacja aktywatora w pełni określa:

  • Zestaw kryteriów:
    • konkretnych danych aktywatora, których dotyczy ta specyfikacja; To źródło może być dopasowywane tylko do reguł, które mają jedną ze wskazanych wartości trigger_data w polu trigger_specs. Inaczej mówiąc, jeśli reguła pasuje do tego źródła, ale jej parametr trigger_data nie jest jedną z wartości w konfiguracji źródła, reguła jest ignorowana.
    • Jeśli konkretna reguła pasuje do tej specyfikacji (z użyciem event_report_windows). Pamiętaj, że reguła nadal może być dopasowywana ze źródłem dla raportów agregowanych mimo błędu dopasowania wymienionych powyżej.
  • Specjalny algorytm do podsumowywania i grupowania wszystkich aktywatorów w grupie w oknie atrybucji. Dzięki temu aktywatory mogą określać parametr value podsumowywane dla określonej specyfikacji i zgłaszane jako wartość zbiorcza.
.

Będą one też obsługiwać dodawanie parametru opcjonalnej wartości w słownikach w sekcji event_trigger_data.

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

Każda rejestracja reguły będzie pasować do maksymalnie 1 specyfikacji reguły i zaktualizuje powiązaną z nią wartość podsumowania. Ogólnie rzecz biorąc, w momencie uruchomienia:

  • Zastosuj globalne filtry atrybucji.
  • W przypadku każdej specyfikacji reguły sprawdź atrybut event_trigger_data w specyfikacji, aby znaleźć zgodnie ze specyfikacją: event_reporting_window. Organizacja najwyższego poziomu event_reporting_windows działa jako wartość domyślna w przypadku, gdy którakolwiek specyfikacja aktywatora jest brakujące pole podrzędne event_report_windows.
  • Do atrybucji jest wybierana pierwsza pasująca specyfikacja, a podsumowana wartość to zwiększył się o value.

Gdy event_report_window dla specyfikacji dobiegnie końca, zmapujemy jej podsumowanie do zasobnika i wysyłać raport na poziomie zdarzenia dla każdego przyrostu wartości w powodowane przez przypisane wartości reguł. W raportach będzie podana jedna dodatkowe pole, trigger_summary_bucket.

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

konfiguracje, które są równoważne bieżącej wersji;

Poniżej znajdziesz odpowiadające im konfiguracje bieżącego zdarzenia interfejsów API oraz źródeł nawigacji. Szczególnie w przypadku źródeł nawigacji ta definicja wyjaśnia, dlaczego poziomy szumu są tak wysokie w stosunku do źródeł zdarzeń utrzymują te same wartości ypsilon: dane wyjściowe źródeł nawigacji mają znacznie większe wartości kosmosu.

Możliwe, że istnieje wiele równoważnych konfiguracji, ponieważ niektóre parametry mogą być ustawione jako domyślne lub wyeliminowane.

Źródła zdarzeń równoważne
// 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>,
}
Źródła nawigacji o równoważnych funkcjach
// 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>,
}

Przykładowe konfiguracje niestandardowe

Poniżej znajdziesz dodatkowe konfiguracje inne niż domyślne. We wszystkich tych przykładach kompromisy dla deweloperów obejmują:

  • ograniczenie niektórych wymiarów konfiguracji domyślnej (#triggers, dane wyzwalacza moc zbioru, #windows) w celu zwiększenia kolejnej w celu zachowania poziomu szumu
  • zmniejszenie niektórych wymiarów domyślnej konfiguracji (np. liczby wyzwalaczy, mocy danych wyzwalacza, liczby okien) w celu zmniejszenia poziomu szumu;

Raportowanie zakresów wartości aktywatora

Ta przykładowa konfiguracja jest przeznaczona dla dewelopera, który chce zoptymalizować kampanię pod kątem wartości danych tylko dla jednego okna raportowania (np. 7 dni) i mniejszej liczby raportów i zmniejszyć szum. W tym przykładzie każdy przełącznik, który ustawia wartość trigger_data na wartość inną niż 0, nie kwalifikuje się do przypisywania.

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

Aktywatory mogły być zarejestrowane przy użyciu zestawu pól value, które są sumowane, do zasobnika. Na przykład jeśli w ciągu 7 dni od źródła istnieją 3 reguły rejestracje z wartościami 1, 3 i 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}] }

Wartości są sumowane do 8 i raportowane w tych raportach po 7 dniach + 1 godzinie:

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

W ciągu kolejnych 7 dni zarejestrowane zostaną te reguły:

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

Wartości są sumowane do 8 + 50 + 45 = 103. W ten sposób uzyskujesz następujące raporty przy 14 dni + 1 godzina:

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

// Report 3
{
  ...
  "trigger_summary_bucket": [100, MAX_INT]
}
Raportowanie liczby reguł

Ten przykład pokazuje, jak deweloper może skonfigurować źródło, aby obliczać wyzwala do 10 elementów.

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

Przypisane reguły, w których wartość trigger_data jest ustawiona na 0, są zliczane i ograniczone do 10. Wartość reguły jest ignorowana, ponieważ zasada summary_window_operator jest ustawiona na liczenie. Jeśli Zarejestrowano 4 reguły i zostały przypisane do źródła. Raport będzie wyglądał tak podobny do tego:

// 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]
}
binarne z częstszym raportowaniem,

Ta przykładowa konfiguracja ułatwia życie deweloperowi, który chce się dowiedzieć, czy w ciągu pierwszych 10 dni wystąpiła co najmniej 1 konwersja (niezależnie od jej wartości), ale chce otrzymywać raporty w częstszych odstępach czasu niż domyślne. Znowu za W tym przykładzie każda reguła, która ustawia trigger_data na wartość inną niż 0, to nie kwalifikuje się do atrybucji. Dlatego ten przypadek użycia nazywamy binarnym.

{
  "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]
  }],
}
zmienić specyfikacje aktywatora w zależności od źródła;
{
  "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
}

Zachęcamy deweloperów do sugerowania różnych zastosowań tego rozszerzenia interfejsu API. Na tej podstawie zaktualizujemy ten artykuł o przykładowe konfiguracje dla tych zastosowań.

Atrybucja międzysieciowa bez przekierowań

Technologie reklamowe powinny używać przekierowań do rejestrowania wielu źródeł atrybucji oraz do przeprowadzania atrybucji między sieciami. Ta funkcja pomaga obsługiwać atrybucję w wielu sieciach, gdy przekierowania nie są możliwe w różnych sieciach. Więcej informacji

Technologie reklamowe mogą wysyłać konfigurację w odpowiedzi dotyczącej rejestracji na podstawie tego, które źródła zarejestrowane przez inne technologie reklamowe są wybierane w celu wygenerowania źródeł; te źródła są następnie używane do atrybucji. Raporty zbiorcze są generowane, jeśli wyzwalacz zostanie przypisany do źródła pochodzenia. Raport zdarzeń generowanie dla źródeł pochodnych nie jest obsługiwane.

Techniki reklamowe mogą wybierać spośród aggregation_keys zarejestrowanych źródeł, które które zamierzają udostępnić partnerom zajmującym się technologiami reklamowymi. Te klucze można zadeklarować w sekcji opcjonalne pole shared_aggregation_keys znajdujące się w ramach rejestracji źródła nagłówek Attribution-Reporting-Register-Source:

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

Źródła pochodne są generowane na podstawie konfiguracji w nagłówku rejestracji reguły 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]"
    }
  ]

Oto wersja z dodanymi przykładowymi wartościami:

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

Do nagłówka aktywatora rejestracji dodaliśmy 2 nowe pola opcjonalne. Te pola umożliwiają użycie identyfikatora zwycięskiej firmy dostarczającej technologie reklamowe w kluczach raportów podlegających agregacji:

  • x_network_bit_mapping: mapowanie identyfikatora rejestracji na bit identyfikatora technologii reklamowej
  • x_network_data: przesunięcie (przesunięcie w lewo) dla zwycięskiej technologii reklamowejx_network_bit_mapping LUB operacja z kluczem uruchamiającym
Przykład:
"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
  }
  
}

Oto wynik obliczeń części klucza wyzwalającego podczas generowania raportu dla Źródło AdTechB:

  • key_piece: 0x400 (010000000000)
  • key_offset: 12
  • Wartość enrollment_id w AdtechB: 2 (010) (z x_network_bit_mapping)
  • Wynikowy element klucza reguły: 0x400 | 0x2 << 12 = 0x2400

Ograniczenia

Aby zobaczyć listę pozostających w toku funkcji środowiska wykonawczego SDK, wyświetl informacjami o wersji.

Zgłaszanie błędów i problemów

Twoja opinia jest kluczowym elementem Piaskownicy prywatności na Androida. Daj nam znać wykrytych problemów lub pomysłów na ulepszenie Piaskownicy prywatności. na Androidzie.