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

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

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

پیش نیازها

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

با AMAPI SDK در برنامه خود ادغام کنید

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

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

تعدادی از سیگنال‌های بازگردانده شده از Device Trust از 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 را نصب کند. به آماده کردن محیط مشتری مراجعه کنید.

محیط مشتری را آماده کنید

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

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

Android Device Policy را نصب کنید

امکان ثبت تماس پاسخ برای نظارت بر انتخاب کاربر وجود دارد. برای جزئیات بیشتر به پیگیری تعامل کاربر در طول نصب برنامه ADP مراجعه کنید.

توصیه می‌کنیم که تماس prepareEnvironment از یک فرآیند پیش‌زمینه، در طول جریان UX داخلی انجام شود تا از تعجب کاربر با گفتگوی مودال Install Android Device Policy جلوگیری شود. اگر تماس از یک فرآیند پیش‌زمینه امکان‌پذیر نباشد، زیرا این یک جریان وب است و مؤلفه Android فاقد رابط کاربری است، تماس از پس‌زمینه مجاز است با این شرط که این اتفاق در جریان 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());
}

ردیابی تعامل کاربر در حین نصب برنامه 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");
        }
    }
}

مسائل شناخته شده

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