| Key concepts | Set up your development environment | Build an RE SDK | Consume the RE SDK | Testing, and building for distribution |
Tạo một SDK hỗ trợ thời gian chạy
Bạn phải hoàn tất các bước sau để tạo một SDK có thể chạy:
- Thiết lập cấu trúc dự án
- Chuẩn bị các phần phụ thuộc của dự án và mô-đun
- Thêm logic nghiệp vụ SDK
- Xác định các API SDK
- Chỉ định một điểm truy cập cho SDK của bạn
Thiết lập cấu trúc dự án
Bạn nên sắp xếp dự án của mình thành các mô-đun sau:
- Mô-đun ứng dụng – Ứng dụng kiểm thử mà bạn đang dùng để kiểm thử và phát triển SDK, thể hiện những gì mà ứng dụng khách thực tế của bạn sẽ có. Ứng dụng của bạn phải có một phần phụ thuộc vào mô-đun thư viện quảng cáo hiện có (SDK nhận biết thời gian chạy).
- Mô-đun thư viện quảng cáo hiện có (SDK nhận biết thời gian chạy) – Một mô-đun thư viện Android chứa logic SDK "không hỗ trợ thời gian chạy" hiện có, một SDK được liên kết tĩnh.
- Để bắt đầu, bạn có thể chia các chức năng. Ví dụ: một số mã có thể được xử lý bằng SDK hiện có và một số mã có thể được định tuyến đến SDK hỗ trợ thời gian chạy.
- Mô-đun thư viện quảng cáo hỗ trợ thời gian chạy – Chứa logic nghiệp vụ SDK hỗ trợ thời gian chạy của bạn. Bạn có thể tạo thành phần này trên Android Studio dưới dạng một mô-đun thư viện Android.
- Mô-đun ASB hỗ trợ thời gian chạy – Xác định dữ liệu gói để kết hợp mã SDK hỗ trợ thời gian chạy vào một ASB.
- Bạn cần tạo mô-đun này theo cách thủ công bằng loại com.android.privacy-sandbox-sdk. Bạn có thể thực hiện việc này bằng cách tạo một thư mục mới.
- Mô-đun này không được chứa bất kỳ mã nào và chỉ có một tệp build.gradle trống với các phần phụ thuộc vào mô-đun thư viện quảng cáo có thể chạy. Nội dung của tệp này được xác định trong phần Chuẩn bị SDK.
- Nhớ thêm mô-đun này vào tệp settings.gradle và vào mô-đun thư viện quảng cáo hiện có.
Cấu trúc dự án trong hướng dẫn này chỉ là một đề xuất, bạn có thể chọn một cấu trúc khác cho SDK của mình và áp dụng các nguyên tắc kỹ thuật tương tự. Bạn luôn có thể tạo các mô-đun bổ sung khác để mô-đun hoá mã trong ứng dụng và các mô-đun thư viện.
Chuẩn bị SDK của bạn
Để chuẩn bị dự án cho quá trình phát triển SDK có thể chạy, trước tiên, bạn cần xác định một số phần phụ thuộc về công cụ và thư viện:
- Thư viện tương thích ngược với Thời gian chạy SDK, hỗ trợ các thiết bị không có Hộp cát về quyền riêng tư (Android 13 trở xuống) (
androidx.privacysandbox.sdkruntime:) - Thư viện giao diện người dùng để hỗ trợ việc trình bày quảng cáo (
androidx.privacysandbox.ui:) - Các công cụ dành cho nhà phát triển SDK để hỗ trợ khai báo API SDK và tạo shim (
androidx.privacysandbox.tools:)
Thêm cờ này vào tệp gradle.properties của dự án để bật khả năng tạo các SDK hỗ trợ thời gian chạy.
# This enables the Privacy Sandbox for your project on Android Studio. android.experimental.privacysandboxsdk.enable=true android.experimental.privacysandboxsdk.requireServices=falseSửa đổi build.gradle của dự án để thêm các thư viện Jetpack trợ giúp và các phần phụ thuộc khác:
// 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 }Cập nhật tệp build.gradle trong mô-đun thư viện quảng cáo có hỗ trợ thời gian chạy (RE SDK) để thêm các phần phụ thuộc này.
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" }Thay thế tệp build.gradle trong mô-đun ASB có thể bật thời gian chạy bằng nội dung sau:
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>') }Cập nhật tệp build.gradle trong mô-đun thư viện quảng cáo hiện có (RA SDK) để thêm các phần phụ thuộc sau:
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" }
Thêm logic nghiệp vụ SDK
Triển khai logic nghiệp vụ của SDK như bạn thường làm bên trong mô-đun thư viện quảng cáo có bật thời gian chạy.
Nếu bạn có một SDK hiện tại mà bạn đang di chuyển, hãy di chuyển càng nhiều logic nghiệp vụ, giao diện và các chức năng hướng đến hệ thống càng tốt ở giai đoạn này, nhưng hãy tính đến việc di chuyển hoàn toàn trong tương lai.
Nếu bạn cần quyền truy cập vào bộ nhớ, mã nhận dạng cho quảng cáo trên Google Play hoặc mã nhóm ứng dụng, hãy đọc các phần sau:
Sử dụng API lưu trữ trong SDK
Các SDK trong Thời gian chạy SDK không còn truy cập, đọc hoặc ghi trong bộ nhớ trong của ứng dụng nữa và ngược lại.
Thời gian chạy SDK được phân bổ vào vùng bộ nhớ trong riêng biệt, tách biệt với ứng dụng.
Các SDK có thể truy cập vào bộ nhớ trong riêng biệt này thông qua các API lưu trữ tệp trên đối tượng Context do SandboxedSdkProvider#getContext() trả về.
SDK chỉ có thể dùng bộ nhớ trong nên chỉ các API bộ nhớ trong, chẳng hạn như Context.getFilesDir() hoặc Context.getCacheDir(), mới hoạt động. Vui lòng tham khảo thêm ví dụ ở bài viết Quyền truy cập vào bộ nhớ trong.
Không hỗ trợ quyền truy cập vào bộ nhớ ngoài trong Thời gian chạy SDK. Việc gọi các API để truy cập vào bộ nhớ ngoài sẽ gửi một ngoại lệ hoặc trả về giá trị rỗng. Sau đây là một số ví dụ:
- Việc truy cập các tệp bằng Khung truy cập bộ nhớ sẽ tạo ra một SecurityException.
getExternalFilsDir()luôn trả về giá trị rỗng.
Bạn phải sử dụng Context do SandboxedSdkProvider.getContext() trả về để lưu trữ. Việc sử dụng API lưu trữ tệp trên mọi thực thể đối tượng Context nào khác, chẳng hạn như ngữ cảnh của ứng dụng, không được đảm bảo sẽ hoạt động như mong đợi trong mọi tình huống.
Đoạn mã sau đây minh hoạ cách sử dụng bộ nhớ trong Thời gian chạy 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" } }
Trong bộ nhớ trong riêng biệt của từng Thời gian chạy SDK, mỗi SDK có một thư mục bộ nhớ riêng. Bộ nhớ trên mỗi SDK là sự phân tách logic của bộ nhớ trong của Thời gian chạy SDK, giúp tính toán dung lượng bộ nhớ mà mỗi SDK sử dụng.
Tất cả các API bộ nhớ trong trên đối tượng Context đều trả về một đường dẫn bộ nhớ cho từng SDK.
Truy cập vào mã nhận dạng cho quảng cáo do Dịch vụ Google Play cung cấp
Nếu SDK của bạn cần quyền truy cập vào mã nhận dạng cho quảng cáo do Dịch vụ Google Play cung cấp, hãy sử dụng AdIdManager#getAdId() để truy xuất giá trị một cách không đồng bộ.
Truy cập vào mã nhóm ứng dụng do Dịch vụ Google Play cung cấp
Nếu SDK của bạn cần quyền truy cập vào mã nhóm ứng dụng do Dịch vụ Google Play cung cấp, hãy dùng AppSetIdManager#getAppSetId() để truy xuất giá trị một cách không đồng bộ.
Khai báo API SDK
Để có thể truy cập vào SDK có thể chạy bên ngoài thời gian chạy, bạn phải xác định những API mà các ứng dụng (RA SDK hoặc ứng dụng khách) có thể sử dụng.
Sử dụng chú thích để khai báo các giao diện này.
Chú thích
Bạn cần khai báo các API SDK trong Kotlin dưới dạng giao diện và lớp dữ liệu bằng cách sử dụng các chú thích sau:
| Chú thích | |
|---|---|
@PrivacySandboxService |
|
@PrivacySandboxInterface |
|
@PrivacySandboxValue |
|
@PrivacySandboxCallback |
|
Bạn cần xác định các giao diện và lớp này ở bất kỳ đâu bên trong mô-đun thư viện quảng cáo được bật thời gian chạy.
Hãy xem cách sử dụng các chú giải này trong các phần sau.
@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() }
Các kiểu được hỗ trợ
Các API SDK hỗ trợ thời gian chạy hỗ trợ các loại sau:
- Tất cả các kiểu dữ liệu nguyên thuỷ trong ngôn ngữ lập trình Java (chẳng hạn như int, long, char, boolean, v.v.)
- Chuỗi
- Giao diện Kotlin được chú thích bằng
@PrivacySandboxInterfacehoặc@PrivacySandboxCallback - Các lớp dữ liệu Kotlin được chú thích bằng
@PrivacySandboxValue - java.lang.List – tất cả các phần tử trong Danh sách phải thuộc một trong các kiểu dữ liệu được hỗ trợ
Có một số điểm cần lưu ý khác:
- Các lớp dữ liệu được chú thích bằng
@PrivacySandboxValuekhông thể chứa các trường thuộc loại@PrivacySandboxCallback - Kiểu trả về không được chứa các kiểu được chú thích bằng
@PrivacySandboxCallback - Danh sách không được chứa các phần tử thuộc loại được chú thích bằng
@PrivacySandboxInterfacehoặc@PrivacySandboxCallback
API không đồng bộ
Vì các API SDK luôn gọi đến một quy trình riêng biệt, nên chúng ta cần đảm bảo rằng những lệnh gọi này không chặn luồng gọi của ứng dụng.
Để đạt được điều này, tất cả các phương thức trong giao diện được chú thích bằng @PrivacySandboxService, @PrivacySandboxInterface và @PrivacySandboxCallback đều phải được khai báo rõ ràng là API không đồng bộ.
Bạn có thể triển khai các API không đồng bộ trong Kotlin theo 2 cách:
- Sử dụng hàm tạm ngưng.
- Chấp nhận các lệnh gọi lại được thông báo khi thao tác hoàn tất hoặc các sự kiện khác trong quá trình thực hiện thao tác. Loại dữ liệu trả về của hàm phải là Unit.
Ngoại lệ
Các API SDK không hỗ trợ bất kỳ hình thức nào của ngoại lệ đã kiểm tra.
Mã shim được tạo sẽ nắm bắt mọi ngoại lệ thời gian chạy do SDK gửi và gửi chúng dưới dạng PrivacySandboxException cho máy khách cùng với thông tin về nguyên nhân được gói bên trong.
Thư viện giao diện người dùng
Nếu có các giao diện đại diện cho Quảng cáo (chẳng hạn như biểu ngữ), bạn cũng cần triển khai giao diện SandboxedUiAdapter để cho phép mở các phiên cho quảng cáo đã tải.
Các phiên này tạo thành một kênh phụ giữa ứng dụng và SDK, đồng thời đáp ứng hai mục đích chính:
- Nhận thông báo mỗi khi có thay đổi về giao diện người dùng.
- Thông báo cho ứng dụng khách về mọi thay đổi trong cách trình bày giao diện người dùng.
Vì ứng dụng có thể sử dụng giao diện được chú thích bằng @PrivacySandboxService để giao tiếp với SDK của bạn, nên mọi API để tải quảng cáo đều có thể được thêm vào giao diện này.
Khi ứng dụng yêu cầu tải một quảng cáo, hãy tải quảng cáo đó và trả về một phiên bản của giao diện triển khai SandboxedUiAdapter. Điều này cho phép ứng dụng yêu cầu mở các phiên cho quảng cáo đó.
Khi ứng dụng yêu cầu mở một phiên, SDK có thể tạo một khung hiển thị quảng cáo bằng cách sử dụng phản hồi quảng cáo và bối cảnh được cung cấp.
Để đạt được điều này, hãy tạo một lớp triển khai giao diện SandboxedUiAdapter.Session và khi SandboxedUiAdapter.openSession() được gọi, hãy đảm bảo rằng bạn gọi client.onSessionOpened(), truyền một thực thể của lớp Session làm tham số.
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)
}
}
}
Lớp này cũng nhận được thông báo mỗi khi có thay đổi về giao diện người dùng. Bạn có thể sử dụng lớp này để đổi kích thước quảng cáo hoặc biết khi nào cấu hình đã thay đổi, chẳng hạn như vậy.
Tìm hiểu thêm về API trình bày giao diện người dùng trong Thời gian chạy.
Hỗ trợ hoạt động
Để bắt đầu các hoạt động do SDK sở hữu từ Hộp cát về quyền riêng tư, bạn cần sửa đổi API SDK để nhận một đối tượng SdkActivityLauncher, cũng do thư viện giao diện người dùng cung cấp.
Ví dụ: API SDK sau đây sẽ chạy các hoạt động, vì vậy, API này yêu cầu tham số SdkActivityLauncher:
@PrivacySandboxInterface
interface FullscreenAd {
suspend fun show(activityLauncher: SdkActivityLauncher)
}
Điểm truy cập SDK
Lớp trừu tượng SandboxedSdkProvider bao gồm API mà Thời gian chạy SDK dùng để tương tác với các SDK đã tải vào đó.
SDK hỗ trợ thời gian chạy phải triển khai lớp trừu tượng này để tạo điểm truy cập cho thời gian chạy SDK nhằm có thể giao tiếp với SDK đó.
Để hỗ trợ khả năng tương thích ngược, chúng tôi đã giới thiệu các lớp sau:
SandboxedSdkProviderAdapter, mở rộngSandboxedSdkProvidervà xử lý các yêu cầu tải SDK bất kể Thời gian chạy SDK có hoạt động hay không. Đây là một biến được dùng nội bộ, được khai báo trong Mô-đun ASB.SandboxedSdkProviderCompat, một lớp trừu tượng mô phỏng giao diện củaSandboxedSdkProvider.
Tìm hiểu thêm về khả năng tương thích ngược cho Thời gian chạy SDK.
Các công cụ tạo shim sẽ thêm một lớp trừu tượng khác: Chúng tạo ra một lớp trừu tượng có tên là AbstractSandboxedSdkProvider bằng cách sử dụng giao diện mà bạn đã chú giải bằng @PrivacySandboxService.
Lớp này mở rộng SandboxedSdkProviderCompat và nằm trong cùng một gói với giao diện được chú thích của bạn.
// Auto-generated code.
abstract class AbstractSandboxedSdkProvider : SandboxedSdkProviderCompat {
abstract fun createMySdk(context: Context): MySdk
}
Lớp được tạo này hiển thị một phương thức nhà máy trừu tượng duy nhất nhận Context và dự kiến giao diện được chú thích điểm truy cập của bạn sẽ được trả về.
Phương thức này được đặt tên theo giao diện @PrivacySandboxService của bạn, thêm create vào tên. Ví dụ: nếu giao diện của bạn có tên là MySdk, thì các công cụ sẽ tạo createMySdk.
Để kết nối hoàn toàn điểm truy cập, bạn phải cung cấp một cách triển khai giao diện được chú thích @PrivacySandboxService trong SDK hỗ trợ thời gian chạy cho AbstractSandboxedSdkProvider đã tạo.
class MySdkSandboxedSdkProvider : AbstractSandboxedSdkProvider() {
override fun createMySdk(context: Context): MySdk = MySdkImpl(context)
}
Các thay đổi đối với Mô-đun ASB
Bạn cần khai báo tên lớp đủ điều kiện của việc triển khai SandboxedSdkProviderCompat trong trường compatSdkProviderClassName của tệp build.gradle của mô-đun ASB.
Đây là lớp mà bạn đã triển khai ở bước trước và bạn sẽ sửa đổi build.gradle trên Mô-đun ASB như sau:
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"
}
Bước 2: Thiết lập môi trường phát triển Bước 4: Sử dụng SDK có thể chạy