Device Trust از Android Enterprise - راهنمای ادغام

این سند باید راهنمای اصلی شما برای استفاده از AMAPI SDK به منظور دریافت سیگنال‌های اعتماد دستگاه باشد.

کیت توسعه نرم‌افزار AMAPI به برنامه شما (که گاهی اوقات ممکن است به عنوان یک برنامه "همراه" از آن یاد کنیم) این امکان را می‌دهد که به سیگنال‌های اعتماد دستگاه از برنامه ADP (سیاست دستگاه اندروید) دسترسی پیدا کند. سپس برنامه شما می‌تواند از این سیگنال‌ها برای محاسبه وضعیت اعتماد دستگاه و اجرای منطق تجاری انتخاب شده استفاده کند.

پیش‌نیازها

  • دسترسی به سیگنال‌های اعتماد دستگاه برای جلوگیری از استفاده غیرمجاز محدود شده است. برای کسب اطلاعات در مورد نحوه درخواست، به صفحه دسترسی به سیگنال‌های اعتماد دستگاه مراجعه کنید.
  • اندروید انترپرایز توصیه می‌کند که مجموعه APIهای Play Integrity را در برنامه کلاینت خود ادغام کنید و قبل از خواندن و تکیه بر سیگنال‌های اعتماد دستگاه، به نتیجه مراجعه کنید. دستگاه‌هایی که در بررسی‌های API Play Integrity ناموفق هستند، نباید مورد اعتماد قرار گیرند، و همچنین هیچ سیگنالی که از دستگاه برای تعیین وضعیت اعتماد گرفته می‌شود، نباید مورد استفاده قرار گیرد. برای جزئیات بیشتر می‌توانید به مستندات Play Integrity مراجعه کنید.

ادغام با AMAPI SDK در برنامه شما

برای دسترسی به سیگنال‌های اعتماد دستگاه، برنامه شما باید با AMAPI SDK ادغام شود. می‌توانید اطلاعات بیشتر در مورد این کتابخانه و نحوه افزودن آن به برنامه خود را در راهنمای ادغام AMAPI SDK بیابید.

مجوزهای مورد نیاز را اضافه کنید

تعدادی از سیگنال‌های برگشتی از Device Trust from Android Enterprise API مستلزم آن است که برنامه همان مجوزی را که برای دسترسی به این اطلاعات در وهله اول لازم است، اعلام کند، به ویژه:

سیگنال مجوز لازم
وضعیت شبکه ACCESS_NETWORK_STATE
پیچیدگی قفل صفحه REQUEST_PASSWORD_COMPLEXITY

اگر این مجوزها در AndroidManifest.xml برنامه گنجانده نشده باشند، Device Trust از Android Enterprise API مقدار PERMISSION_ISSUE در متادیتای سیگنال مربوطه برمی‌گرداند:

internalDeviceSettings=DeviceSettings{
  screenLockComplexity=COMPLEXITY_UNSPECIFIED,
  internalScreenLockComplexityMetadata=Metadata{
    dataIssues=[
      DataIssue{
        issueType=PERMISSION_ISSUE,
        issueLevel=WARNING,
        issueDetails=IssueDetailsCase{none}
      }
    ]
  },

برای جزئیات بیشتر، به فهرست سیگنال‌های اعتماد دستگاه موجود مراجعه کنید.

مراحل دسترسی به سیگنال‌های اعتماد دستگاه

برنامه‌هایی که می‌خواهند به سیگنال‌های اعتماد دستگاه دسترسی پیدا کنند، موظفند به‌روزرسانی محیط کلاینت را تأیید کرده و در صورت لزوم آن را به‌روزرسانی کنند.

مراحل دسترسی به سیگنال‌های اعتماد دستگاه عبارتند از:

مراحل دسترسی به سیگنال‌های اعتماد دستگاه

محیط کلاینت را بررسی کنید

مثال کد زیر نحوه استفاده از getEnvironment را برای خواندن وضعیت فعلی برنامه ADP نشان می‌دهد. سپس برنامه شما می‌تواند یک deviceClient ایجاد کند تا در صورت آماده و به‌روز بودن محیط، به سیگنال‌های اعتماد دستگاه دسترسی پیدا کند (به بخش دسترسی به سیگنال‌های اعتماد دستگاه مراجعه کنید).

کاتلین

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)
}

جاوا

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 را نصب کند. به بخش Prepare the client environment مراجعه کنید.

آماده سازی محیط مشتری

  • اگر برنامه ADP از قبل نصب شده باشد، API بدون دخالت کاربر و به صورت بی‌صدا آن را به‌روزرسانی می‌کند.

  • اگر برنامه ADP نصب نشده باشد، API از کاربر می‌خواهد که نصب برنامه ADP را بپذیرد.

نصب خط‌مشی دستگاه اندروید

می‌توان یک فراخوانی مجدد برای نظارت بر انتخاب کاربر ثبت کرد. برای جزئیات بیشتر به بخش «ردیابی تعامل کاربر در طول نصب برنامه ADP» مراجعه کنید.

توصیه می‌کنیم فراخوانی prepareEnvironment از یک فرآیند پیش‌زمینه، در طول جریان UX آن‌بوردینگ انجام شود تا از غافلگیر شدن کاربر با پنجره محاوره‌ای نصب سیاست دستگاه اندروید جلوگیری شود. اگر فراخوانی از یک فرآیند پیش‌زمینه امکان‌پذیر نیست، زیرا این یک جریان وب است و کامپوننت اندروید رابط کاربری ندارد، فراخوانی از پس‌زمینه با این شرط مجاز است که این اتفاق در طول جریان UX آن‌بوردینگ رخ دهد.

پس از تنظیم صحیح محیط، می‌توان به سیگنال‌های اعتماد دستگاه دسترسی پیدا کرد. به بخش «دسترسی به سیگنال‌های اعتماد دستگاه» مراجعه کنید.

کاتلین

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())
}

جاوا

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 استفاده کنید.

کاتلین

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())
}

جاوا

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());
}

مدیریت خطاها

اگر برنامه شما درخواست اعتماد دستگاه را ارسال کند و فراخوانی ناموفق باشد، برنامه شما یک استثنا دریافت می‌کند. این استثنائات می‌توانند به دلایل مختلفی مانند موارد زیر رخ دهند:

استراتژی‌های تلاش مجدد

برای استثنائات ناشی از شرایط گذرا، یک استراتژی تلاش مجدد با یک عقب‌نشینی نمایی پیاده‌سازی کنید. پس از اولین شکست، با یک تأخیر اولیه ۵ ثانیه‌ای قبل از تلاش مجدد شروع کنید.

یک استراتژی تلاش مجدد با حداکثر تعداد تلاش به عنوان شرط خروج با استفاده از یک تأخیر نمایی افزایش یافته در هر بار (10 ثانیه، 20 ثانیه و غیره) پیاده‌سازی کنید.

تعامل کاربر را در طول نصب برنامه ADP ردیابی کنید

اگر دستگاه نیاز به نصب برنامه ADP در طول prepareEnvironment داشته باشد، برنامه شما می‌تواند تعامل کاربر را با پیاده‌سازی NotificationReceiverService برای دریافت اعلان‌هایی که getPrepareEnvironmentListener لغو می‌کنند، پیگیری کند:

کاتلین

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
    }
}

جاوا

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");
        }
    }
}

مشکلات شناخته شده

در حال حاضر هیچ مشکل شناخته‌شده‌ای وجود ندارد.