Topics API 개발자 가이드

안내가 다를 수 있으므로 Android의 개인 정보 보호 샌드박스 문서를 읽으면서 개발자 프리뷰 또는 베타 버튼을 사용하여 작업 중인 프로그램 버전을 선택하세요.


의견 보내기

Topics API는 사용자의 앱 사용을 기반으로 기기 내에서 대략적인 관심분야 신호를 추론합니다. 주제라고 하는 이러한 신호는 여러 앱에서 개별 사용자를 추적하지 않고도 관심 기반 광고를 지원하기 위해 광고주와 공유됩니다. 디자인 제안서에서 Topics API에 관해 자세히 알아보세요. 중요: 안내가 다를 수 있으므로 SDK 확장 프로그램 출시 또는 개발자 프리뷰 버튼을 선택하여 작업 중인 프로그램 버전을 선택하세요.

설정

최신 Android 개인 정보 보호 샌드박스 SDK를 사용하여 개인 정보 보호 API의 최신 버전을 다운로드하세요. 앱에서 Topics API를 사용하려면 앱의 매니페스트에서 권한을 포함하고 광고 서비스 구성을 만들어야 합니다.

<uses-permission android:name="android.permission.ACCESS_ADSERVICES_TOPICS" />

매니페스트의 <application> 요소에서 광고 서비스 구성을 참조합니다.

<property android:name="android.adservices.AD_SERVICES_CONFIG"
   android:resource="@xml/ad_services_config" />

매니페스트에 참조된 광고 서비스 XML 리소스를 지정합니다(예: res/xml/ad_services_config.xml). allowAllToAccess 속성을 사용하여 모든 SDK에 대한 액세스 권한을 부여하거나 allowSdksToAccess 속성을 사용하여 개별 SDK에 대한 액세스 권한을 부여합니다. 광고 서비스 권한 및 SDK 액세스 제어에 관해 자세히 알아보세요.

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

또한 이러한 adb 명령어를 사용하여 Topics API(기본적으로 사용 중지됨)에 대한 액세스를 사용 설정해야 합니다.

adb shell device_config put adservices ppapi_app_signature_allow_list \"*\"
adb shell setprop debug.adservices.disable_topics_enrollment_check true

Topics API의 기본 기능은 다음 예시와 같이 TopicsManager 객체 내 getTopics() 메서드에 있습니다.

Kotlin

fun getTopics(
        getTopicsRequest: GetTopicsRequest,
        executor: Executor,
        callback: OutcomeReceiver<GetTopicsResponse, Exception>
    ) { }

Java

public void getTopics (@NonNull GetTopicsRequest getTopicsRequest,
    @NonNull Executor executor,
    @NonNull OutcomeReceiver<GetTopicsResponse, Exception> callback)

이 메서드를 사용하려면 TopicsManager 객체와 주제 데이터를 수신하는 데 필요한 매개변수를 초기화합니다. GetTopicsRequest는 호출자가 관찰자 역할을 할지 여부를 나타내는 플래그를 포함하여 Topics API 데이터를 가져오는 데 필요한 정보를 전달합니다. 관찰자 역할을 하지 않는 경우 getTopics 호출은 이전 에포크의 주제를 반환하지만 다음 에포크의 주제 데이터에는 영향을 주지 않습니다. OutcomeReceiver 콜백은 결과를 비동기적으로 처리합니다. 예를 들면 다음과 같습니다.

Kotlin

private fun topicGetter() {
    val mContext = baseContext
    val mTopicsManager = mContext.getSystemService(TopicsManager::class.java)
    val mExecutor: Executor = Executors.newCachedThreadPool()
    val shouldRecordObservation = false
    val mTopicsRequestBuilder: GetTopicsRequest.Builder = GetTopicsRequest.Builder()
    mTopicsRequestBuilder.setAdsSdkName(baseContext.packageName)
    mTopicsRequestBuilder.setShouldRecordObservation(shouldRecordObservation)
    mTopicsManager.getTopics(mTopicsRequestBuilder.build(), mExecutor,
        mCallback as OutcomeReceiver<GetTopicsResponse, Exception>)
}
private var mCallback: OutcomeReceiver<GetTopicsResponse, java.lang.Exception> =
object : OutcomeReceiver<GetTopicsResponse, java.lang.Exception> {
    override fun onResult(result: GetTopicsResponse) {
        // handle successful result
        val topicsResult = result.topics
        for (i in topicsResult.indices) {
            Log.i("Topic", topicsResult[i].getTopicId().toString())
        }
        if (topicsResult.size == 0) {
            Log.i("Topic", "Returned Empty")
        }
    }
    override fun onError(error: java.lang.Exception) {
        // handle error
        Log.i("Topic", "Error, did not return successfully")
    }
}

