Attribution Reporting API 개발자 가이드

컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요.

Attribution Reporting API는 당사자 간 사용자 식별자에 관한 의존성을 제거하여 사용자 개인 정보 보호를 개선하고 앱에서 기여 분석 및 전환 측정을 위한 주요 사용 사례를 지원하도록 설계되었습니다. 이 개발자 가이드에서는 광고 클릭, 조회, 전환 등의 이벤트와 관련된 트리거 및 소스를 등록하는 메서드를 호출하여 그러한 이벤트를 등록하는 Attribution Reporting API를 구성하고 테스트하는 방법을 설명합니다.

이 가이드에서는 서버 엔드포인트를 설정하고 그러한 서비스를 호출하는 클라이언트 앱을 빌드하는 방법을 설명합니다. 설계 제안에서 Attribution Reporting API의 전반적인 설계에 관해 자세히 알아보세요.

주요 용어

  • 기여 분석 소스는 클릭수 또는 조회수를 나타냅니다.
  • 트리거는 전환에 기여할 수 있는 이벤트입니다.
  • 보고서에는 트리거와 관련 기여 분석 소스에 관한 데이터가 포함됩니다. 이러한 보고서는 트리거 이벤트에 관한 응답으로 전송됩니다. Attribution Reporting API는 이벤트 수준 보고서집계 가능한 보고서를 지원합니다.

시작하기 전에

Attribution Reporting API를 사용하려면 다음 섹션에 나와 있는 서버 측 작업과 클라이언트 측 작업을 완료하세요.

Attribution Reporting API 엔드포인트 설정

Attribution Reporting API를 사용하려면 테스트 기기 또는 에뮬레이터에서 액세스할 수 있는 엔드포인트 세트가 필요합니다. 다음 서버 측 작업별로 엔드포인트를 하나씩 만듭니다.

필수 엔드포인트를 설정하는 방법에는 여러 가지가 있습니다.

  • 가장 빨리 시작하고 실행하는 방법은 샘플 코드 저장소에서 OpenAPI v3 서비스 정의를 모의 플랫폼 또는 마이크로서비스 플랫폼에 배포하는 것입니다. Postman 또는 Prism이나 이 형식을 허용하는 다른 모의 서버 플랫폼을 모두 사용할 수 있습니다. 각 엔드포인트를 배포하고 앱에 사용할 URI를 추적합니다. 보고서 전송을 확인하려면 이전에 모의 플랫폼 또는 서버리스 플랫폼에 실행한 호출을 참고하세요.
  • 스프링 부트 기반 Kotlin 샘플을 사용하여 고유한 독립형 서버를 실행합니다. 이 서버를 클라우드 제공업체 또는 내부 인프라에 배포합니다.
  • 서비스 정의를 예로 사용하여 엔드포인트를 기존 시스템에 통합합니다.

소스 등록 허용

이 엔드포인트는 다음과 유사한 URI에서 주소 지정이 가능해야 합니다.

https://adtech.example/attribution_source

클라이언트 앱이 기여 분석 소스를 등록할 때 이 서버 엔드포인트의 URI를 제공합니다. 그러면 Attribution Reporting API가 요청을 실행하고 다음 헤더 중 하나를 포함합니다.

  • 클릭 이벤트의 경우:

    Attribution-Reporting-Source-Info: navigation
    
  • 조회 이벤트의 경우:

    Attribution-Reporting-Source-Info: event
    

다음으로 응답하도록 서버 엔드포인트를 구성합니다.

