런타임 지원 SDK 빌드 및 사용

1
Key concepts
2
Set up your development environment
3
Build an RE SDK
4
Consume the RE SDK
5
Testing, and building for distribution

런타임 지원 SDK 빌드

런타임 지원 SDK를 빌드하려면 다음 단계를 완료해야 합니다.

  1. 프로젝트 구조 설정하기
  2. 프로젝트 및 모듈 종속 항목 준비
  3. SDK 비즈니스 로직 추가
  4. SDK API 정의
  5. SDK의 진입점 지정

프로젝트 구조 설정

프로젝트를 다음 모듈로 구성하는 것이 좋습니다.

  1. 앱 모듈 - SDK를 테스트하고 개발하는 데 사용 중인 테스트 앱으로, 실제 앱 클라이언트가 보유한 항목을 나타냅니다. 앱은 다음과 같아야 합니다. 기존 광고 라이브러리 모듈 (런타임 인식 SDK)에 대한 종속 항목이 있습니다.
  2. 기존 광고 라이브러리 모듈 (런타임 인식 SDK) - Android 라이브러리 모듈 여기에는 기존 'non-runtime-enabled'가 포함되어 있으며 SDK 로직은 연결된 SDK에 연결됩니다.
    • 먼저 기능을 분할할 수 있습니다. 예를 들어 일부 코드는 기존 SDK에서 처리할 수 있고 일부 코드는 런타임 지원 SDK로 라우팅될 수 있습니다.
  3. 런타임 지원 광고 라이브러리 모듈 - 런타임 지원 SDK가 포함되어 있습니다. 비즈니스 로직에 더 집중할 수 있습니다 이는 Android 스튜디오에서 Android 라이브러리 모듈로 만들 수 있습니다.
  4. 런타임 지원 ASB 모듈: 다음 모듈을 번들로 묶을 패키지 데이터를 정의합니다. 런타임 지원 SDK 코드를 ASB로 옮깁니다.
    • 이 경우 태그를 사용하여 com.android.privacy-sandbox-sdk 유형을 포함하지 마세요. 새 디렉터리를 만들어
    • 이 모듈에는 어떠한 코드도 포함되어서는 안 되며 비어 있는 build.gradle만 포함해야 합니다. 이 파일은 런타임 지원 광고 라이브러리 모듈에 대한 종속 항목을 포함하고 있습니다. 이 파일의 콘텐츠는 SDK를 준비합니다.
    • 이 모듈을 settings.gradle 파일과 포함됩니다

이 가이드의 프로젝트 구조는 제안사항일 뿐입니다. SDK에 다른 구조를 선택하고 동일한 기술 원칙을 적용할 수 있습니다. 언제든지 다른 추가 모듈을 만들어 앱 및 라이브러리 모듈의 코드를 모듈화할 수 있습니다.

SDK 준비

