Key concepts | Set up your development environment | Build an RE SDK | Consume the RE SDK | Testing, and building for distribution |
建構支援執行階段的 SDK
如要建構支援執行階段的 SDK,您必須完成下列步驟:
設定專案結構
建議您將專案分成下列模組:
- 應用程式模組 - 您用來測試及開發 代表您的實際應用程式用戶端所具備的 SDK。您的應用程式應 具備現有廣告程式庫模組 (執行階段感知 SDK) 的依附元件。
- 現有廣告程式庫模組 (執行階段感知 SDK):Android 程式庫模組
其中包含現有的「非執行階段支援」SDK 邏輯是靜態的
。
- 首先,您可以分割功能。舉例來說,您可以使用某些程式碼 ,部分 SDK 可轉送至啟用執行階段的 SDK 將機器學習工作流程自動化
- 支援執行階段的廣告程式庫模組 - 包含支援執行階段的 SDK 商業邏輯您可以在 Android Studio 中建立此類模組,做為 Android 程式庫模組。
- 已啟用執行階段的 ASB 模組:定義要整合
轉換為 ASB 中的 SDK
- 必須使用 com.android.privacy-sandbox-sdk 類型。做法是建立 新目錄
- 這個模組不應包含任何程式碼,且只含有空白的 build.gradle 檔案並將其命名為支援執行階段的廣告程式庫模組。 這個檔案的內容定義於 準備 SDK。
- 請記得在 settings.gradle 檔案和現有的廣告程式庫模組中加入這個模組。
本指南中的專案結構僅供參考 並採用相同的技術原則。您隨時可以建立其他模組,將應用程式和程式庫模組中的程式碼模組化。
準備 SDK
如要為支援執行階段的 SDK 開發作業準備專案,您必須先定義一些工具和程式庫依附元件:
- SDK 執行階段回溯相容性程式庫,為
尚未安裝 Privacy Sandbox 的裝置 (Android 13 以下版本)
(
androidx.privacysandbox.sdkruntime:
) - 支援廣告呈現的 UI 程式庫 (
androidx.privacysandbox.ui:
) - 支援 SDK API 宣告和產生輔助程式的 SDK 開發人員工具 (
androidx.privacysandbox.tools:
)
將此標記新增至專案的 gradle.properties 檔案,以啟用建立支援執行階段的 SDK。
# This enables the Privacy Sandbox for your project on Android Studio. android.experimental.privacysandboxsdk.enable=true android.experimental.privacysandboxsdk.requireServices=false
修改專案的 build.gradle,加入輔助 Jetpack 程式庫和其他依附元件:
// 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 }
請更新支援執行階段的廣告程式庫 (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" }
將 啟用執行階段的 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>') }
更新現有廣告程式庫 (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,請在此階段盡可能遷移業務邏輯、介面和系統面向的函式,但請考慮日後要完全遷移的情況。
如果您需要存取儲存空間、Google Play 廣告 ID 或應用程式組 ID,請參閱以下各節:
在 SDK 中使用 Storage API
SDK 執行階段中的 SDK 將無法再存取、讀取或寫入應用程式的內部儲存空間 反之亦然
SDK 執行階段分配到專屬的內部儲存空間區域,與應用程式分開。
SDK 可以對 SandboxedSdkProvider#getContext()
傳回的 Context
物件使用檔案儲存空間 API,存取這個獨立的內部儲存空間。
SDK 只能使用內部儲存空間,因此只能使用內部儲存空間 API,例如 Context.getFilesDir()
或
「Context.getCacheDir()
」是成功的。如需更多範例,請參閱「從內部儲存空間存取」。
無法透過 SDK 執行階段存取外部儲存空間。呼叫 API 以存取外部儲存空間時,系統會擲回例外狀況或傳回空值。以下列舉一些範例:
- 使用儲存空間存取架構存取檔案會擲回 SecurityException。
getExternalFilsDir()
一律會傳回空值。
您必須使用 SandboxedSdkProvider.getContext()
傳回的 Context
做為儲存空間。在任何其他 Context
物件執行個體 (例如應用程式內容) 上使用檔案儲存 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()
以非同步方式擷取值。
存取 Google Play 服務提供的應用程式組 ID
如果 SDK 需要存取 Google Play 服務提供的應用程式組 ID,請使用
AppSetIdManager#getAppSetId()
:以非同步方式擷取值。
宣告 SDK API
如要讓支援執行階段的 SDK 可在執行階段外存取,您必須定義用戶端 (RA SDK 或用戶端應用程式) 可使用的 API。
使用註解宣告這些介面。
註解
SDK API 必須使用以下項目,在 Kotlin 中宣告為介面和資料類別 以下註解:
註解 | |
---|---|
@PrivacySandboxService |
|
@PrivacySandboxInterface |
|
@PrivacySandboxValue |
|
@PrivacySandboxCallback |
|
您需要在容器內的任何位置定義這些介面和類別 在支援執行階段的廣告程式庫模組中操作。
請參閱下文,瞭解這些註解的用法。
@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
- 加上
@PrivacySandboxValue
註解的 Kotlin 資料類別 - java.lang.List - 清單中的所有元素都必須是支援的資料類型之一
以下是幾項額外注意事項:
- 使用
@PrivacySandboxValue
註解的資料類別不得含有 類型:@PrivacySandboxCallback
- 傳回類型不得包含標示為
@PrivacySandboxCallback
的類型 - 清單不得包含以
@PrivacySandboxInterface
或@PrivacySandboxCallback
註解的類型元素
非同步 API
由於 SDK API 一律會呼叫另外的程序,因此我們必須 確定這些呼叫不會封鎖用戶端的呼叫執行緒。
為此,您必須明確將使用 @PrivacySandboxService
、@PrivacySandboxInterface
和 @PrivacySandboxCallback
註解的介面中所有方法宣告為非同步 API。
您可以透過兩種方式在 Kotlin 中實作非同步 API:
- 使用暫停函式。
- 接受在作業完成時收到通知,或 作業進度中的其他事件。 函式必須是單位。
例外狀況
SDK API 不支援任何形式勾選的例外狀況。
產生的填充碼程式碼會擷取 SDK 擲回的所有執行階段例外狀況,並
會以 PrivacySandboxException
的形式擲回給用戶端,
包裝材料
UI 程式庫
如果您的介面代表 Google Ads,則必須導入 SandboxedUiAdapter
介面,才能為已載入的廣告開啟工作階段功能。
這些工作階段形成用戶端和 SDK 之間的側邊管道, 可達成兩個主要目的:
- 在 UI 發生變更時接收通知。
- 通知用戶端 UI 呈現的任何變更。
由於用戶端可以使用加上 @PrivacySandboxService
註解的介面
與您的 SDK 通訊,即可將任何用來載入廣告的 API 新增至
存取 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 變更時,這個類別也會收到通知。您可以使用這個類別調整廣告大小,或瞭解何時設定有所變更。
活動支援
如要從 Privacy Sandbox 啟動 SDK 擁有的活動,您必須修改 SDK API,才能接收由 UI 程式庫提供的 SdkActivityLauncher
物件。
舉例來說,下列 SDK API 應啟動活動,因此預期 SdkActivityLauncher
參數:
@PrivacySandboxInterface
interface FullscreenAd {
suspend fun show(activityLauncher: SdkActivityLauncher)
}
SDK 進入點
抽象類別 SandboxedSdkProvider
封裝 SDK 執行階段用來與已載入沙箱中 SDK 互動的 API。
支援執行階段的 SDK 必須實作這個抽象類別,以產生 SDK 執行階段的進入點,才能與其通訊。
為了支援回溯相容性,我們引入了下列類別:
SandboxedSdkProviderAdapter
:擴充SandboxedSdkProvider
並處理 SDK 載入要求,無論 SDK 執行階段是否可用。這會在內部使用,在 ASB 模組中宣告。SandboxedSdkProviderCompat
:模擬SandboxedSdkProvider
介面的抽象類別。
填充工具會產生另一個抽象層:使用加上 @PrivacySandboxService
註解的介面,產生名為 AbstractSandboxedSdkProvider
的抽象類別。
此類別會擴充 SandboxedSdkProviderCompat
,並位於與註解介面相同的套件下。
// Auto-generated code.
abstract class AbstractSandboxedSdkProvider : SandboxedSdkProviderCompat {
abstract fun createMySdk(context: Context): MySdk
}
此產生的類別會公開一個抽象工廠方法,
Context
,並預期會傳回進入點註解的介面。
這個方法會以 @PrivacySandboxService
介面命名,並在名稱前方加上 create
。舉例來說,如果介面名稱為 MySdk
,工具就會產生 createMySdk
。
如要完全連結進入點,您必須在支援執行階段的 SDK 中,為產生的 AbstractSandboxedSdkProvider
提供 @PrivacySandboxService
註解介面的實作項目。
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