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_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?>?
    ) { }

자바

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

이 메서드를 사용하려면 TopicsManager 객체와 주제 데이터를 수신하는 데 필요한 매개변수를 초기화합니다. 매개변수를 초기화하려면 GetTopicsRequest, Executor, 콜백의 OutcomeReceiver를 만듭니다. GetTopicsRequest는 Topics API 데이터를 검색하는 데 필요한 정보를 전달합니다. Executor를 사용하면 getTopics()가 UI 스레드에서 실행되고 OutcomeReceiver 콜백이 결과를 비동기식으로 처리해야 한다는 요구사항을 충족할 수 있습니다. 예를 들면 다음과 같습니다.

Kotlin

private fun topicGetter() {
    val mContext = baseContext
    val mTopicsManager = mContext.getSystemService(TopicsManager::class.java)
    val mExecutor: Executor = Executors.newCachedThreadPool()
    val shouldRecordObservation = true
    val mTopicsRequestBuilder: GetTopicsRequest.Builder = GetTopicsRequest.Builder()
    mTopicsRequestBuilder.setAdsSdkName(baseContext.packageName)
    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")
    }
}

자바

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

자바

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에 알려 주세요.