런타임 지원 SDK 개발을 위해 프로젝트를 준비하려면 다음을 실행해야 합니다. 먼저 몇 가지 도구와 라이브러리 종속 항목을 정의합니다.

  • SDK 런타임 이전 버전과의 호환성 라이브러리로, 개인 정보 보호 샌드박스가 없는 기기 (Android 13 이하) (androidx.privacysandbox.sdkruntime:)
  • 광고 표시를 지원하는 UI 라이브러리 (androidx.privacysandbox.ui:)
  • SDK API 선언 및 shim 생성을 지원하는 SDK 개발자 도구(androidx.privacysandbox.tools:)
  1. 프로젝트의 gradle.properties 파일에 이 플래그를 추가하여 런타임 지원 SDK를 만드는 기능을 사용 설정합니다.

    # This enables the Privacy Sandbox for your project on Android Studio.
    android.experimental.privacysandboxsdk.enable=true
    android.experimental.privacysandboxsdk.requireServices=false
    
  2. 도우미 Jetpack 라이브러리와 기타 종속 항목을 포함하도록 프로젝트의 build.gradle을 수정합니다.

    // Top-level build file where you can add configuration options common to all sub-projects/modules.
    buildscript {
        ext.kotlin_version = '1.9.10'
        ext.ksp_version = "$kotlin_version-1.0.13"
        ext.privacy_sandbox_activity_version = "1.0.0-alpha01"
        ext.privacy_sandbox_sdk_runtime_version = "1.0.0-alpha13"
        ext.privacy_sandbox_tools_version = "1.0.0-alpha09"
        ext.privacy_sandbox_ui_version = "1.0.0-alpha09"
        repositories {
            mavenCentral()
        }
        dependencies {
            classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
        }
    }
    
    plugins {
        id 'com.android.application' version '8.4.0-alpha13' apply false
        id 'com.android.library' version '8.4.0-alpha13' apply false
    
        // These two plugins do annotation processing and code generation for the sdk-implementation.
        id 'androidx.privacysandbox.library' version '1.0.0-alpha02' apply false
        id 'com.google.devtools.ksp' version "$ksp_version" apply false
    
        id 'org.jetbrains.kotlin.jvm' version '1.9.10' apply false
    }
    
    task clean(type: Delete) {
        delete rootProject.buildDir
    }
    
  3. 이러한 종속 항목을 포함하도록 런타임 지원 광고 라이브러리(RE SDK) 모듈의 build.gradle 파일을 업데이트합니다.

    dependencies {
        // This allows Android Studio to parse and validate your SDK APIs.
        ksp "androidx.privacysandbox.tools:tools-apicompiler:$privacy_sandbox_tools_version"
    
        // This contains the annotation classes to decorate your SDK APIs.
        implementation "androidx.privacysandbox.tools:tools:$privacy_sandbox_tools_version"
    
        // This is runtime dependency required by the generated server shim code for
        // backward compatibility.
        implementation "androidx.privacysandbox.sdkruntime:sdkruntime-provider:$privacy_sandbox_sdk_runtime_version"
    
        // These are runtime dependencies required by the generated server shim code as
        // they use Kotlin.
        implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.1"
        implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.1'
    
        // This is the core part of the UI library to help with UI notifications.
        implementation "androidx.privacysandbox.ui:ui-core:$privacy_sandbox_ui_version"
    
        // This helps the SDK open sessions for the ad.
        implementation "androidx.privacysandbox.ui:ui-provider:$privacy_sandbox_ui_version"
    
        // This is needed if your SDK implements mediation use cases
        implementation "androidx.privacysandbox.ui:ui-client:$privacy_sandbox_ui_version"
    }
    
  4. 런타임 지원 ASB 모듈의 build.gradle 파일을 다음으로 바꿉니다.

    plugins {
        id 'com.android.privacy-sandbox-sdk'
    }
    
    android {
        compileSdk 34
        minSdk 21
    
        bundle {
            // This is the package name of the SDK that you want to publish.
            // This is used as the public identifier of your SDK.
            // You use this later on to load the runtime-enabled SDK
            packageName = '<package name of your runtime-enabled SDK>'
    
            // This is the version of the SDK that you want to publish.
            // This is used as the public identifier of your SDK version.
            setVersion(1, 0, 0)
    
            // SDK provider defined in the SDK Runtime library.
            // This is an important part of the future backwards compatibility
            // support, most SDKs won't need to change it.
            sdkProviderClassName = "androidx.privacysandbox.sdkruntime.provider.SandboxedSdkProviderAdapter"
    
            // This is the class path of your implementation of the SandboxedSdkProviderCompat class.
            // It's the implementation of your runtime-enabled SDK's entry-point.
            // If you miss this step, your runtime-enabled SDK will fail to load at runtime:
            compatSdkProviderClassName = "<your-sandboxed-sdk-provider-compat-fully-qualified-class-name>"
        }
    }
    
    dependencies {
        // This declares the dependency on your runtime-enabled ad library module.
        include project(':<your-runtime-enabled-ad-library-here>')
    }
    
  5. 기존 광고 라이브러리 (RA SDK) 모듈에서 다음 종속 항목을 포함하도록 build.gradle 파일을 업데이트합니다.

    dependencies {
        // This declares the client's dependency on the runtime-enabled ASB module.
        //  ⚠️ Important: We depend on the ASB module, not the runtime-enabled module.
        implementation project(':<your-runtime-enabled-asb-module-here>')
    
        // Required for backwards compatibility on devices where SDK Runtime is unavailable.
        implementation "androidx.privacysandbox.sdkruntime:sdkruntime-client:$privacy_sandbox_sdk_runtime_version"
    
        // This is required to display banner ads using the SandboxedUiAdapter interface.
        implementation "androidx.privacysandbox.ui:ui-core:$privacy_sandbox_ui_version"
        implementation "androidx.privacysandbox.ui:ui-client:$privacy_sandbox_ui_version"
    
        // This is required to use SDK ActivityLaunchers.
        implementation "androidx.privacysandbox.activity:activity-core:$privacy_sandbox_activity_version"
        implementation "androidx.privacysandbox.activity:activity-client:$privacy_sandbox_activity_version"
    }
    

SDK 비즈니스 로직 추가

SDK의 비즈니스 로직을 SDK의 비즈니스 로직 구현 런타임 지원 광고 라이브러리 모듈을 사용하는 것이 좋습니다

