ขณะที่คุณอ่าน Privacy Sandbox ใน Android ให้ใช้ปุ่มแสดงตัวอย่างสำหรับนักพัฒนาซอฟต์แวร์ หรือปุ่มเบต้าเพื่อเลือก เวอร์ชันของโปรแกรมที่คุณใช้งานอยู่ เนื่องจากวิธีการอาจแตกต่างกันไป
รันไทม์ของ SDK ทำให้ SDK สามารถทำงานในแซนด์บ็อกซ์เฉพาะที่แยกต่างหากจาก แอปการโทร รันไทม์ของ SDK ให้การป้องกันและการรับประกันที่ดียิ่งขึ้น เกี่ยวกับการรวบรวมข้อมูลผู้ใช้ ซึ่งทำได้โดยผ่านการดำเนินการที่แก้ไขแล้ว สภาพแวดล้อมที่จำกัดสิทธิ์การเข้าถึงข้อมูลและชุดสิทธิ์ที่อนุญาต ดูข้อมูลเพิ่มเติมเกี่ยวกับรันไทม์ของ SDK ในข้อเสนอการออกแบบ
ขั้นตอนในหน้านี้จะแนะนำคุณตลอดขั้นตอนการสร้าง SDK ที่เปิดใช้รันไทม์ซึ่งกำหนดมุมมองบนเว็บที่แสดงผลจากระยะไกลได้ ลงในแอปการโทร
ข้อจำกัดที่ทราบ
ดูรายการความสามารถที่กำลังดำเนินการอยู่สำหรับรันไทม์ของ SDK ได้ที่รุ่น หมายเหตุ
ข้อจำกัดต่อไปนี้คาดว่าจะได้รับการแก้ไขใน Android เวอร์ชันหลักเวอร์ชันถัดไป การเปิดตัวแพลตฟอร์ม
- การแสดงโฆษณาภายในมุมมองที่เลื่อนได้ ตัวอย่างเช่น
RecyclerView
ไม่ ทำงานได้อย่างถูกต้อง- คุณอาจพบปัญหาการกระตุกเมื่อปรับขนาด
- เหตุการณ์การเลื่อนการแตะของผู้ใช้ไม่ส่งผ่านไปยังรันไทม์อย่างถูกต้อง
- API พื้นที่เก็บข้อมูล
- พื้นที่เก็บข้อมูลต่อ SDK ไม่พร้อมใช้งานใน Android 13
ปัญหาต่อไปนี้จะได้รับการแก้ไขในปี 2023
- API
getAdId
และgetAppSetId
ยังทำงานผิดปกติเนื่องจากรองรับ ที่ยังไม่ได้เปิดใช้งาน
ก่อนเริ่มต้น
ก่อนที่จะเริ่มต้น ให้ทำตามขั้นตอนต่อไปนี้
ตั้งค่าสภาพแวดล้อมในการพัฒนาซอฟต์แวร์สำหรับ Privacy Sandbox ใน Android เครื่องมือเพื่อสนับสนุนรันไทม์ของ SDK อยู่ในระหว่างการพัฒนาอย่างต่อเนื่อง คู่มือนี้จะกำหนดให้คุณใช้ Android เวอร์ชัน Canary Studio คุณสามารถเรียกใช้ Android Studio เวอร์ชันนี้พร้อมกันได้ เวอร์ชันที่คุณใช้ ดังนั้นโปรดแจ้งให้เราทราบ หากข้อกำหนดนี้ไม่มีผลกับ ที่ทำงานให้คุณ
ติดตั้งอิมเมจระบบลงในอุปกรณ์ที่รองรับ หรือ ตั้งค่าโปรแกรมจําลองที่รองรับ Privacy Sandbox ใน Android
ตั้งค่าโปรเจ็กต์ใน Android Studio
หากต้องการลองใช้รันไทม์ของ SDK ให้ใช้โมเดลที่คล้ายกับ แบบไคลเอ็นต์-เซิร์ฟเวอร์ ความแตกต่างที่สำคัญคือแอป ( ไคลเอ็นต์) และ SDK ("เซิร์ฟเวอร์") ทำงานในอุปกรณ์เดียวกัน
- เพิ่มโมดูลแอปลงในโปรเจ็กต์ โมดูลนี้ทำหน้าที่เป็นไคลเอ็นต์ที่ ทำหน้าที่ขับเคลื่อน SDK
- ในโมดูลแอป ให้เปิดใช้รันไทม์ของ SDK ประกาศสิทธิ์ที่จำเป็น และ กำหนดค่าบริการโฆษณาเฉพาะ API
- เพิ่มโมดูลไลบรารี 1 รายการในโปรเจ็กต์ โมดูลนี้มีโค้ด SDK ของคุณ
- ในโมดูล SDK ให้ประกาศสิทธิ์ที่จำเป็น คุณไม่จำเป็นต้อง กำหนดค่าบริการโฆษณาเฉพาะ API ในโมดูลนี้
- นำ
dependencies
ในไฟล์build.gradle
ของโมดูลคลังที่ SDK ของคุณไม่ใช้ ในกรณีส่วนใหญ่ คุณจะนำทรัพยากร Dependency ออกทั้งหมดได้ คุณ โดยการสร้างไดเรกทอรีใหม่ที่มีชื่อที่สอดคล้องกับ SDK ของคุณ สร้างโมดูลใหม่ด้วยตนเองโดยใช้
com.android.privacy-sandbox-sdk
ประเภท ซึ่งจะมาพร้อมกับโค้ด SDK สำหรับสร้าง APK ที่สามารถ กับอุปกรณ์ของคุณ คุณสามารถทำได้โดยการสร้างไดเรกทอรีใหม่ที่มี สอดคล้องกับ SDK ของคุณ เพิ่มไฟล์build.gradle
ที่ว่างเปล่า เนื้อหา ของไฟล์นี้จะปรากฏในส่วนหลังของคู่มือนี้เพิ่มข้อมูลโค้ดต่อไปนี้ลงในไฟล์
gradle.properties
android.experimental.privacysandboxsdk.enable=true
ดาวน์โหลดอิมเมจโปรแกรมจำลอง Tiramisu (Extension Level 4) และสร้าง โปรแกรมจำลองที่มีรูปภาพนี้ รวมถึง Play Store
ขึ้นอยู่กับว่าคุณเป็นนักพัฒนา SDK หรือนักพัฒนาแอป คุณอาจมี การตั้งค่าขั้นสุดท้ายแตกต่างจากการตั้งค่าที่อธิบายในย่อหน้าก่อนหน้านี้
ติดตั้ง SDK ในอุปกรณ์ทดสอบ ในทำนองเดียวกับวิธีติดตั้งแอปโดยใช้ Android Studio หรือ Android Debug Bridge (ADB) เราได้สร้างแอปตัวอย่างใน Kotlin และ Java เพื่อช่วยคุณเริ่มต้นใช้งาน ในภาษาโปรแกรม ซึ่งสามารถพบได้ใน ที่เก็บของ GitHub ไฟล์ README และไฟล์ Manifest ความคิดเห็นที่อธิบายสิ่งที่ต้องเปลี่ยนแปลงเพื่อเรียกใช้ตัวอย่างในเวอร์ชันเสถียร ของ Android Studio
เตรียม SDK ของคุณ
สร้างไดเรกทอรีระดับโมดูลด้วยตนเอง โดยนี่จะทำหน้าที่เป็น Wrapper ของ รหัสการติดตั้งใช้งานเพื่อสร้าง SDK APK ในไดเรกทอรีใหม่ ให้เพิ่ม
build.gradle
และเติมข้อมูลด้วยข้อมูลโค้ดต่อไปนี้ ใช้แท็กที่ไม่ซ้ำกัน ของ SDK ที่เปิดใช้รันไทม์ (RE-SDK) และระบุเวอร์ชัน รวม โมดูลคลังของคุณในส่วนdependencies
plugins { id 'com.android.privacy-sandbox-sdk' } android { compileSdk 33 compileSdkExtension 4 minSdk 33 targetSdk 33 namespace = "com.example.example-sdk" bundle { packageName = "com.example.privacysandbox.provider" sdkProviderClassName = "com.example.sdk_implementation.SdkProviderImpl" setVersion(1, 0, 0) } } dependencies { include project(':<your-library-here>') }
สร้างชั้นเรียนในไลบรารีการใช้งานเพื่อใช้เป็นจุดแรกเข้าสำหรับ SDK ของคุณ ชื่อของชั้นเรียนควรจับคู่กับค่าของ
sdkProviderClassName
และขยายเวลาSandboxedSdkProvider
จุดแรกเข้าสำหรับ SDK ของคุณขยาย SandboxedSdkProvider
SandboxedSdkProvider
มีออบเจ็กต์ Context
สำหรับ SDK ของคุณ ซึ่งคุณสามารถ
โดยโทรไปที่ getContext()
ต้องเข้าถึงบริบทนี้เพียงครั้งเดียว
มีการเรียก onLoadSdk()
แล้ว
หากต้องการให้แอป SDK คอมไพล์ คุณต้องลบล้างเมธอดในการจัดการ SDK วงจร:
onLoadSdk()
โหลด SDK ในแซนด์บ็อกซ์ และแจ้งแอปการโทรเมื่อ SDK ถูก พร้อมที่จะจัดการคำขอโดยการส่งอินเทอร์เฟซเป็นออบเจ็กต์
IBinder
ที่ห่อหุ้มอยู่ในออบเจ็กต์SandboxedSdk
ใหม่ คำแนะนำเกี่ยวกับบริการที่มีผลผูกพันจะระบุวิธีต่างๆ ในการมอบIBinder
คุณ มีตัวเลือกในการเลือกวิธีที่เหมาะสม แต่จะต้องสอดคล้องกันสำหรับ SDK และแอปโทรเมื่อใช้ AIDL เป็นตัวอย่าง คุณควรกำหนดไฟล์ AIDL ที่จะใช้นำเสนอ
IBinder
ของคุณ ซึ่งแอปจะแชร์และใช้:// ISdkInterface.aidl interface ISdkInterface { // the public functions to share with the App. int doSomething(); }
getView()
สร้างและตั้งค่าข้อมูลพร็อพเพอร์ตี้สำหรับโฆษณาของคุณ โดยเริ่มต้นการแสดงผลด้วยวิธีเดียวกัน มุมมองอื่นของ Android และแสดงผลมุมมองที่จะแสดงผลจากระยะไกล ตามความกว้างและความสูงที่ระบุเป็นพิกเซล
ข้อมูลโค้ดต่อไปนี้แสดงวิธีลบล้างเมธอดเหล่านี้
Kotlin
class SdkProviderImpl : SandboxedSdkProvider() { override fun onLoadSdk(params: Bundle?): SandboxedSdk { // Returns a SandboxedSdk, passed back to the client. The IBinder used // to create the SandboxedSdk object is used by the app to call into the // SDK. return SandboxedSdk(SdkInterfaceProxy()) } override fun getView(windowContext: Context, bundle: Bundle, width: Int, height: Int): View { val webView = WebView(windowContext) val layoutParams = LinearLayout.LayoutParams(width, height) webView.setLayoutParams(layoutParams) webView.loadUrl("https://developer.android.com/privacy-sandbox") return webView } private class SdkInterfaceProxy : ISdkInterface.Stub() { fun doSomething() { // Implementation of the API. } } }
Java
public class SdkProviderImpl extends SandboxedSdkProvider { @Override public SandboxedSdk onLoadSdk(Bundle params) { // Returns a SandboxedSdk, passed back to the client. The IBinder used // to create the SandboxedSdk object is used by the app to call into the // SDK. return new SandboxedSdk(new SdkInterfaceProxy()); } @Override public View getView(Context windowContext, Bundle bundle, int width, int height) { WebView webView = new WebView(windowContext); LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(width, height); webView.setLayoutParams(layoutParams); webView.loadUrl("https://developer.android.com/privacy-sandbox"); return webView; } private static class SdkInterfaceProxy extends ISdkInterface.Stub { @Override public void doSomething() { // Implementation of the API. } } }
ทดสอบโปรแกรมเล่นวิดีโอในรันไทม์ของ SDK
นอกเหนือจากการสนับสนุนโฆษณาแบนเนอร์แล้ว Privacy Sandbox ยังมุ่งมั่นที่จะ รองรับโปรแกรมเล่นวิดีโอที่ทำงานภายในรันไทม์ของ SDK
ขั้นตอนการทดสอบโปรแกรมเล่นวิดีโอจะคล้ายกับการทดสอบโฆษณาแบนเนอร์ เปลี่ยน
getView()
ของจุดแรกเข้าของ SDK เพื่อรวมโปรแกรมเล่นวิดีโอไว้ใน
แสดงผลออบเจ็กต์ View
รายการ ทดสอบขั้นตอนทั้งหมดของวิดีโอเพลเยอร์ที่คุณคาดว่าจะทำ
ที่ Privacy Sandbox รองรับ โปรดทราบว่าการสื่อสารระหว่าง SDK กับ
แอปไคลเอ็นต์เกี่ยวกับวงจรของวิดีโอ
จึงอยู่นอกเหนือขอบเขตการทำงาน
ยังไม่จำเป็นต้องป้อนคำติชมสำหรับฟังก์ชันนี้
การทดสอบและความคิดเห็นของคุณจะช่วยให้มั่นใจได้ว่ารันไทม์ของ SDK สนับสนุน โปรแกรมเล่นวิดีโอที่คุณต้องการได้ด้วย
ข้อมูลโค้ดต่อไปนี้แสดงวิธีการแสดงผลวิดีโอแบบง่าย โหลดจาก URL
Kotlin
class SdkProviderImpl : SandboxedSdkProvider() { override fun getView(windowContext: Context, bundle: Bundle, width: Int, height: Int): View { val videoView = VideoView(windowContext) val layoutParams = LinearLayout.LayoutParams(width, height) videoView.setLayoutParams(layoutParams) videoView.setVideoURI(Uri.parse("https://test.website/video.mp4")) videoView.setOnPreparedListener { mp -> mp.start() } return videoView } }
Java
public class SdkProviderImpl extends SandboxedSdkProvider { @Override public View getView(Context windowContext, Bundle bundle, int width, int height) { VideoView videoView = new VideoView(windowContext); LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(width, height); videoView.setLayoutParams(layoutParams); videoView.setVideoURI(Uri.parse("https://test.website/video.mp4")); videoView.setOnPreparedListener(mp -> { mp.start(); }); return videoView; } }
การใช้ API พื้นที่เก็บข้อมูลใน SDK ของคุณ
SDK ในรันไทม์ของ SDK จะเข้าถึง อ่าน หรือเขียนในแอปไม่ได้อีกต่อไป ที่จัดเก็บข้อมูลภายในและในทางกลับกันด้วย รันไทม์ของ SDK จะได้รับการจัดสรรพื้นที่เก็บข้อมูลภายในของตนเอง ซึ่งก็คือ แยกต่างหากจากแอป
SDK จะสามารถเข้าถึงที่จัดเก็บข้อมูลภายในที่แยกต่างหากนี้โดยใช้ไฟล์
Storage API ในออบเจ็กต์ Context
ที่แสดงผลโดย
SandboxedSdkProvider#getContext()
SDK สามารถใช้ได้เฉพาะที่จัดเก็บข้อมูลภายในเท่านั้น จึงมีเพียง
API ที่จัดเก็บข้อมูลภายใน เช่น Context.getFilesDir()
หรือ
Context.getCacheDir()
จะใช้งานได้ ดูตัวอย่างเพิ่มเติมใน
เข้าถึงจากที่จัดเก็บข้อมูลภายใน
ไม่รองรับการเข้าถึงที่จัดเก็บข้อมูลภายนอกจากรันไทม์ของ SDK กำลังเรียก API ไปยัง
การเข้าถึงที่จัดเก็บข้อมูลภายนอกจะส่งกลับข้อยกเว้นหรือแสดงผล null
หลายรายการ
ตัวอย่าง:
- การเข้าถึงไฟล์โดยใช้เฟรมเวิร์กการเข้าถึงพื้นที่เก็บข้อมูลจะทำให้
SecurityException
getExternalFilsDir()
จะส่งกลับnull
เสมอ
ใน Android 13 SDK ทั้งหมดในรันไทม์ของ SDK จะแชร์ที่จัดเก็บข้อมูลภายใน ที่จัดสรรสำหรับรันไทม์ของ SDK แล้ว พื้นที่เก็บข้อมูลจะยังคงอยู่จนกว่าแอปไคลเอ็นต์จะ ถอนการติดตั้งแล้ว หรือเมื่อล้างข้อมูลแอปไคลเอ็นต์แล้ว
คุณต้องใช้ Context
ที่ SandboxedSdkProvider.getContext()
ส่งคืนสำหรับ
พื้นที่เก็บข้อมูล การใช้ API พื้นที่เก็บไฟล์กับอินสแตนซ์ออบเจ็กต์ Context
อื่นๆ เช่น
เราไม่รับประกันว่าบริบทของแอปพลิเคชันนั้นจะทำงานตามที่คาดไว้ในทุกสถานการณ์
หรือในอนาคต
ข้อมูลโค้ดต่อไปนี้แสดงวิธีใช้พื้นที่เก็บข้อมูลในรันไทม์ของ SDK
Kotlin
private static class SdkInterfaceStorage extends ISdkInterface.Stub { override fun doSomething() { val filename = "myfile" val fileContents = "content" try { getContext().openFileOutput(filename, Context.MODE_PRIVATE).use { it.write(fileContents.toByteArray()) } catch (e: Exception) { throw RuntimeException(e) } } } }
Java
private static class SdkInterfaceStorage extends ISdkInterface.Stub { @Override public void doSomething() { final filename = "myFile"; final String fileContents = "content"; try (FileOutputStream fos = getContext().openFileOutput(filename, Context.MODE_PRIVATE)) { fos.write(fileContents.toByteArray()); } catch (Exception e) { throw new RuntimeException(e); } } }
พื้นที่เก็บข้อมูลต่อ SDK
SDK แต่ละรายการจะมีพื้นที่เก็บข้อมูลภายในแยกกันสำหรับรันไทม์ของ SDK แต่ละรายการ ไดเรกทอรีพื้นที่เก็บข้อมูล พื้นที่เก็บข้อมูลต่อ SDK เป็นการแยกเชิงตรรกะของรันไทม์ SDK ที่จัดเก็บข้อมูลภายใน ซึ่งช่วยให้ทราบว่า SDK แต่ละรายการใช้พื้นที่เก็บข้อมูลไปเท่าใด
ใน Android 13 มี API เพียงรายการเดียวที่ส่งคืนเส้นทางไปยังพื้นที่เก็บข้อมูลต่อ SDK ดังนี้
Context#getDataDir()
ใน Android 14 API พื้นที่เก็บข้อมูลภายในทั้งหมดในออบเจ็กต์ Context
จะแสดงผล
ของ SDK แต่ละรายการ คุณอาจต้องเปิดใช้ฟีเจอร์นี้โดยเรียกใช้
คำสั่ง adb ต่อไปนี้
adb shell device_config put adservices sdksandbox_customized_sdk_context_enabled true
เข้าถึงรหัสโฆษณาที่จัดหาโดยบริการ Google Play
หาก SDK ของคุณต้องการเข้าถึงรหัสโฆษณาที่บริการ Google Play ให้ไว้ ให้ทำดังนี้
- ประกาศสิทธิ์
android.permission.ACCESS_ADSERVICES_AD_ID
ในไฟล์ Manifest ของ SDK - ใช้
AdIdManager#getAdId()
เพื่อดึงค่าแบบไม่พร้อมกัน
เข้าถึงรหัสชุดแอปที่ได้รับจากบริการ Google Play
หาก SDK ของคุณต้องการเข้าถึงรหัสชุดแอปจากบริการ Google Play ให้ทำดังนี้
- ใช้
AppSetIdManager#getAppSetId()
เพื่อดึงค่าแบบไม่พร้อมกัน
อัปเดตแอปไคลเอ็นต์
หากต้องการเรียกใช้ SDK ที่ทำงานอยู่ในรันไทม์ของ SDK ให้ทำดังนี้ การเปลี่ยนแปลงของแอปไคลเอ็นต์การโทร
เพิ่มสิทธิ์
INTERNET
และACCESS_NETWORK_STATE
ไปยัง ไฟล์ Manifest ของแอป<uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
ในกิจกรรมของแอปที่มีโฆษณา ให้ประกาศการอ้างอิง
SdkSandboxManager
เป็นบูลีนเพื่อดูว่า SDK โหลดแล้วหรือไม่ และ ออบเจ็กต์SurfaceView
สำหรับการแสดงผลระยะไกลKotlin
private lateinit var mSdkSandboxManager: SdkSandboxManager private lateinit var mClientView: SurfaceView private var mSdkLoaded = false companion object { private const val SDK_NAME = "com.example.privacysandbox.provider" }
Java
private static final String SDK_NAME = "com.example.privacysandbox.provider"; private SdkSandboxManager mSdkSandboxManager; private SurfaceView mClientView; private boolean mSdkLoaded = false;
ตรวจสอบว่ากระบวนการรันไทม์ของ SDK พร้อมใช้งานในอุปกรณ์หรือไม่
ตรวจสอบค่าคงที่
SdkSandboxState
(getSdkSandboxState()
)SDK_SANDBOX_STATE_ENABLED_PROCESS_ISOLATION
หมายความว่ารันไทม์ของ SDK คือ พร้อมใช้งานตรวจสอบว่าโทรหา
loadSdk()
เรียบร้อยแล้ว ถือว่าประสบความสำเร็จหากมี ไม่มีข้อยกเว้น และตัวรับเป็นอินสแตนซ์SandboxedSdk
โทรหา
loadSdk()
จากเบื้องหน้า ถ้ามีการเรียกจาก พื้นหลัง จะมีการส่งSecurityException
ตรวจสอบ
OutcomeReceiver
สำหรับอินสแตนซ์SandboxedSdk
เพื่อยืนยันว่ามีการส่งLoadSdkException
หรือไม่ ข้อยกเว้นระบุว่า รันไทม์ของ SDK อาจไม่พร้อมใช้งาน
หากเรียกใช้
SdkSandboxState
หรือloadSdk
ไม่สำเร็จ รันไทม์ของ SDK จะไม่อัปเดต และการเรียกใช้ควรเป็นทางเลือกสำหรับ SDK ที่มีอยู่กำหนดคลาส Callback โดยการใช้
OutcomeReceiver
เพื่อโต้ตอบ กับ SDK ในรันไทม์หลังจากโหลดเสร็จแล้ว ในรายการต่อไปนี้ ตัวอย่างเช่น ไคลเอ็นต์ใช้ Callback เพื่อรอจนกว่า SDK จะโหลดแล้ว สำเร็จ แล้วพยายามแสดงผลมุมมองเว็บจาก SDK Callback จะกำหนดภายหลังในขั้นตอนนี้Kotlin
private inner class LoadSdkOutcomeReceiverImpl private constructor() : OutcomeReceiver<SandboxedSdk?, LoadSdkException?> { override fun onResult(sandboxedSdk: SandboxedSdk) { mSdkLoaded = true val binder: IBinder = sandboxedSdk.getInterface() if (!binderInterface.isPresent()) { // SDK is not loaded anymore. return } val sdkInterface: ISdkInterface = ISdkInterface.Stub.asInterface(binder) sdkInterface.doSomething() Handler(Looper.getMainLooper()).post { val bundle = Bundle() bundle.putInt(SdkSandboxManager.EXTRA_WIDTH_IN_PIXELS, mClientView.getWidth()) bundle.putInt(SdkSandboxManager.EXTRA_HEIGHT_IN_PIXELS, mClientView.getHeight()) bundle.putInt(SdkSandboxManager.EXTRA_DISPLAY_ID, display!!.displayId) bundle.putInt(SdkSandboxManager.EXTRA_HOST_TOKEN, mClientView.getHostToken()) mSdkSandboxManager!!.requestSurfacePackage( SDK_NAME, bundle, { obj: Runnable -> obj.run() }, RequestSurfacePackageOutcomeReceiverImpl()) } } override fun onError(error: LoadSdkException) { // Log or show error. } }
Java
import static android.app.sdksandbox.SdkSandboxManager.EXTRA_DISPLAY_ID; import static android.app.sdksandbox.SdkSandboxManager.EXTRA_HEIGHT_IN_PIXELS; import static android.app.sdksandbox.SdkSandboxManager.EXTRA_HOST_TOKEN; import static android.app.sdksandbox.SdkSandboxManager.EXTRA_WIDTH_IN_PIXELS; private class LoadSdkOutcomeReceiverImpl implements OutcomeReceiver<LoadSdkResponse, LoadSdkException> { private LoadSdkOutcomeReceiverImpl() {} @Override public void onResult(@NonNull SandboxedSdk sandboxedSdk) { mSdkLoaded = true; IBinder binder = sandboxedSdk.getInterface(); if (!binderInterface.isPresent()) { // SDK is not loaded anymore. return; } ISdkInterface sdkInterface = ISdkInterface.Stub.asInterface(binder); sdkInterface.doSomething(); new Handler(Looper.getMainLooper()).post(() -> { Bundle bundle = new Bundle(); bundle.putInt(EXTRA_WIDTH_IN_PIXELS, mClientView.getWidth()); bundle.putInt(EXTRA_HEIGHT_IN_PIXELS, mClientView.getHeight()); bundle.putInt(EXTRA_DISPLAY_ID, getDisplay().getDisplayId()); bundle.putInt(EXTRA_HOST_TOKEN, mClientView.getHostToken()); mSdkSandboxManager.requestSurfacePackage( SDK_NAME, bundle, Runnable::run, new RequestSurfacePackageOutcomeReceiverImpl()); }); } @Override public void onError(@NonNull LoadSdkException error) { // Log or show error. } }
วิธีกลับไปมุมมองระยะไกลจาก SDK ในรันไทม์ขณะโทร
requestSurfacePackage()
ใช้อินเทอร์เฟซOutcomeReceiver<Bundle, RequestSurfacePackageException>
:Kotlin
private inner class RequestSurfacePackageOutcomeReceiverImpl : OutcomeReceiver<Bundle, RequestSurfacePackageException> { fun onResult(@NonNull result: Bundle) { Handler(Looper.getMainLooper()) .post { val surfacePackage: SurfacePackage = result.getParcelable( EXTRA_SURFACE_PACKAGE, SurfacePackage::class.java) mRenderedView.setChildSurfacePackage(surfacePackage) mRenderedView.setVisibility(View.VISIBLE) } } fun onError(@NonNull error: RequestSurfacePackageException?) { // Error handling } }
Java
import static android.app.sdksandbox.SdkSandboxManager.EXTRA_SURFACE_PACKAGE; private class RequestSurfacePackageOutcomeReceiverImpl implements OutcomeReceiver<Bundle, RequestSurfacePackageException> { @Override public void onResult(@NonNull Bundle result) { new Handler(Looper.getMainLooper()) .post( () -> { SurfacePackage surfacePackage = result.getParcelable( EXTRA_SURFACE_PACKAGE, SurfacePackage.class); mRenderedView.setChildSurfacePackage(surfacePackage); mRenderedView.setVisibility(View.VISIBLE); }); } @Override public void onError(@NonNull RequestSurfacePackageException error) { // Error handling } }
เมื่อแสดงมุมมองเสร็จแล้ว อย่าลืมปล่อย
SurfacePackage
โดยโทรหา:surfacePackage.notifyDetachedFromWindow()
ใน
onCreate()
ให้เริ่มต้นSdkSandboxManager
ซึ่งเป็น Callback ที่จำเป็น แล้วส่งคำขอเพื่อโหลด SDK โดยทำดังนี้Kotlin
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) mSdkSandboxManager = applicationContext.getSystemService( SdkSandboxManager::class.java ) mClientView = findViewById(R.id.rendered_view) mClientView.setZOrderOnTop(true) val loadSdkCallback = LoadSdkCallbackImpl() mSdkSandboxManager.loadSdk( SDK_NAME, Bundle(), { obj: Runnable -> obj.run() }, loadSdkCallback ) }
Java
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mSdkSandboxManager = getApplicationContext().getSystemService( SdkSandboxManager.class); mClientView = findViewById(R.id.rendered_view); mClientView.setZOrderOnTop(true); LoadSdkCallbackImpl loadSdkCallback = new LoadSdkCallbackImpl(); mSdkSandboxManager.loadSdk( SDK_NAME, new Bundle(), Runnable::run, loadSdkCallback); }
วิธีจัดการกรณีที่กระบวนการแซนด์บ็อกซ์ SDK หยุดโดยไม่คาดคิด กำหนดการใช้งานสำหรับอินเทอร์เฟซ
SdkSandboxProcessDeathCallback
ดังนี้Kotlin
private inner class SdkSandboxLifecycleCallbackImpl() : SdkSandboxProcessDeathCallback { override fun onSdkSandboxDied() { // The SDK runtime process has terminated. To bring back up the // sandbox and continue using SDKs, load the SDKs again. val loadSdkCallback = LoadSdkOutcomeReceiverImpl() mSdkSandboxManager.loadSdk( SDK_NAME, Bundle(), { obj: Runnable -> obj.run() }, loadSdkCallback) } }
Java
private class SdkSandboxLifecycleCallbackImpl implements SdkSandboxProcessDeathCallback { @Override public void onSdkSandboxDied() { // The SDK runtime process has terminated. To bring back up // the sandbox and continue using SDKs, load the SDKs again. LoadSdkOutcomeReceiverImpl loadSdkCallback = new LoadSdkOutcomeReceiverImpl(); mSdkSandboxManager.loadSdk( SDK_NAME, new Bundle(), Runnable::run, loadSdkCallback); } }
วิธีลงทะเบียน Callback นี้เพื่อรับข้อมูลว่าแซนด์บ็อกซ์ SDK เมื่อใด ยุติการใช้งานแล้ว คุณสามารถเพิ่มบรรทัดต่อไปนี้ได้ทุกเมื่อ
Kotlin
mSdkSandboxManager.addSdkSandboxProcessDeathCallback({ obj: Runnable -> obj.run() }, SdkSandboxLifecycleCallbackImpl())
Java
mSdkSandboxManager.addSdkSandboxProcessDeathCallback(Runnable::run, new SdkSandboxLifecycleCallbackImpl());
เนื่องจากสถานะของแซนด์บ็อกซ์จะสูญหายไปเมื่อกระบวนการสิ้นสุดลง การดู ที่แสดงผลจากระยะไกลโดย SDK อาจทำงานไม่ถูกต้องอีกต่อไป หากต้องการโต้ตอบกับ SDK ต่อไป ต้องโหลดมุมมองเหล่านี้อีกครั้งเพื่อให้ จะเป็นการเริ่มกระบวนการแซนด์บ็อกซ์ใหม่
เพิ่มทรัพยากร Dependency ของโมดูล SDK ในแอปไคลเอ็นต์
build.gradle
:dependencies { ... implementation project(':<your-sdk-module>') ... }
ทดสอบแอป
หากต้องการเรียกใช้แอปไคลเอ็นต์ ให้ติดตั้งแอป SDK และแอปไคลเอ็นต์ลงในอุปกรณ์ทดสอบ โดยใช้ Android Studio หรือบรรทัดคำสั่ง
ติดตั้งใช้งานผ่าน Android Studio
เมื่อติดตั้งใช้งานผ่าน Android Studio ให้ทำตามขั้นตอนต่อไปนี้
- เปิดโปรเจ็กต์ Android Studio สำหรับแอปไคลเอ็นต์
- ไปที่เรียกใช้ > แก้ไขการกำหนดค่า หน้าต่างการกำหนดค่าเรียกใช้/แก้ไขข้อบกพร่อง จะปรากฏขึ้น
- ในส่วนตัวเลือกการเปิดตัว ให้ตั้งค่าการเปิดตัวเป็นกิจกรรมที่ระบุ
- คลิกเมนู 3 จุดข้างกิจกรรม แล้วเลือกกิจกรรมหลัก สำหรับลูกค้าของคุณ
- คลิกใช้ แล้วคลิกตกลง
- คลิกเรียกใช้
เพื่อติดตั้งแอปไคลเอ็นต์และ SDK ในอุปกรณ์ทดสอบ
ทำให้ใช้งานได้ในบรรทัดคำสั่ง
เมื่อทำให้ใช้งานได้โดยใช้บรรทัดคำสั่ง ให้ทำตามขั้นตอนในรายการต่อไปนี้
ส่วนนี้จะถือว่าชื่อของโมดูลแอป SDK ของคุณคือ sdk-app
และ
ชื่อของโมดูลแอปไคลเอ็นต์คือ client-app
จากเทอร์มินัลบรรทัดคำสั่ง ให้สร้าง APK SDK ของ Privacy Sandbox โดยทำดังนี้
./gradlew :client-app:buildPrivacySandboxSdkApksForDebug
การดำเนินการนี้จะแสดงผลตำแหน่งสำหรับ APK ที่สร้างขึ้น APK เหล่านี้รับรองด้วย คีย์การแก้ไขข้อบกพร่องในเครื่อง และต้องใช้เส้นทางนี้ในคำสั่งถัดไป
ติดตั้ง APK ในอุปกรณ์
adb install -t /path/to/your/standalone.apk
ใน Android Studio คลิกเรียกใช้ > แก้ไขการกำหนดค่า ฟังก์ชันเรียกใช้/แก้ไขข้อบกพร่อง หน้าต่างการกำหนดค่าจะปรากฏขึ้น
ในส่วนตัวเลือกการติดตั้ง ให้ตั้งค่าทำให้ใช้งานได้เป็น APK เริ่มต้น
คลิกใช้ แล้วคลิกตกลง
คลิก Run เพื่อติดตั้ง Bundle APK ในอุปกรณ์ทดสอบ
แก้ไขข้อบกพร่องของแอป
หากต้องการแก้ไขข้อบกพร่องของแอปไคลเอ็นต์ ให้คลิกแก้ไขข้อบกพร่อง
ใน Android Studio
หากต้องการแก้ไขข้อบกพร่องของแอป SDK ให้ไปที่เรียกใช้ > Attach to Process ซึ่งแสดงป๊อปอัป
หน้าจอ (แสดงด้านล่าง) เลือกช่องแสดงกระบวนการทั้งหมด ในรายการที่
ปรากฏขึ้น ให้มองหากระบวนการที่ชื่อ CLIENT_APP_PROCESS_sdk_sandbox
เลือกตัวเลือกนี้และเพิ่มเบรกพอยท์ในโค้ดของแอป SDK ไปยัง
เริ่มแก้ไขข้อบกพร่อง SDK ของคุณ
![ขั้นตอนของแอป SDK จะปรากฏในมุมมองรายการบริเวณด้านล่าง
ของกล่องโต้ตอบ](https://developers.google.cn/static/privacy-sandbox/assets/images/android/debug-sdk-app.png?authuser=19&hl=th)
เริ่มและหยุดรันไทม์ของ SDK จากบรรทัดคำสั่ง
ใช้คำสั่ง Shell ต่อไปนี้เพื่อเริ่มขั้นตอนรันไทม์ของ SDK สำหรับแอป
adb shell cmd sdk_sandbox start [--user <USER_ID> | current] <CLIENT_APP_PACKAGE>
ในทำนองเดียวกัน หากต้องการหยุดกระบวนการรันไทม์ของ SDK ให้เรียกใช้คำสั่งนี้
adb shell cmd sdk_sandbox stop [--user <USER_ID> | current] <CLIENT_APP_PACKAGE>
ข้อจำกัด
ดูรายการความสามารถที่กำลังดำเนินการอยู่สำหรับรันไทม์ของ SDK ได้ที่ บันทึกประจำรุ่น
ตัวอย่างโค้ด
ที่เก็บรันไทม์ของ SDK และที่เก็บ API ที่รักษาความเป็นส่วนตัว ใน GitHub มีชุดโปรเจ็กต์ Android Studio แต่ละโปรเจ็กต์ที่จะช่วยให้คุณได้รับ ที่เริ่มใช้งาน ซึ่งรวมถึงตัวอย่างที่สาธิตวิธีเริ่มต้นและเรียกใช้ SDK รันไทม์รายงานข้อบกพร่องและปัญหา
ความคิดเห็นของคุณเป็นส่วนสำคัญของ Privacy Sandbox ใน Android โปรดแจ้งให้เราทราบ ของปัญหาที่คุณพบหรือแนวคิดในการปรับปรุง Privacy Sandbox ใน Android
แนะนำสำหรับคุณ
- หมายเหตุ: ข้อความลิงก์จะแสดงเมื่อ JavaScript ปิดอยู่
- รันไทม์ของ SDK
- บันทึกประจำรุ่น
- Protected Audience API ในคู่มือนักพัฒนาซอฟต์แวร์ Android