Java

public void TopicGetter() {
    @NonNull Context mContext = getBaseContext();
    TopicsManager mTopicsManager = mContext.getSystemService(TopicsManager.class);
    Executor mExecutor = Executors.newCachedThreadPool();
    boolean shouldRecordObservation = false;
    GetTopicsRequest.Builder mTopicsRequestBuilder = new GetTopicsRequest.Builder();
    mTopicsRequestBuilder.setAdsSdkName(getBaseContext().getPackageName());
    mTopicsRequestBuilder.setShouldRecordObservation(shouldRecordObservation);
    mTopicsManager.getTopics(mTopicsRequestBuilder.build(), mExecutor, mCallback);
}
OutcomeReceiver mCallback = new OutcomeReceiver<GetTopicsResponse, Exception>() {
    @Override
    public void onResult(@NonNull GetTopicsResponse result) {
        //Handle Successful Result
        List<Topic> topicsResult = result.getTopics();
        for (int i = 0; i < topicsResult.size(); i++) {
            Log.i("Topic", topicsResult.get(i).getTopicId().toString());
        }
        if (topicsResult.size() == 0) {
            Log.i("Topic", "Returned Empty");
        }
    }
    @Override
    public void onError(@NonNull Exception error) {
        // Handle error
        Log.i("Topic", "Experienced an error, and did not return successfully");
    }
};

주제 모음 요청

설정이 준비되면 getTopics() 메서드의 결과로 GetTopicsResponse를 수신하도록 호출할 수 있습니다.

Kotlin

mTopicsManager.getTopics(mTopicsRequestBuilder.build(), mExecutor,
        mCallback as OutcomeReceiver<GetTopicsResponse, java.lang.Exception>)

Java

mTopicsManager.getTopics(mTopicsRequestBuilder.build(), mExecutor, mCallback);

위 호출을 통해, 오픈소스 분류 중에서 사용자와 관련된 주제에 해당하는 ID 값이 포함된 Topics 객체의 목록이나 관련 오류가 제공됩니다. 주제는 다음 예와 유사합니다.

/Internet & Telecom/Text & Instant Messaging

반환될 수 있는 주제 목록은 분류를 참고하세요. 이 분류는 오픈소스이므로 이 페이지 상단의 의견 보내기 버튼을 사용하여 변경사항을 제안할 수 있습니다.

테스트

Topics API는 앱 사용에 따라 관련성이 높은 새로운 주제를 제공합니다. 이 초기 버전을 통해 API 동작을 미리 볼 수 있으며 향후 출시를 통해 주제의 품질을 개선할 예정입니다. 최대한의 경험을 얻으려면 getTopics()를 호출하여 주제가 선택되는 방식을 확인하는, 앱이 여러 개 포함된 테스트 환경을 사용하는 것이 좋습니다. GitHub의 SDK 런타임 및 개인 정보 보호 API 저장소에는 Topics API 초기화 및 호출 방법을 보여주는 샘플을 비롯하여 시작하는 데 도움이 되는 개별 Android 스튜디오 프로젝트 집합이 포함되어 있습니다.

주제 계산은 '에포크'가 끝날 때 이루어집니다. 기본적으로 각 에포크는 7일이지만 이 간격을 수정하여 결과를 얻을 수 있습니다. 이 Android 디버그 브리지 셸 명령어는 에포크 길이를 5분으로 단축합니다.

adb shell setprop debug.adservices.topics_epoch_job_period_ms 300000

getprop를 사용하여 topics_epoch_job_period_ms 값을 확인할 수 있습니다.

adb shell getprop debug.adservices.topics_epoch_job_period_ms

에포크 계산을 수동으로 트리거하려면 다음 명령어를 실행하세요.

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

샘플 앱을 사용하는 것 외에도 Colab을 사용하여 주제 분류 기준에 따라 다양한 앱 정보 조합을 테스트할 수 있습니다. 이 Colab을 사용하여 getTopics 호출 시 앱이 얻을 수 있는 다양한 결과를 확인하세요.

제한사항

Topics API의 진행 중인 기능 목록은 출시 노트를 참고하세요.

버그 및 문제 신고

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