마이그레이션할 기존 SDK가 있는 경우 이 단계에서 비즈니스 로직, 인터페이스, 시스템 연결 기능을 원하는 만큼 이동하되 향후 전체 이전도 고려하세요.

저장소, Google Play 광고 ID 또는 앱 세트 ID에 액세스해야 하는 경우 다음 섹션을 참고하세요.

SDK에서 Storage API 사용

SDK 런타임의 SDK는 더 이상 앱의 내부 저장소에 액세스하거나 이를 읽거나 쓸 수 없으며, 그 반대도 불가능합니다.

SDK 런타임에는 앱과 별도의 자체 내부 저장소 영역이 할당됩니다.

SDK는 SandboxedSdkProvider#getContext()에서 반환된 Context 객체의 File Storage API를 사용하여 이 별도의 내부 저장소에 액세스할 수 있습니다.

SDK는 내부 저장소만 사용할 수 있으므로 Context.getFilesDir() 또는 Context.getCacheDir()와 같은 내부 저장소 API만 작동합니다. 예시 더보기: 내부 저장소에서 액세스:

SDK 런타임에서는 외부 저장소에 액세스할 수 없습니다. 외부 저장소에 액세스하기 위해 API를 호출하면 예외가 발생하거나 null이 반환됩니다. 다음 목록에는 몇 가지 예시가 포함되어 있습니다.

SandboxedSdkProvider.getContext()에서 반환된 Context를 사용하여 저장해야 합니다. 애플리케이션 컨텍스트와 같은 다른 Context 객체 인스턴스에 File Storage API를 사용하면 일부 상황에서는 예상대로 작동하지 않을 수도 있습니다.

다음 코드 스니펫은 SDK 런타임에서 저장소를 사용하는 방법을 보여줍니다.

class SdkServiceImpl(private val context: Context) : SdkService {
    override suspend fun getMessage(): String = "Hello from Privacy Sandbox!"

    override suspend fun createFile(sizeInMb: Int): String {
        val path = Paths.get(
            context.dataDir.path, "file.txt"
        )

        withContext(Dispatchers.IO) {
            Files.deleteIfExists(path)
            Files.createFile(path)
            val buffer = ByteArray(sizeInMb * 1024 * 1024)
            Files.write(path, buffer)
        }

        val file = File(path.toString())
        val actualFileSize: Long = file.length() / (1024 * 1024)
        return "Created $actualFileSize MB file successfully"
    }
}

각 SDK 런타임의 별도 내부 저장소 내에서 각 SDK에는 자체 저장소 디렉터리가 있습니다. SDK별 저장소는 SDK 런타임의 내부 저장소를 논리적으로 분리한 것으로, 각 SDK에서 사용 중인 저장용량을 확인하는 데 도움이 됩니다.

Context 객체의 모든 내부 저장소 API는 각 SDK의 저장소 경로를 반환합니다.

Google Play 서비스에서 제공하는 광고 ID에 액세스

SDK가 Google Play 서비스에서 제공하는 광고 ID에 액세스해야 하는 경우 AdIdManager#getAdId()를 사용하여 값을 비동기적으로 가져옵니다.

<ph type="x-smartling-placeholder">

Google Play 서비스에서 제공하는 앱 세트 ID에 액세스

SDK가 Google Play 서비스에서 제공하는 앱 세트 ID에 액세스해야 하는 경우 AppSetIdManager#getAppSetId(): 값을 비동기식으로 가져옵니다.

SDK API 선언

런타임 지원 SDK가 런타임 외부에서 액세스할 수 있도록 하려면 클라이언트(RA SDK 또는 클라이언트 앱)가 사용할 수 있는 API를 정의해야 합니다.

주석을 사용하여 이러한 인터페이스를 선언합니다.

주석

SDK API는 다음 주석을 사용하여 Kotlin에서 인터페이스 및 데이터 클래스로 선언해야 합니다.

주석
@PrivacySandboxService
  • RE SDK의 진입점을 정의합니다.
  • 고유해야 합니다.
@PrivacySandboxInterface
  • 추가 모듈화 및 인터페이스 노출 사용 설정
  • 여러 인스턴스가 있을 수 있습니다.
@PrivacySandboxValue
  • 프로세스 간에 데이터 전송을 사용 설정합니다.
  • 서로 다른 유형의 여러 값을 반환할 수 있는 불변 구조체와 유사
@PrivacySandboxCallback
  • 콜백을 사용하여 API 선언
  • 클라이언트 코드를 호출하는 백 채널 제공

