כשתקראו את מסמכי התיעוד של ארגז החול לפרטיות ב-Android, השתמשו בלחצן תצוגה מקדימה למפתחים או בטא כדי לבחור את גרסת התוכנית שאיתה אתם עובדים, מכיוון שההוראות עשויות להשתנות.
זמן הריצה של ה-SDK מאפשר לערכות SDK לפעול בארגז חול ייעודי שנפרד מהאפליקציה לשיחות. זמן הריצה של ה-SDK מספק אמצעי הגנה ואחריות משופרת לאיסוף נתוני משתמשים. הדבר מתבצע באמצעות סביבת ביצוע מותאמת שמגבילה את זכויות הגישה לנתונים ואת קבוצת ההרשאות המותרות. מידע נוסף על זמן הריצה של ה-SDK זמין בהצעת העיצוב.
ההוראות בדף הזה ינחו אותך בתהליך היצירה של SDK עם זמן ריצה, שמגדיר תצוגה מבוססת-אינטרנט שאפשר לעבד מרחוק לאפליקציה לשיחות.
מגבלות ידועות
נתוני הגרסה כוללים את רשימת היכולות שמתבצעות בזמן הריצה של ה-SDK.
המגבלות הבאות צפויות להיות מתוקנות בגרסה הגדולה הבאה של הפלטפורמה של Android.
- מודעות שמוצגות בתצוגה שניתנת לגלילה. לדוגמה,
RecyclerView
לא פועל כראוי.- ייתכן שתיתקלו ב-jank בעת שינוי הגודל.
- אירועי הגלילה באמצעות מגע של המשתמש לא מועברים לזמן הריצה בצורה תקינה.
- Storage API
- אחסון לכל SDK לא זמין ב-Android 13.
הבעיה הבאה תיפתר בשנת 2023:
- ממשקי ה-API של
getAdId
ו-getAppSetId
עדיין לא פועלים בצורה תקינה כי התמיכה בהם עדיין לא הופעלה.
לפני שמתחילים
לפני שמתחילים, חשוב לבצע את השלבים הבאים:
איך מגדירים את סביבת הפיתוח לארגז החול לפרטיות ב-Android. הכלים לתמיכה בזמן הריצה של ה-SDK נמצאים בפיתוח פעיל, לכן המדריך הזה ידרוש מכם להשתמש בגרסה האחרונה של Canary של Android Studio. תוכלו להריץ את הגרסה הזו של Android Studio במקביל לגרסאות אחרות שבהן אתם משתמשים, אז נשמח לדעת אם הדרישה הזו לא עובדת.
מתקינים תמונת מערכת במכשיר נתמך או מגדירים אמולטור שכולל תמיכה בארגז החול לפרטיות ב-Android.
הגדרת הפרויקט ב-Android Studio
כדי לנסות את זמן הריצה של ה-SDK, עליכם להשתמש במודל שדומה למודל שרת הלקוח. ההבדל העיקרי הוא שאפליקציות (הלקוח) וערכות SDK (ה "שרת") פועלות באותו מכשיר.
- מוסיפים מודול אפליקציה לפרויקט. המודול הזה משמש כלקוח שמניע את ה-SDK.
- במודול האפליקציה, מפעילים את זמן הריצה ל-SDK, מצהירים על ההרשאות הנדרשות ומגדירים שירותי פרסום שספציפיים ל-API.
- הוספת מודול ספרייה אחד לפרויקט. המודול הזה מכיל את קוד ה-SDK שלך.
- מצהירים במודול ה-SDK על ההרשאות הנדרשות. במודול הזה לא צריך להגדיר שירותי מודעות ספציפיים ל-API.
- מסירים את
dependencies
בקובץbuild.gradle
של המודול של הספרייה, שה-SDK לא משתמש בו. ברוב המקרים אפשר להסיר את כל יחסי התלות. כדי לעשות זאת, יוצרים ספרייה חדשה ששמה תואם ל-SDK שלכם. יוצרים באופן ידני מודול חדש עם הסוג
com.android.privacy-sandbox-sdk
. החבילה הזו כלולה בחבילה עם קוד ה-SDK כדי ליצור חבילת APK שאפשר לפרוס במכשיר שלכם. כדי לעשות זאת, אפשר ליצור ספרייה חדשה ששמה תואם ל-SDK שלכם. יש להוסיף קובץbuild.gradle
ריק. התוכן של הקובץ הזה יאוכלס בהמשך המדריך.מוסיפים את קטע הקוד הבא לקובץ
gradle.properties
:android.experimental.privacysandboxsdk.enable=true
מורידים את תמונת האמולטור Tiramisu (רמת תוסף 4) ויוצרים אמולטור עם התמונה הזו שכוללת את חנות Play.
ההגדרה הסופית עשויה להיות שונה מזו שמתוארת בפסקה הקודמת, בהתאם למפתחים של SDK או למפתחי אפליקציות.
מתקינים את ה-SDK במכשיר בדיקה, בדומה לאופן שבו מתקינים אפליקציה, באמצעות Android Studio או גשר ניפוי הבאגים של Android (ADB). כדי לעזור לכם להתחיל, יצרנו אפליקציות לדוגמה בשפות התכנות Kotlin ו-Java, שזמינות במאגר הזה של GitHub. בקובצי README ובקובצי המניפסט יש הערות שמתארות מה צריך לשנות כדי להריץ את הדוגמה בגרסאות יציבות של Android Studio.
הכנת ה-SDK
יצירת ספרייה ברמת המודול באופן ידני. היא משמשת כ-wrapper סביב קוד ההטמעה לצורך בניית ה-APK של ה-SDK. בספרייה החדשה, צריך להוסיף קובץ
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 לעבור הידור (compile), צריך לשנות את השיטות לטיפול במחזור החיים של ה-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
בנוסף לתמיכה במודעות באנר, ארגז החול לפרטיות מחויב לתמוך בנגני וידאו שפועלים בתוך זמן הריצה של ה-SDK.
התהליך לבדיקת נגני וידאו דומה לתהליך הבדיקה של מודעות באנר. משנים את השיטה getView()
בנקודת הכניסה של ה-SDK כך שתכלול נגן וידאו באובייקט View
שהוחזר. בודקים את כל התהליכים של נגן הווידאו שאתם מצפים שנתמכים על ידי ארגז החול לפרטיות. שימו לב: אין תקשורת בין ה-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 יוכלו לגשת לאחסון הפנימי הנפרד הזה באמצעות ממשקי ה-API של אחסון הקבצים באובייקט Context
שהוחזר על ידי SandboxedSdkProvider#getContext()
. ערכות SDK יכולות להשתמש רק באחסון פנימי, ולכן רק ממשקי API של אחסון פנימי, כמו Context.getFilesDir()
או Context.getCacheDir()
, יפעלו. דוגמאות נוספות זמינות במאמר גישה מאחסון פנימי.
אין תמיכה בגישה לאחסון חיצוני מזמן הריצה של ה-SDK. קריאה לממשקי API לגישה לאחסון חיצוני תגרום לחריגה או להחזרת הערך null
. דוגמאות:
- גישה לקבצים באמצעות Storage Access Framework תוביל ל-
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 Services
אם ל-SDK נדרשת גישה למזהה הפרסום שסופק על ידי Google Play Services:
- יש להצהיר על ההרשאה
android.permission.ACCESS_ADSERVICES_AD_ID
במניפסט של ה-SDK. - משתמשים בפונקציה
AdIdManager#getAdId()
כדי לאחזר את הערך באופן אסינכרוני.
גישה למזהה קבוצת האפליקציות שסופק על ידי Google Play Services
אם ל-SDK נדרשת גישה למזהה קבוצת האפליקציות שסופק על ידי Google Play Services:
- משתמשים בפונקציה
AppSetIdManager#getAppSetId()
כדי לאחזר את הערך באופן אסינכרוני.
עדכון אפליקציות לקוח
כדי להפעיל SDK שפועל בזמן הריצה של ה-SDK, צריך לבצע את השינויים הבאים באפליקציית הלקוח לשיחות:
מוסיפים את ההרשאות
INTERNET
ו-ACCESS_NETWORK_STATE
למניפסט של האפליקציה:<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 בזמן הריצה, אחרי שהוא נטען. בדוגמה הבאה, הלקוח משתמש בקריאה חוזרת כדי להמתין עד שה-SDK ייטען בהצלחה, ואז מנסה לעבד תצוגה מפורטת של אתר מה-SDK. הקריאות החוזרות (callback) מוגדרות בשלב מאוחר יותר בשלב הזה.Kotlin
private inner class LoadSdkOutcomeReceiverImpl private constructor() : OutcomeReceiver
{ 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
{ 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
{ 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
{ @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
, הקריאות החוזרות הנחוצות, ולאחר מכן שולחים בקשה לטעינת ה-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); }
כדי לטפל בפנייה שבה תהליך ה-Sandbox של ה-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) כך שתקבלו מידע על סיום ה-Sandbox של ה-SDK, תוכלו להוסיף את השורה הבאה בכל שלב:
Kotlin
mSdkSandboxManager.addSdkSandboxProcessDeathCallback({ obj: Runnable -> obj.run() }, SdkSandboxLifecycleCallbackImpl())
Java
mSdkSandboxManager.addSdkSandboxProcessDeathCallback(Runnable::run, new SdkSandboxLifecycleCallbackImpl());
מכיוון שהמצב של ארגז החול מאבד כשהתהליך מסתיים, יכול להיות שתצוגות שעובדו מרחוק על ידי ה-SDK לא יפעלו כמו שצריך. כדי להמשיך את האינטראקציה עם ערכות ה-SDK, צריך לטעון מחדש את התצוגות האלה כדי שיתחיל תהליך חדש של Sandbox.
מוסיפים תלות במודול ה-SDK ל-
build.gradle
של אפליקציית הלקוח:dependencies { ... implementation project(':<your-sdk-module>') ... }
בדיקת האפליקציות
כדי להריץ את אפליקציית הלקוח, מתקינים את אפליקציית ה-SDK ואת אפליקציית הלקוח במכשיר הבדיקה באמצעות Android Studio או באמצעות שורת הפקודה.
פריסה באמצעות Android Studio
במהלך הפריסה באמצעות Android Studio, מבצעים את השלבים הבאים:
- פותחים את פרויקט Android Studio של אפליקציית הלקוח.
- עוברים אל הפעלה > עריכת הגדרות. יופיע החלון Run/Debug Configuration.
- בקטע אפשרויות הפעלה, מגדירים את האפשרות הפעלה לאפשרות פעילות שצוינה.
- לחצו על תפריט שלוש הנקודות לצד 'פעילות' ובחרו באפשרות הפעילות הראשית של הלקוח.
- לוחצים על Apply (אישור) ואז על OK (אישור).
- לוחצים על Run כדי להתקין את אפליקציית הלקוח ואת ה-SDK במכשיר הבדיקה.
פריסה בשורת הפקודה
במהלך הפריסה באמצעות שורת הפקודה, מבצעים את השלבים שמפורטים ברשימה הבאה.
בקטע הזה ההנחה היא שהשם של מודול האפליקציה של ה-SDK הוא sdk-app
והשם של מודול אפליקציית הלקוח הוא client-app
.
ממסוף של שורת הפקודה, יוצרים את חבילות ה-APK של ה-SDK של ארגז החול לפרטיות:
./gradlew :client-app:buildPrivacySandboxSdkApksForDebug
פלט המיקום של חבילות ה-APK שנוצרו. חבילות ה-APK האלה חתומות באמצעות מפתח ניפוי הבאגים המקומי. הנתיב הזה נדרש בפקודה הבאה.
מתקינים את ה-APK במכשיר:
adb install -t /path/to/your/standalone.apk
ב-Android Studio, לוחצים על הפעלה > עריכת הגדרות. מופיע החלון Run/Debug Configuration.
בקטע אפשרויות התקנה, מגדירים את האפשרות פריסה ל-APK המוגדר כברירת מחדל.
לוחצים על Apply (אישור) ואז על OK (אישור).
לוחצים על הפעלה כדי להתקין את חבילת ה-APK במכשיר הבדיקה.
ניפוי באגים באפליקציות
על מנת לנפות באגים באפליקציית הלקוח, לוחצים על הלחצן Debug ב-Android Studio.
כדי לנפות באגים באפליקציית ה-SDK, נכנסים לקטע Run > Attach to Process, שמופיע מסך קופץ (מוצג למטה). מסמנים את התיבה הצגת כל התהליכים. ברשימה שמופיעה, חפשו תהליך בשם CLIENT_APP_PROCESS_sdk_sandbox
. כדי להתחיל לנפות באגים ב-SDK, יש לבחור באפשרות הזו ולהוסיף נקודות עצירה לקוד של אפליקציית ה-SDK.
הפעלה ועצירה של זמן הריצה של ה-SDK משורת הפקודה
כדי להתחיל את תהליך זמן הריצה של ה-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 ול לקרוא לו זמן ריצה.דיווח על באגים ובעיות
המשוב שלך הוא חלק חיוני מארגז החול לפרטיות ב-Android. דווחו לנו על בעיות שמצאתם או על רעיונות לשיפור ארגז החול לפרטיות ב-Android.
מומלץ עבורכם
- הערה: טקסט הקישור מוצג כאשר JavaScript מושבת
- זמן ריצה ל-SDK
- נתוני גרסה
- Protected Audience API במדריך למפתחים ל-Android