// Metadata associated with attribution source.
Attribution-Reporting-Register-Source: {
  "destination": "[app package name]",
  "web_destination": "[eTLD+1]",
  "source_event_id": "[64 bit unsigned integer]",
  "expiry": "[64 bit signed integer]",
  "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>

다음은 샘플 값이 추가된 예입니다.

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

Attribution-Reporting-Redirects에 광고 기술 파트너의 URI가 포함되어 있으면 Attribution Reporting API가 각 URI에 비슷한 요청을 실행합니다. 각 광고 기술 파트너는 다음 헤더로 응답하는 서버를 구성해야 합니다.

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.

전환 트리거 등록 허용

이 엔드포인트는 다음과 유사한 URI에서 주소 지정이 가능해야 합니다.

https://adtech.example/attribution_trigger

클라이언트 앱이 트리거 이벤트를 등록할 때 이 서버 엔드포인트의 URI를 제공합니다. 그러면 Attribution Reporting API가 요청을 실행하고 다음 헤더 중 하나를 포함합니다.

다음으로 응답하도록 서버 엔드포인트를 구성합니다.

// Metadata associated with trigger.
Attribution-Reporting-Register-Trigger: {
  "event_trigger_data": [{
    // "trigger_data returned" in event reports is truncated to
    // the last 1 or 3 bits, based on conversion type.
    "trigger_data": "[unsigned 64-bit integer]",
    "priority": "[signed 64-bit integer]",
    "deduplication_key": "[signed 64-bit integer]",
    // "filter" and "not_filters" are optional fields which allow configuring
    // 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>

다음은 샘플 값이 추가된 예입니다.

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

Attribution-Reporting-Redirects에 광고 기술 파트너의 URI가 포함되어 있으면 Attribution Reporting API가 각 URI에 비슷한 요청을 실행합니다. 각 광고 기술 파트너는 다음 헤더로 응답하는 서버를 구성해야 합니다.

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

이벤트 수준 보고서 허용

이 엔드포인트는 URI에서 처리 가능해야 합니다. Android의 개인 정보 보호 샌드박스가 고유한 포스트백 URI 등록을 지원할 때까지 URI는 소스 등록 및 트리거 등록 허용에 사용되는 서버의 eTLD+1에서 추론됩니다. 소스 등록을 허용하고 트리거 등록을 허용하는 엔드포인트의 URI 예를 사용할 경우 이 엔드포인트의 URI는 다음과 같습니다.

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

다음 형식을 사용하는 JSON 요청을 수락하도록 이 서버를 구성합니다.

{
  "attribution_destination": "android-app://com.advertiser.example",
  "source_event_id": "12345678",
  "trigger_data": "2",
  "report_id": "12324323",
  "source_type": "navigation",
  "randomized_trigger_rate": "0.02"
}

집계 가능한 보고서 허용

이 엔드포인트는 URI에서 처리 가능해야 합니다. Android의 개인 정보 보호 샌드박스가 고유한 포스트백 URI 등록을 지원할 때까지 URI는 소스 등록 및 트리거 등록 허용에 사용되는 서버의 출처에서 추론됩니다. 소스 등록을 허용하고 트리거 등록을 허용하는 엔드포인트의 URI 예를 사용할 경우 이 엔드포인트의 URI는 다음과 같습니다.

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

현재 집계 가능한 보고서에는 암호화된 필드와 암호화되지 않은 필드가 모두 채워져 있습니다. 암호화된 보고서를 사용하면 집계 서비스로 테스트를 시작할 수 있으며 암호화되지 않은 필드는 설정된 키-값 쌍의 데이터 구조화 방식에 관한 유용한 정보를 제공합니다.

다음 형식을 사용하는 JSON 요청을 수락하도록 이 서버를 구성합니다.

{
  // Info that the aggregation services also need encoded in JSON
  // for use with AEAD. Line breaks added for readability.
  "shared_info": "{
     \"api\":\"attribution-reporting\",
     \"attribution_destination\": \"android-app://com.advertiser.example.advertiser\",
     \"scheduled_report_time\":\"[timestamp in seconds]\",
     \"source_registration_time\": \"[timestamp in seconds]\",
     \"version\":\"[api version]\",
     \"report_id\":\"[UUID]\",
     \"reporting_origin\":\"https://reporter.example\" }",

  // In the current Developer Preview release, The "payload" and "key_id" fields
  // are not used because the platform does not yet encrypt aggregate reports.
  // Currently, the "debug_cleartext_payload" field holds unencrypted reports.
  "aggregation_service_payloads": [
    {
      "payload": "[base64 HPKE encrypted data readable only by the aggregation service]",
      "key_id": "[string identifying public key used to encrypt payload]",

      "debug_cleartext_payload": "[unencrypted payload]",
    },
  ],

  "source_debug_key": "[64 bit unsigned integer]",
  "trigger_debug_key": "[64 bit unsigned integer]"
}

Android 클라이언트 설정

클라이언트 앱은 기여 분석 소스와 트리거를 등록하고 이벤트 수준 보고서 및 집계 가능한 보고서 생성을 가능하게 합니다. Attribution Reporting API를 사용하도록 Android 클라이언트 기기 또는 에뮬레이터를 준비하려면 다음을 진행하세요.

  1. Android의 개인 정보 보호 샌드박스의 개발 환경을 설정합니다.
  2. 지원되는 기기에 시스템 이미지를 설치하거나 Android의 개인 정보 보호 샌드박스 지원이 포함된 에뮬레이터를 설정합니다.
  3. 다음 ADB 명령어를 실행하여 Attribution Reporting API에 대한 액세스를 사용 설정합니다. 이 API는 기본적으로 사용 중지되어 있습니다.

    adb shell device_config put adservices ppapi_app_allow_list \"*\"
    
  4. 다음 코드 스니펫과 같이 ACCESS_ADSERVICES_ATTRIBUTION 권한을 포함하고 앱에서 Attribution Reporting API를 사용할 수 있도록 광고 서비스 구성을 만듭니다.

    <uses-permission android:name="android.permission.ACCESS_ADSERVICES_ATTRIBUTION" />
    
  5. 매니페스트에 참조된 광고 서비스 XML 리소스를 지정합니다(예: res/xml/ad_services_config.xml). 광고 서비스 권한 및 SDK 액세스 제어에 관해 자세히 알아보세요.

    <property android:name="android.adservices.AD_SERVICES_CONFIG"
          android:resource="@xml/ad_services_config" />
    
  6. 매니페스트의 <application> 요소에서 광고 서비스 구성을 참조합니다.

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

광고 이벤트 등록

소스와 전환이 발생할 때 앱에서 이를 등록해야 제대로 보고됩니다. MeasurementManager 클래스에는 기여 분석 소스 이벤트전환 트리거를 등록하는 데 도움이 되는 메서드가 있습니다.

기여 분석 소스 이벤트 등록

광고가 조회되거나 클릭되면 게시자 앱은 registerSource()를 호출하여 코드 스니펫에 표시된 것처럼 기여 분석 소스를 등록합니다.

Attribution Reporting API는 다음 유형의 기여 분석 소스 이벤트를 지원합니다.

  • 클릭: 일반적으로 onClick()과 유사한 콜백 메서드 내에서 등록합니다. 관련 트리거 이벤트는 일반적으로 클릭 이벤트 직후에 발생합니다. 이 이벤트 유형은 사용자 상호작용에 관한 자세한 정보를 제공하므로 높은 우선순위를 부여하는 데 적합한 기여 분석 소스 유형입니다.
  • 조회: 일반적으로 onAdShown()과 유사한 콜백 메서드 내에서 등록합니다. 관련 트리거 이벤트는 조회 이벤트가 발생하고 몇 시간 또는 며칠 후에 발생할 수 있습니다.

Kotlin

companion object {
    private val CALLBACK_EXECUTOR = Executors.newCachedThreadPool()
}

val measurementManager = context.getSystemService(MeasurementManager::class.java)
var exampleClickEvent: InputEvent? = null

// Use the URI of the server-side endpoint that accepts attribution source
// registration.
val attributionSourceUri: Uri =
  Uri.parse("https://adtech.example/attribution_source?AD_TECH_PROVIDED_METADATA")

val future = CompletableFuture<Void>()

adView.setOnTouchListener(_: View?, event: MotionEvent?)) ->
    exampleClickEvent = event
    true
}

// Register Click Event
measurementManager.registerSource(
        attributionSourceUri,
        exampleClickEvent,
        CALLBACK_EXECUTOR,
        future::complete)

// Register View Event
measurementManager.registerSource(
        attributionSourceUri,
        null,
        CALLBACK_EXECUTOR,
        future::complete)

자바

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

등록 후 API는 attributionSourceUri로 지정된 주소에서 서비스 엔드포인트에 HTTP POST 요청을 보냅니다. 엔드포인트의 응답에는 destination, source_event_id, expirysource_priority 값이 포함되어 있습니다.

발신 광고 기술에서 소스 등록을 공유하려는 경우 원래의 기여 분석 소스 URI에는 다른 광고 기술 엔드포인트로의 리디렉션이 포함될 수 있습니다. 리디렉션에 적용 가능한 제한과 규칙은 기술 제안에 자세히 설명되어 있습니다.

전환 트리거 이벤트 등록

전환 트리거 이벤트를 등록하려면 앱에서 registerTrigger()를 호출합니다.

Kotlin

companion object {
    private val CALLBACK_EXECUTOR = Executors.newCachedThreadPool()
}

val measurementManager = context.getSystemService(MeasurementManager::class.java)

// Use the URI of the server-side endpoint that accepts trigger registration.
val attributionTriggerUri: Uri =
    Uri.parse("https://adtech.example/trigger?AD_TECH_PROVIDED_METADATA")

val future = CompletableFuture<Void>()

// Register trigger (conversion)
measurementManager.registerTrigger(
        attributionTriggerUri,
        CALLBACK_EXECUTOR,
        future::complete)

자바

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)

등록 후 API는 attributionTriggerUri로 지정된 주소에서 서비스 엔드포인트에 HTTP POST 요청을 보냅니다. 엔드포인트의 응답에는 이벤트 보고서 및 집계 보고서의 값이 포함되어 있습니다.

발신 광고 기술 플랫폼에서 트리거 등록 공유를 허용하는 경우 URI에는 다른 광고 기술 플랫폼에 속한 URI로의 리디렉션이 포함될 수 있습니다. 리디렉션에 적용 가능한 제한과 규칙은 기술 제안에 자세히 설명되어 있습니다.

교차 앱 및 웹 측정 등록

소스에서 트리거로 이어지는 사용자 여정에서 앱과 브라우저가 모두 기여한 경우 광고 이벤트 등록 구현에는 미묘한 차이가 있습니다. 사용자가 앱에서 광고를 보고 전환을 위해 브라우저로 리디렉션되는 경우 소스는 앱에서 등록되고 전환은 웹브라우저에서 등록됩니다. 마찬가지로 사용자가 웹브라우저에서 시작하고 전환을 위해 앱으로 이동되면 브라우저에서 소스를 등록하고 앱에서 전환을 등록합니다.

광고 기술이 웹과 Android에서 구성되는 방식에 차이가 있으므로 Google에서는 소스 및 트리거가 브라우저에서 발생할 때 이를 등록하는 새 API를 추가했습니다. 이러한 API와 이에 상응하는 앱 기반 API의 주요 차이점은 브라우저가 리디렉션을 따르고 브라우저 관련 필터를 적용하며 registerWebSource() 또는 registerWebTrigger()를 호출하여 플랫폼에 유효한 등록을 전달할 것으로 예상된다는 점입니다.

다음 코드 스니펫은 사용자를 앱으로 안내하기 전에 브라우저가 기여 분석 소스를 등록하기 위해 실행하는 API 호출의 예를 보여줍니다.

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)

