Device Trust من Android Enterprise - دليل الدمج

يجب أن يكون هذا المستند هو دليلك الأساسي لاستخدام حزمة تطوير البرامج (SDK) الخاصة بواجهة برمجة التطبيقات AMAPI لأغراض تلقّي إشارات موثوقية الجهاز.

تتيح حزمة تطوير البرامج (SDK) لواجهة برمجة التطبيقات AMAPI لتطبيقك (الذي قد نشير إليه أحيانًا باسم تطبيق "مساعد") الوصول إلى إشارات موثوقية الجهاز من تطبيق "سياسة جهاز Android" (ADP). ويمكن لتطبيقك بعد ذلك استخدام هذه الإشارات لاحتساب حالة موثوقية الجهاز وتفعيل منطق النشاط التجاري الذي تختاره.

المتطلبات الأساسية

  • يتم حظر الوصول إلى إشارات ثقة الجهاز لمنع الاستخدام غير المصرَّح به. للحصول على معلومات حول كيفية تقديم الطلب، انتقِل إلى صفحة الوصول إلى إشارات ثقة الجهاز.
  • تنصح Android Enterprise بدمج مجموعة واجهات برمجة التطبيقات Play Integrity في تطبيق العميل والرجوع إلى النتيجة قبل قراءة إشارات موثوقية الجهاز والاعتماد عليها. لا يمكن الوثوق بالأجهزة التي لا تجتاز عمليات التحقّق التي تجريها واجهة برمجة التطبيقات Play Integrity API، ولا بأي إشارات مشتقة من الجهاز المستخدَم لتحديد حالة الثقة. يمكنك الرجوع إلى مستندات Play Integrity لمزيد من التفاصيل.

دمج حزمة تطوير البرامج (SDK) لواجهة برمجة التطبيقات AMAPI في تطبيقك

للوصول إلى إشارات موثوقية الجهاز، يجب أن يتكامل تطبيقك مع حزمة تطوير البرامج لواجهة برمجة التطبيقات AMAPI. يمكنك العثور على مزيد من المعلومات حول هذه المكتبة وكيفية إضافتها إلى تطبيقك في دليل دمج حزمة تطوير البرامج (SDK) لواجهة برمجة التطبيقات AMAPI.

إضافة الأذونات المطلوبة

تتطلّب بعض الإشارات التي يتم عرضها من خلال واجهة برمجة التطبيقات Device Trust from 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();

    ImmutableList roles = 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.

تثبيت تطبيق Android Device Policy

من الممكن تسجيل دالة ردّ لتتبُّع اختيار المستخدم. راجِع مقالة تتبُّع تفاعل المستخدم أثناء تثبيت تطبيق 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
    );

    ImmutableList roles = 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 {
    ListenableFuture deviceFuture =
            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());
}

تتبُّع تفاعل المستخدم أثناء تثبيت تطبيق 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");
        }
    }
}

المشاكل المعروفة

ليس هناك أي مشاكل معروفة في الوقت الحالي.