يجب أن يكون هذا المستند هو دليلك الأساسي لاستخدام حزمة تطوير البرامج (SDK) الخاصة بواجهة برمجة التطبيقات AMAPI لأغراض تلقّي إشارات موثوقية الجهاز.
تتيح حزمة تطوير البرامج (SDK) الخاصة بواجهة برمجة التطبيقات AMAPI لتطبيقك (الذي قد نشير إليه أحيانًا باسم تطبيق "مساعد") الوصول إلى إشارات موثوقية الجهاز من تطبيق "سياسة جهاز Android" (ADP). ويمكن لتطبيقك بعد ذلك استخدام هذه الإشارات لاحتساب حالة موثوقية الجهاز وتفعيل منطق النشاط التجاري الذي تختاره.
المتطلبات الأساسية
- يتم حظر الوصول إلى إشارات ثقة الأجهزة لمنع الاستخدام غير المصرَّح به. للحصول على معلومات حول كيفية تقديم الطلب، انتقِل إلى صفحة الوصول إلى إشارات ثقة الجهاز.
- تنصح Android Enterprise بدمج مجموعة واجهات برمجة التطبيقات Play Integrity في تطبيق العميل والرجوع إلى النتيجة قبل قراءة إشارات موثوقية الجهاز والاعتماد عليها. يجب عدم الوثوق بالأجهزة التي لا تجتاز عمليات التحقّق التي تجريها واجهة برمجة التطبيقات Play Integrity API، ولا بأي إشارات مشتقة من الجهاز المستخدَم لتحديد حالة الثقة. يمكنك الرجوع إلى مستندات Play Integrity API للحصول على مزيد من التفاصيل.
دمج حزمة تطوير البرامج (SDK) لواجهة برمجة التطبيقات AMAPI في تطبيقك
للوصول إلى إشارات موثوقية الجهاز، يجب أن يتكامل تطبيقك مع حزمة تطوير البرامج لواجهة برمجة التطبيقات AMAPI. يمكنك العثور على مزيد من المعلومات حول هذه المكتبة وكيفية إضافتها إلى تطبيقك في دليل دمج حزمة تطوير البرامج (SDK) لواجهة برمجة التطبيقات AMAPI.
إضافة الأذونات المطلوبة
تتطلّب بعض الإشارات التي يتم عرضها من خلال Device Trust API في Android Enterprise أن يوضّح التطبيق الإذن نفسه المطلوب للوصول إلى هذه المعلومات في المقام الأول، وخاصةً ما يلي:
| إشارة | الإذن المطلوب |
|---|---|
| حالة الشبكة | ACCESS_NETWORK_STATE |
| مستوى صعوبة قفل الشاشة | REQUEST_PASSWORD_COMPLEXITY |
إذا لم يتم تضمين هذه الأذونات في AndroidManifest.xml للتطبيق، ستعرض واجهة برمجة التطبيقات Device Trust من Android Enterprise القيمة PERMISSION_ISSUE في البيانات الوصفية للإشارة ذات الصلة:
internalDeviceSettings=DeviceSettings{
screenLockComplexity=COMPLEXITY_UNSPECIFIED,
internalScreenLockComplexityMetadata=Metadata{
dataIssues=[
DataIssue{
issueType=PERMISSION_ISSUE,
issueLevel=WARNING,
issueDetails=IssueDetailsCase{none}
}
]
},
لمزيد من التفاصيل، يُرجى الاطّلاع على قائمة إشارات موثوقية الجهاز المتاحة.
خطوات الوصول إلى إشارات ثقة الأجهزة
يجب أن تتحقّق التطبيقات التي تريد الوصول إلى إشارات موثوقية الجهاز من أنّ بيئة البرنامج محدَّثة، وأن تعمل على تحديثها إذا لزم الأمر.
في ما يلي خطوات الوصول إلى إشارات ثقة الأجهزة:

التحقّق من بيئة العميل
يوضّح مثال الرمز البرمجي التالي كيفية استخدام getEnvironment لقراءة الحالة الحالية لتطبيق ADP. ويمكن لتطبيقك بعد ذلك إنشاء deviceClient للوصول إلى إشارات موثوقية الجهاز إذا كانت البيئة جاهزة ومحدّثة (راجِع الوصول إلى إشارات موثوقية الجهاز).
Kotlin
import com.google.android.managementapi.common.model.Role import com.google.android.managementapi.device.DeviceClient import com.google.android.managementapi.device.DeviceClientFactory import com.google.android.managementapi.device.model.GetDeviceRequest import com.google.android.managementapi.environment.EnvironmentClient import com.google.android.managementapi.environment.EnvironmentClientFactory import com.google.android.managementapi.environment.model.Environment.AndroidDevicePolicyEnvironment.State.INSTALLED import com.google.android.managementapi.environment.model.Environment.AndroidDevicePolicyEnvironment.State.NOT_INSTALLED import com.google.android.managementapi.environment.model.Environment.AndroidDevicePolicyEnvironment.State.READY import com.google.android.managementapi.environment.model.Environment.AndroidDevicePolicyEnvironment.Version.UP_TO_DATE import com.google.android.managementapi.environment.model.GetEnvironmentRequest import com.google.android.managementapi.environment.model.PrepareEnvironmentRequest try { val context = applicationContext val roles = listOf(Role.builder().setRoleType(Role.RoleType.IDENTITY_PROVIDER).build()) val request = GetEnvironmentRequest.builder().setRoles(roles).build() val environmentClient = EnvironmentClientFactory.create(context) val environmentResponse = environmentClient.getEnvironment(request) if (environmentResponse.hasAndroidDevicePolicyEnvironment()) { val adpEnvironment = environmentResponse.androidDevicePolicyEnvironment if (adpEnvironment.state == READY && adpEnvironment.version == UP_TO_DATE) { // AMAPI Environment State OK, Version OK. Requesting Device signals.. checkDevice(deviceClient = DeviceClientFactory.create(context)) } else if (adpEnvironment.state == INSTALLED) { // prepareEnvironment should be called, calling // prepareEnvironment won't show the UI prepareEnvironment(context, environmentClient) } else if (adpEnvironment.state == NOT_INSTALLED) { // prepareEnvironment should be called, calling // prepareEnvironment will show the UI prepareEnvironment(context, environmentClient) } } } catch (e: Exception) { Log.e(TAG, "Exception", e) }
Java
import static com.google.android.managementapi.environment.model.Environment.AndroidDevicePolicyEnvironment.State.INSTALLED; import static com.google.android.managementapi.environment.model.Environment.AndroidDevicePolicyEnvironment.State.NOT_INSTALLED; import static com.google.android.managementapi.environment.model.Environment.AndroidDevicePolicyEnvironment.State.READY; import static com.google.android.managementapi.environment.model.Environment.AndroidDevicePolicyEnvironment.Version.UP_TO_DATE; import com.google.android.managementapi.common.model.Role; import com.google.android.managementapi.device.DeviceClient; import com.google.android.managementapi.device.DeviceClientFactory; import com.google.android.managementapi.device.model.Device; import com.google.android.managementapi.device.model.GetDeviceRequest; import com.google.android.managementapi.environment.EnvironmentClient; import com.google.android.managementapi.environment.EnvironmentClientFactory; import com.google.android.managementapi.environment.model.Environment; import com.google.android.managementapi.environment.model.Environment.AndroidDevicePolicyEnvironment; import com.google.android.managementapi.environment.model.GetEnvironmentRequest; import com.google.android.managementapi.environment.model.PrepareEnvironmentRequest; import com.google.android.managementapi.environment.model.PrepareEnvironmentResponse; try { Context context = getApplicationContext(); ImmutableListroles = new ImmutableList.Builder () .add(Role.builder() .setRoleType(Role.RoleType.IDENTITY_PROVIDER) .build()) .build(); EnvironmentClient environmentClient = EnvironmentClientFactory.create(context); GetEnvironmentRequest request = GetEnvironmentRequest.builder() .setRoles(roles) .build(); ListenableFuture getEnvironmentFuture = environmentClient.getEnvironmentAsync(request); Futures.addCallback(getEnvironmentFuture, new FutureCallback<>() { @Override public void onSuccess(Environment environment) { AndroidDevicePolicyEnvironment adpEnvironment = environment.getAndroidDevicePolicyEnvironment(); AndroidDevicePolicyEnvironment.State state = adpEnvironment.getState(); AndroidDevicePolicyEnvironment.Version version = adpEnvironment.getVersion(); if (state == READY && version == UP_TO_DATE) { // AMAPI Environment State OK, Version OK. Requesting Device signals.. DeviceClient deviceClient = DeviceClientFactory.create(context); checkDevice(deviceClient); } else if (state == INSTALLED) { // prepareEnvironment should be called, calling // prepareEnvironment won't show the UI prepareEnvironment(context, environmentClient); } else if (state == NOT_INSTALLED) { // prepareEnvironment should be called, calling // prepareEnvironment will show the UI prepareEnvironment(context, environmentClient); } } @Override public void onFailure(Throwable t) { Log.d(TAG, t.toString()); } }, MoreExecutors.directExecutor()); } catch (Exception e) { Log.d(TAG, e.toString()); }
إذا كان تطبيق ADP مثبَّتًا ولكن ليس محدَّثًا، يجب أن يستدعي تطبيقك الدالة
prepareEnvironment لتحديث تطبيق ADP تلقائيًا بدون تدخل المستخدم.
إذا لم يكن تطبيق ADP مثبَّتًا، يمكن لتطبيقك استدعاء prepareEnvironment
لطلب تثبيت تطبيق ADP من المستخدم. راجِع
إعداد بيئة العميل.
إعداد بيئة العميل
إذا كان تطبيق ADP مثبَّتًا من قبل، ستعمل واجهة برمجة التطبيقات على تحديثه تلقائيًا بدون أي تدخل من المستخدم.
إذا لم يكن تطبيق ADP مثبَّتًا، ستطلب واجهة برمجة التطبيقات من المستخدم قبول تثبيت تطبيق ADP.
من الممكن تسجيل دالة ردّ لتتبُّع اختيار المستخدم. راجِع مقالة تتبُّع تفاعل المستخدم أثناء تثبيت تطبيق ADP للحصول على تفاصيل إضافية.
ننصحك بتنفيذ طلب prepareEnvironment من عملية تعمل في المقدّمة، وذلك أثناء مسار تجربة المستخدم الخاص بالإعداد لتجنُّب مفاجأة المستخدم بعرض مربّع الحوار المشروط تثبيت تطبيق "سياسة أمان Android".
إذا لم يكن من الممكن إجراء المكالمة من عملية في المقدّمة، لأنّ هذا إجراء على الويب ولا يتضمّن مكوّن Android أي واجهة مستخدم، يُسمح بإجراء المكالمة من الخلفية بشرط أن يتم ذلك أثناء عملية إعداد تجربة المستخدم.
بعد إعداد البيئة بشكل صحيح، يمكن الوصول إلى إشارات ثقة الجهاز. اطّلِع على الوصول إلى إشارات ثقة الأجهزة.
Kotlin
try { val myNotificationReceiverService = ComponentName( context, MyNotificationReceiverService::class.java ) val roles = listOf(Role.builder().setRoleType(Role.RoleType.IDENTITY_PROVIDER).build()) val request = PrepareEnvironmentRequest.builder().setRoles(roles).build() val response = environmentClient.prepareEnvironment(request, myNotificationReceiverService) val environment = response.environment val adpEnvironment = environment.androidDevicePolicyEnvironment val state = adpEnvironment.state val version = adpEnvironment.version if (state == READY && version == UP_TO_DATE) { // Environment is prepared, access device posture signals using // DeviceClient. checkDevice(deviceClient = DeviceClientFactory.create(context)) } else { // The prepareEnvironment call failed to prepare Log.w( TAG, "AMAPI environment was not ready: " + state + " - " + version ) } } catch (e: java.lang.Exception) { Log.d(TAG, e.toString()) }
Java
try { ComponentName myNotificationReceiverService = new ComponentName( context, MyNotificationReceiverService.class ); ImmutableListroles = new ImmutableList.Builder () .add(Role.builder() .setRoleType(Role.RoleType.IDENTITY_PROVIDER) .build()) .build(); PrepareEnvironmentRequest request = PrepareEnvironmentRequest.builder() .setRoles(roles) .build(); ListenableFuture environmentFuture = environmentClient.prepareEnvironmentAsync( request, myNotificationReceiverService ); Futures.addCallback(environmentFuture, new FutureCallback<>() { @Override public void onSuccess(PrepareEnvironmentResponse response) { Environment environment = response.getEnvironment(); AndroidDevicePolicyEnvironment adpEnvironment = environment.getAndroidDevicePolicyEnvironment(); AndroidDevicePolicyEnvironment.State state = adpEnvironment.getState(); AndroidDevicePolicyEnvironment.Version version = adpEnvironment.getVersion(); if (state == READY && version == UP_TO_DATE) { // AMAPI Environment State OK, Version OK. Requesting Device signals.. DeviceClient deviceClient = DeviceClientFactory.create(context); checkDevice(deviceClient); } else { // The prepareEnvironment call failed to prepare Log.w( TAG, "AMAPI environment was not ready: " + adpEnvironment.getState() + " - " + adpEnvironment.getVersion() ); } } @Override public void onFailure(@NonNull Throwable t) { // Handle the error Log.d(TAG, "AMAPI response did not contain an ADP environment"); } }, MoreExecutors.directExecutor()); } catch (Exception e) { Log.d(TAG, e.toString()); }
الوصول إلى إشارات الثقة في الجهاز
وضع الجهاز.للوصول إلى إشارات موثوقية الجهاز التي تهمّك، يمكنك استخدام مثيل deviceClient الذي تم عرضه في الخطوة السابقة لطلب العنصر Device.
Kotlin
try { kotlin.runCatching { deviceClient.getDeviceAwait(GetDeviceRequest.getDefaultInstance()) }.onFailure { t -> Log.d(TAG, t.toString()) }.onSuccess { device -> // Access device posture signals available in device val deviceString = device.toString() Log.d(TAG, deviceString) } } catch (e: java.lang.Exception) { Log.d(TAG, e.toString()) }
Java
try { ListenableFuturedeviceFuture = deviceClient.getDevice(GetDeviceRequest.getDefaultInstance()); Futures.addCallback(deviceFuture, new FutureCallback () { @Override public void onSuccess(Device device) { // Access device posture signals available in device String deviceString = device.toString(); Log.d(TAG, deviceString); } @Override public void onFailure(Throwable t) { Log.d(TAG, Log.d(TAG, t.toString()); } }, MoreExecutors.directExecutor()); } catch (Exception e) { Log.d(TAG, e.toString()); }
معالجة الأخطاء
إذا أرسل تطبيقك طلبًا بشأن موثوقية الجهاز وتعذّر إكماله، سيتلقّى تطبيقك استثناءً. يمكن أن تحدث هذه الاستثناءات لأسباب مختلفة، مثل:
SecurityException: لم يتم تسجيل تطبيقك للوصول إلى إشارات موثوقية الجهاز. اطّلِع على إذن الوصول إلى إشارات ثقة الأجهزة.- لم يتم إعداد فئة فرعية من
AmapiSdkException- ADP أو أنّها غير جاهزة. يمكن أن يكون السبب في ذلك حالة عابرة، لذا عليك إعادة محاولة إجراء المكالمة.
استراتيجيات إعادة المحاولة
بالنسبة إلى الاستثناءات الناتجة عن حالة مؤقتة، عليك تنفيذ استراتيجية إعادة المحاولة باستخدام خوارزمية الرقود الأسي الثنائي. بعد حدوث الخطأ الأول، ابدأ بتأخير أولي يبلغ 5 ثوانٍ قبل إعادة المحاولة.
نفِّذ استراتيجية إعادة محاولة مع تحديد الحد الأقصى لعدد المحاولات كشرط للخروج باستخدام تأخير متزايد بشكل كبير في كل مرة (10 ثوانٍ، 20 ثانية، وما إلى ذلك).
تتبُّع تفاعل المستخدم أثناء تثبيت تطبيق ADP
إذا كان الجهاز بحاجة إلى تثبيت تطبيق ADP أثناء prepareEnvironment، يمكن لتطبيقك تتبُّع تفاعل المستخدم من خلال تنفيذ NotificationReceiverService لتلقّي الإشعارات التي تتجاوز getPrepareEnvironmentListener:
Kotlin
import android.util.Log import com.google.android.managementapi.environment.EnvironmentListener import com.google.android.managementapi.environment.model.EnvironmentEvent.EventCase.Kind.ANDROID_DEVICE_POLICY_INSTALL_CONSENT_ACCEPTED import com.google.android.managementapi.environment.model.EnvironmentEvent import com.google.android.managementapi.notification.NotificationReceiverService class MyNotificationReceiverService : NotificationReceiverService() { override fun getPrepareEnvironmentListener(): EnvironmentListener { return MyEnvironmentListener() } } class MyEnvironmentListener : EnvironmentListener { override fun onEnvironmentEvent( event: EnvironmentEvent ) { if (event.event.kind == ANDROID_DEVICE_POLICY_INSTALL_CONSENT_ACCEPTED) { Log.d(TAG, "User provided install consent") } else { Log.d(TAG, "User rejected install consent") } } companion object { private val TAG: String = MyEnvironmentListener::class.java.simpleName } }
Java
import static com.google.android.managementapi.environment.model.EnvironmentEvent.EventCase.Kind.ANDROID_DEVICE_POLICY_INSTALL_CONSENT_ACCEPTED; import android.util.Log; import androidx.annotation.NonNull; import com.google.android.managementapi.environment.EnvironmentListener; import com.google.android.managementapi.environment.model.EnvironmentEvent; import com.google.android.managementapi.notification.NotificationReceiverService; class MyNotificationReceiverService extends NotificationReceiverService { @NonNull @Override protected EnvironmentListener getPrepareEnvironmentListener() { return new MyEnvironmentListener(); } } class MyEnvironmentListener implements EnvironmentListener { final private String TAG = MyEnvironmentListener.class.getSimpleName(); @Override public void onEnvironmentEvent(EnvironmentEvent event) { if (event.getEvent().getKind() == ANDROID_DEVICE_POLICY_INSTALL_CONSENT_ACCEPTED) { Log.d(TAG, "User provided install consent"); } else { Log.d(TAG, "User rejected install consent"); } } }
المشاكل المعروفة
ليس هناك أي مشاكل معروفة في الوقت الحالي.