클래스 내부의 아무 곳에서나 이러한 인터페이스와 클래스를 정의해야 합니다. 런타임 지원 광고 라이브러리 모듈을 사용하는 것이 좋습니다

다음 섹션에서 이러한 주석의 사용법을 참고하세요.

@PrivacySandboxService

@PrivacySandboxService
interface SdkService {
    suspend fun getMessage(): String

    suspend fun createFile(sizeInMb: Int): String

    suspend fun getBanner(request: SdkBannerRequest, requestMediatedAd: Boolean): SdkSandboxedUiAdapter?

    suspend fun getFullscreenAd(): FullscreenAd
}

@PrivacySandboxInterface

@PrivacySandboxInterface
interface SdkSandboxedUiAdapter : SandboxedUiAdapter

@PrivacySandboxValue

@PrivacySandboxValue
data class SdkBannerRequest(
    /** The package name of the app. */
    val appPackageName: String,
    /**
     *  An [SdkActivityLauncher] used to launch an activity when the banner is clicked.
     */
    val activityLauncher: SdkActivityLauncher,
    /**
     * Denotes if a WebView banner ad needs to be loaded.
     */
    val isWebViewBannerAd: Boolean
)

@PrivacySandboxCallback

@PrivacySandboxCallback
interface InAppMediateeSdkInterface {
    suspend fun show()
}

지원되는 유형

런타임 지원 SDK API는 다음 유형을 지원합니다.

  • Java 프로그래밍 언어의 모든 원시 유형 (예: int, long, char, boolean 등)
  • 문자열
  • @PrivacySandboxInterface 또는 @PrivacySandboxCallback로 주석이 추가된 Kotlin 인터페이스
  • @PrivacySandboxValue 주석이 달린 Kotlin 데이터 클래스
  • java.lang.List - List의 모든 요소는 지원되는 데이터 중 하나여야 합니다. 유형

몇 가지 추가 주의사항이 있습니다.

  • @PrivacySandboxValue 주석이 달린 데이터 클래스는 다음 필드를 포함할 수 없습니다. 유형 @PrivacySandboxCallback
  • 반환 유형에 @PrivacySandboxCallback로 주석이 달린 유형이 포함될 수 없음
  • 목록에 @PrivacySandboxInterface 또는 @PrivacySandboxCallback로 주석 처리된 유형의 요소를 포함할 수 없음

비동기 API

SDK API는 항상 별도의 프로세스를 호출하므로 이러한 호출이 클라이언트의 호출 스레드를 차단하지 않도록 합니다.

이를 위해 다음과 같이 주석이 달린 인터페이스의 모든 메서드가 @PrivacySandboxService, @PrivacySandboxInterface, @PrivacySandboxCallback 비동기 API로 명시적으로 선언해야 합니다.

비동기 API는 Kotlin에서 다음 두 가지 방법으로 구현할 수 있습니다.

  1. 정지 함수를 사용합니다.
  2. 작업 완료 시 알림을 받는 콜백을 수락하거나 다른 이벤트를 발생시킵니다. 함수의 반환 유형은 Unit이어야 합니다.
를 통해 개인정보처리방침을 정의할 수 있습니다.

예외

SDK API는 어떠한 형태의 확인된 예외도 지원하지 않습니다.

생성된 shim 코드는 SDK에서 발생한 모든 런타임 예외를 포착하며 다음 정보와 함께 클라이언트에 PrivacySandboxException로 발생합니다. 그 내부에 싸여 있습니다.

UI 라이브러리

배너와 같이 광고를 나타내는 인터페이스가 있는 경우 SandboxedUiAdapter 인터페이스도 구현하여 로드된 광고의 세션 열기를 사용 설정해야 합니다.

이러한 세션은 클라이언트와 SDK 간에 부채널을 형성하며 두 가지 기본 목적을 충족합니다.

  • UI가 변경될 때마다 알림을 받습니다.
  • UI 프레젠테이션의 변경사항을 클라이언트에게 알립니다.
를 통해 개인정보처리방침을 정의할 수 있습니다.

클라이언트는 @PrivacySandboxService로 주석 처리된 인터페이스를 사용하여 SDK와 통신할 수 있으므로 광고를 로드하기 위한 모든 API를 이 인터페이스에 추가할 수 있습니다.

클라이언트가 광고 로드를 요청하면 광고를 로드하고 SandboxedUiAdapter를 구현하는 인터페이스의 인스턴스를 반환합니다. 이렇게 하면 클라이언트가 해당 광고의 열기 세션을 요청할 수 있습니다.

