أثناء الاطّلاع على مستندات "مبادرة حماية الخصوصية" على Android، استخدِم الزر معاينة المطوّر أو الزر إصدار تجريبي لاختيار إصدار البرنامج الذي تعمل معه، لأنّ التعليمات قد تختلف.
يسمح "وقت تشغيل SDK" بتشغيل حِزم SDK في وضع حماية مخصَّص ومنفصل عن تطبيق الاتصال. ويوفّر "وقت تشغيل SDK" إجراءات حماية وضمانات محسّنة بشأن جمع بيانات المستخدمين. ويتم ذلك من خلال بيئة تنفيذ معدَّلة تحدّ من حقوق الوصول إلى البيانات ومجموعة الأذونات المسموح بها. اطّلِع على مزيد من المعلومات عن "وقت تشغيل SDK" في اقتراح التصميم.
ترشدك الخطوات الواردة في هذه الصفحة خلال عملية إنشاء حزمة تطوير برامج (SDK) يتم تفعيلها في وقت التشغيل وتحدّد عرضًا مستنِدًا إلى الويب يمكن عرضه عن بُعد في تطبيق اتصال.
القيود المعروفة
للحصول على قائمة بالإمكانات قيد التقدم في "وقت تشغيل SDK"، يمكنك الاطّلاع على ملاحظات الإصدار.
من المتوقع إصلاح القيود التالية في الإصدار الرئيسي التالي لنظام Android الأساسي.
- عرض الإعلانات ضمن شاشة عرض قابلة للتمرير على سبيل المثال، لا يعمل
RecyclerView
بشكل صحيح.- قد يحدث التشويش عند تغيير الحجم.
- لا يتم تمرير أحداث التمرير باللمس للمستخدم إلى وقت التشغيل بشكل صحيح.
- واجهة برمجة التطبيقات Storage
- لا تتوفّر مساحة التخزين لكل حزمة تطوير برامج (SDK) في Android 13.
سيتم حلّ المشكلة التالية في عام 2023:
- لا تعمل واجهتا برمجة التطبيقات
getAdId
وgetAppSetId
بشكل صحيح لأنّه لم يتم بعد تفعيل إمكانية استخدامهما.
قبل البدء
قبل البدء، أكمل الخطوات التالية:
إعداد بيئة تطوير "مبادرة حماية الخصوصية" على Android لا تزال الأدوات اللازمة لدعم "وقت تشغيل SDK" قيد التطوير النشط، لذا سيتطلب منك هذا الدليل استخدام أحدث إصدار Canary من Android استوديو. يمكنك تشغيل هذا الإصدار من "استوديو Android" بالتوازي مع الإصدارات الأخرى التي تستخدمها، لذا يُرجى إعلامنا إذا لم يكن هذا الشرط مناسبًا لك.
يمكنك إما تثبيت صورة نظام على جهاز متوافق أو إعداد محاكي يتيح استخدام "مبادرة حماية الخصوصية" على Android.
إعداد مشروعك في "استوديو Android"
لتجربة "وقت تشغيل SDK"، يمكنك استخدام نموذج مشابه لنموذج خادم العميل. يتمثل الاختلاف الرئيسي في أن التطبيقات (العميل) وحزم SDK ("الخادم") تعمل على نفس الجهاز.
- أضِف وحدة تطبيق إلى مشروعك. هذه الوحدة هي البرنامج الذي يشغِّل حزمة تطوير البرامج (SDK).
- في وحدة تطبيقك، فعِّل "وقت تشغيل SDK" وحدِّد الأذونات اللازمة واضبط الخدمات الإعلانية الخاصة بواجهة برمجة التطبيقات.
- أضف وحدة مكتبة واحدة إلى مشروعك. تحتوي هذه الوحدة على رمز حزمة تطوير البرامج (SDK).
- في وحدة حزمة تطوير البرامج (SDK)، حدِّد الأذونات اللازمة. ولن تحتاج إلى ضبط الخدمات الإعلانية الخاصة بواجهة برمجة التطبيقات في هذه الوحدة.
- عليك إزالة العلامة
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" أو Android Debug Bridge (ADB). لمساعدتك في البدء، أنشأنا نماذج من التطبيقات بلغتَي البرمجة Kotlin وJava، ويمكن العثور عليها في مستودع GitHub هذا. تحتوي ملفات README وملفات البيان على تعليقات تصف ما يجب تغييره لتشغيل العيّنة في الإصدارات الثابتة من "استوديو Android".
إعداد حزمة تطوير البرامج (SDK)
إنشاء دليل على مستوى الوحدة يدويًا. يعمل هذا كبرنامج تضمين حول رمز التنفيذ لإنشاء حزمة SDK لحزمة 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، يجب إلغاء الطرق للتعامل مع دورة حياة 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; } }
استخدام واجهات برمجة التطبيقات للتخزين في حزمة تطوير البرامج (SDK)
لم يعُد بإمكان حِزم SDK في "وقت تشغيل SDK" الوصول إلى وحدة التخزين الداخلية للتطبيق أو قراءتها أو كتابتها، والعكس صحيح. سيتم تخصيص مساحة التخزين الداخلية الخاصة بها لوقت تشغيل SDK، والتي يمكن ضمان أن تكون منفصلة عن التطبيق.
ستتمكن حِزم تطوير البرامج (SDK) من الوصول إلى وحدة التخزين الداخلية المنفصلة هذه باستخدام واجهات برمجة التطبيقات لتخزين الملفات في العنصر Context
الذي يعرضه SandboxedSdkProvider#getContext()
. يمكن لحِزم SDK استخدام مساحة تخزين داخلية فقط، لذلك لن تعمل سوى واجهات برمجة تطبيقات مساحة التخزين الداخلية، مثل Context.getFilesDir()
أو Context.getCacheDir()
. يمكنك الاطّلاع على المزيد من الأمثلة في قسم
الوصول من وحدة التخزين الداخلية.
لا يمكن الوصول إلى وحدة التخزين الخارجية من "وقت تشغيل SDK". سيؤدي استدعاء واجهات برمجة التطبيقات
للوصول إلى وحدة التخزين الخارجية إما إلى إنشاء استثناء أو عرض null
. عدة أمثلة:
- سيؤدي الوصول إلى الملفات باستخدام إطار عمل الوصول إلى مساحة التخزين إلى عرض الخطأ
SecurityException
. - ستعرض
getExternalFilsDir()
دائمًاnull
.
في نظام التشغيل Android 13، ستشارك كل حِزم SDK في "وقت تشغيل SDK" وحدة التخزين الداخلية المخصّصة لوقت تشغيل SDK. وسيستمر التخزين إلى أن يتم إلغاء تثبيت تطبيق العميل أو عند تنظيف بيانات تطبيق العميل.
عليك استخدام Context
التي تم إرجاعها من خلال SandboxedSdkProvider.getContext()
لتوفير مساحة التخزين. لا نضمن لك عمل واجهة برمجة التطبيقات الخاصة بمساحة تخزين الملفات مع أي مثيل آخر من عناصر 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، تعرض واجهة برمجة تطبيقات واحدة فقط مسارًا إلى مساحة التخزين لكل حزمة SDK:
Context#getDataDir()
.
في نظام التشغيل Android 14، تعرض جميع واجهات برمجة التطبيقات لمساحة التخزين الداخلية في العنصر 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
" في ملف بيان حزمة تطوير البرامج (SDK). - استخدِم
AdIdManager#getAdId()
لاسترداد القيمة بشكل غير متزامن.
الوصول إلى معرّف مجموعة التطبيقات المقدَّم من "خدمات Google Play"
إذا كانت حزمة تطوير البرامج (SDK) بحاجة إلى الوصول إلى معرّف مجموعة التطبيقات الذي توفّره "خدمات Google Play":
- استخدِم
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) الحالية.حدِّد فئة معاودة الاتصال من خلال تنفيذ
OutcomeReceiver
للتفاعل مع حزمة تطوير البرامج (SDK) في وقت التشغيل بعد تحميلها. في المثال التالي، يستخدم العميل معاودة الاتصال للانتظار حتى يتم تحميل SDK بنجاح، ثم يحاول عرض عرض ويب من حزمة SDK. يتم تحديد عمليات معاودة الاستدعاء لاحقًا في هذه الخطوة.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); }
لمعالجة حالة انتهاء عملية وضع الحماية لحزمة 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); } }
لتسجيل معاودة الاتصال هذه لتلقي معلومات حول وقت إنهاء وضع الحماية لحزمة SDK، أضف السطر التالي في أي وقت:
Kotlin
mSdkSandboxManager.addSdkSandboxProcessDeathCallback({ obj: Runnable -> obj.run() }, SdkSandboxLifecycleCallbackImpl())
Java
mSdkSandboxManager.addSdkSandboxProcessDeathCallback(Runnable::run, new SdkSandboxLifecycleCallbackImpl());
ونظرًا لفقدان حالة وضع الحماية عند إنهاء العملية، قد لا تعمل طرق العرض التي تم عرضها عن بُعد بواسطة حزمة SDK بشكل صحيح. لمواصلة التفاعل مع حِزم SDK، يجب تحميل طرق العرض هذه مرة أخرى لبدء عملية وضع حماية جديدة.
أضِف عنصر الاعتماد إلى وحدة حزمة تطوير البرامج (SDK) في
build.gradle
في تطبيق العميل:dependencies { ... implementation project(':<your-sdk-module>') ... }
اختبار تطبيقاتك
لتشغيل تطبيق العميل، يجب تثبيت تطبيق SDK وتطبيق العميل على جهاز الاختبار باستخدام Android Studio أو سطر الأوامر.
النشر من خلال "استوديو Android"
عند النشر من خلال "استوديو Android"، أكمل الخطوات التالية:
- افتح مشروع "استوديو Android" لتطبيق عميلك.
- انتقِل إلى تشغيل > تعديل عمليات الضبط. تظهر نافذة إعداد التشغيل/تصحيح الأخطاء.
- ضمن خيارات الإطلاق، اضبط إطلاق على نشاط محدّد.
- انقر على قائمة الخيارات الإضافية بجانب "النشاط" واختَر النشاط الرئيسي لعميلك.
- انقر على تطبيق ثم حسنًا.
- انقر على تشغيل لتثبيت تطبيق العميل وحزمة تطوير البرامج (SDK) على جهاز الاختبار.
النشر في سطر الأوامر
عند النشر باستخدام سطر الأوامر، أكمل الخطوات الواردة في القائمة التالية.
يفترض هذا القسم أنّ اسم وحدة تطبيق حزمة تطوير البرامج (SDK) هو sdk-app
وأنّ اسم وحدة تطبيق العميل هو client-app
.
من الوحدة الطرفية لسطر الأوامر، يمكنك إنشاء حِزم APK لحزمة تطوير البرامج (SDK) ضمن "مبادرة حماية الخصوصية":
./gradlew :client-app:buildPrivacySandboxSdkApksForDebug
يؤدي هذا إلى عرض الموقع الجغرافي لملفات APK التي تم إنشاؤها. تم توقيع حِزم APK هذه باستخدام مفتاح تصحيح الأخطاء المحلي. ستحتاج إلى هذا المسار في الأمر التالي.
تثبيت حزمة APK على جهازك:
adb install -t /path/to/your/standalone.apk
في "استوديو Android"، انقر على تشغيل > تعديل عمليات الضبط. ستظهر نافذة التشغيل/تصحيح الأخطاء.
ضمن خيارات التثبيت، اضبط نشر على حزمة APK التلقائية.
انقر على تطبيق ثم حسنًا.
انقر على Run (تشغيل) لتثبيت حزمة APK على جهاز الاختبار.
تصحيح أخطاء تطبيقاتك
لتصحيح أخطاء تطبيق العميل، انقر على الزر تصحيح الأخطاء في "استوديو Android".
لتصحيح أخطاء تطبيق SDK، انتقل إلى Run > Attach to Process (تشغيل > إرفاق بالعملية)، حيث تظهر لك شاشة منبثقة (كما هو موضح أدناه). ضَع علامة في المربّع عرض جميع العمليات. في القائمة التي تظهر،
ابحث عن عملية تسمى CLIENT_APP_PROCESS_sdk_sandbox
. حدد هذا الخيار وأضف نقاط التوقف في التعليمات البرمجية لتطبيق SDK
لبدء تصحيح أخطاء SDK.
بدء وقت تشغيل حزمة SDK وإيقافه من سطر الأوامر
لبدء عملية تشغيل حزمة تطوير البرامج (SDK) في تطبيقك، استخدِم أمر PowerShell التالي:
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"، يمكنك الاطّلاع على ملاحظات الإصدار.
عيّنات تعليمات برمجية
يحتوي مستودع واجهات برمجة التطبيقات (API) الخاصة بـ "وقت تشغيل SDK" و"الحفاظ على الخصوصية" على GitHub على مجموعة من المشاريع الفردية الخاصة بـ "استوديو Android" لمساعدتك في البدء، بما في ذلك نماذج توضّح كيفية إعداد "وقت تشغيل SDK" واستدعاءه.الإبلاغ عن الأخطاء والمشاكل
ملاحظاتك هي جزء مهم من "مبادرة حماية الخصوصية" على Android. يُرجى إعلامنا بأي مشاكل تصادفها أو أفكارًا لتحسين "مبادرة حماية الخصوصية" على Android.
محتوى مُقترَح لك
- ملاحظة: يتم عرض نص الرابط عند إيقاف JavaScript.
- وقت تشغيل حزمة تطوير البرامج (SDK)
- ملاحظات الإصدار
- Protected Audience API على دليل مطوّري برامج Android