자바

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

다음 코드 스니펫은 사용자가 앱에서 이동한 후 브라우저가 전환을 등록하기 위해 실행하는 API 호출의 예를 보여줍니다.

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)

자바

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

보고서 생성 및 전송

Attribution Reporting API는 이벤트 수준 보고서집계 가능한 보고서를 허용하는 서버 엔드포인트에 보고서를 전송합니다.

보고 작업 강제 실행

기여 분석 소스 이벤트를 등록하거나 트리거 이벤트를 등록하면 시스템에서 실행할 보고 작업을 예약합니다. 기본적으로 이 작업은 4시간마다 실행됩니다. 테스트 목적에서는 보고 작업을 강제로 실행하거나 작업 간 간격을 단축할 수 있습니다.

기여 분석 작업을 강제 실행하려면 다음을 진행합니다.

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

다음과 같이 이벤트 수준 보고 작업을 강제 실행합니다.

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

다음과 같이 집계 가능 보고 작업을 강제 실행합니다.

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

작업이 실행된 시점을 보려면 logcat의 출력을 확인합니다. 다음과 같아야 합니다.

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

보고서 강제 전송

보고 작업이 강제로 실행되더라도 시스템은 몇 시간에서 며칠까지 걸리는 예약된 전송 시간에 따라 보고서를 계속 전송합니다. 테스트 목적을 위해, 기기 시스템 시간을 예약된 지연 이후로 변경하여 보고서 전송을 시작할 수 있습니다.