클라이언트가 세션 열기를 요청하면 런타임 지원 SDK가 제공된 광고 응답과 컨텍스트를 사용하여 광고 보기를 만들 수 있습니다.

이렇게 하려면 SandboxedUiAdapter.Session 인터페이스를 구현하는 클래스를 만들고 SandboxedUiAdapter.openSession()가 호출될 때 client.onSessionOpened()를 호출하여 Session 클래스의 인스턴스를 매개변수로 전달해야 합니다.

class SdkSandboxedUiAdapterImpl(
   private val sdkContext: Context,
   private val request: SdkBannerRequest,
) : SdkSandboxedUiAdapter {
   override fun openSession(
       context: Context,
       windowInputToken: IBinder,
       initialWidth: Int,
       initialHeight: Int,
       isZOrderOnTop: Boolean,
       clientExecutor: Executor,
       client: SandboxedUiAdapter.SessionClient
   ) {
       val session = SdkUiSession(clientExecutor, sdkContext, request)
       clientExecutor.execute {
           client.onSessionOpened(session)
       }
   }
}

이 클래스는 UI 변경이 발생할 때마다 알림도 수신합니다. 다음과 같은 작업을 할 수 있습니다. 예를 들어 이 클래스를 사용하여 광고의 크기를 조정하거나 구성이 변경된 시점을 알 수 있습니다.

런타임의 UI Presentation API에 관해 자세히 알아보세요.

활동 지원

개인 정보 보호 샌드박스에서 SDK 소유 활동을 시작하려면 UI 라이브러리에서도 제공하는 SdkActivityLauncher 객체를 수신하도록 SDK API를 수정해야 합니다.

예를 들어 다음 SDK API는 활동을 시작해야 하므로 SdkActivityLauncher 매개변수가 필요합니다.

@PrivacySandboxInterface
interface FullscreenAd {
    suspend fun show(activityLauncher: SdkActivityLauncher)
}

SDK 진입점

추상 클래스 SandboxedSdkProvider SDK 런타임이 로드된 SDK와 상호작용하는 데 사용하는 API를 캡슐화합니다.

런타임 지원 SDK는 이 추상 클래스를 구현하여 SDK 런타임이 통신할 수 있는 진입점을 생성해야 합니다.

이전 버전과의 호환성 지원을 위해 다음 클래스를 도입했습니다.

SDK 런타임의 이전 버전과의 호환성 자세히 알아보기

쉬시미 생성 도구는 또 다른 추상화 레이어를 추가합니다. @PrivacySandboxService 주석이 달린 인터페이스를 사용하여 AbstractSandboxedSdkProvider라는 추상 클래스를 생성합니다.

이 클래스는 SandboxedSdkProviderCompat를 확장하며 주석이 지정된 인터페이스와 동일한 패키지에 있습니다.

// Auto-generated code.
abstract class AbstractSandboxedSdkProvider : SandboxedSdkProviderCompat {
    abstract fun createMySdk(context: Context): MySdk
}

이렇게 생성된 클래스는 Context이며 진입점 주석이 달린 인터페이스가 반환될 것으로 예상됩니다.

이 메서드의 이름은 @PrivacySandboxService 인터페이스에 따라 지정되며 앞에 이름에 create를 추가합니다. 예를 들어 인터페이스 이름이 MySdk이면 도구는 createMySdk를 생성합니다.

진입점을 완전히 연결하려면 런타임 지원 SDK의 @PrivacySandboxService 주석이 달린 인터페이스의 구현을 생성된 AbstractSandboxedSdkProvider에 제공해야 합니다.

class MySdkSandboxedSdkProvider : AbstractSandboxedSdkProvider() {
    override fun createMySdk(context: Context): MySdk = MySdkImpl(context)
}

ASB 모듈 변경사항

ASB 모듈의 build.gradle에 있는 compatSdkProviderClassName 필드에서 SandboxedSdkProviderCompat 구현의 정규화된 클래스 이름을 선언해야 합니다.

이 클래스는 이전 단계에서 구현했으며 ASB 모듈에서 build.gradle을 다음과 같이 수정합니다.

bundle {
    packageName = '<package name of your runtime-enabled SDK>'
    setVersion(1, 0, 0)

    // SDK provider defined in the SDK Runtime library.
    sdkProviderClassName = "androidx.privacysandbox.sdkruntime.provider.SandboxedSdkProviderAdapter"
    // This is the class that extends AbstractSandboxedSdkProvider,
    // MySdkSandboxProvider as per the example provided.
    compatSdkProviderClassName = "com.example.mysdk.MySdkSandboxProvider"
}

2단계: 개발 환경 설정 4단계: 런타임 지원 SDK 사용