서버에서 보고서 확인

보고서가 전송되면 수신된 보고서나 모의 서버 기록 같은 관련 서버 로그 또는 맞춤 시스템을 확인하여 전송을 확인합니다.

테스트

Attribution Reporting API를 시작하려면 GitHub의 MeasurementSampleApp 프로젝트를 사용하면 됩니다. 이 샘플 앱은 기여 분석 소스 등록 및 트리거 등록 과정을 보여줍니다.

서버 엔드포인트와 관련해서는 다음 참조 리소스 또는 맞춤 솔루션을 사용하는 것이 좋습니다.

  • MeasurementAdTechServerSpec은 지원되는 모의 플랫폼 또는 마이크로서비스 플랫폼에 배포할 수 있는 OpenAPI 서비스 정의를 포함하고 있습니다.
  • MeasurementAdTechServer는 Google App Engine용 Spring Boot 앱에 기반한 모의 서버의 참조 구현을 포함하고 있습니다.

기본 요건

테스트 기기 또는 에뮬레이터에서 액세스할 수 있는 원격 엔드포인트에 모의 API를 배포합니다. 테스트 편의를 위해 MeasurementAdTechServerSpecMeasurementAdTechServer 샘플 프로젝트를 참고하세요.

테스트할 기능

  • 기여 분석 소스 및 전환 트리거 등록을 실행합니다. 서버 측 엔드포인트가 올바른 형식으로 응답하는지 확인합니다.
  • 보고 작업을 실행합니다.
  • 테스트 서버의 백엔드 또는 콘솔에서 보고서 전송을 확인합니다.

제한사항

SDK 런타임의 진행 중인 기능 목록은 출시 노트를 참고하세요.

버그 및 문제 신고

여러분의 의견은 Android의 개인 정보 보호 샌드박스에서 매우 중요한 부분입니다. 발견한 문제나 Android의 개인 정보 보호 샌드박스 개선을 위한 아이디어가 있다면 Google에 알려 주세요.