本文是使用 AMAPI SDK 接收裝置信任訊號的主要指南。
AMAPI SDK 可讓應用程式 (有時也稱為「隨附」應用程式) 存取 ADP (Android 裝置政策) 應用程式的裝置信任信號。應用程式隨後可使用這些信號計算裝置的信任狀態,並根據所選項目執行業務邏輯。
必要條件
- 為防止未經授權的使用行為,裝置信任訊號的存取權受到限制。如要瞭解如何申請,請前往「裝置信任訊號存取權」頁面。
- Android Enterprise 建議您將 Play Integrity API 套件整合至用戶端應用程式,並在讀取及依據裝置信任信號前,先參閱結果。如果裝置未通過 Play Integrity API 檢查,就不應信任該裝置,也不應信任用來判斷信任狀態的任何裝置衍生信號。詳情請參閱 Play Integrity 說明文件。
在應用程式中整合 AMAPI SDK
如要存取裝置信任訊號,應用程式必須整合 AMAPI SDK。如要進一步瞭解這個程式庫,以及如何將其新增至應用程式,請參閱 AMAPI SDK 整合指南。
新增必要權限
Android Enterprise API 傳回的裝置信任度信號中,有幾項需要應用程式宣告與存取這類資訊時相同的權限,特別是:
| 信號 | 必要權限 | 
|---|---|
| 網路狀態 | ACCESS_NETWORK_STATE | 
| 螢幕鎖定複雜度 | REQUEST_PASSWORD_COMPLEXITY | 
如果應用程式的 AndroidManifest.xml未包含這些權限,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 來存取裝置信任訊號 (請參閱「存取裝置信任訊號」)。
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 應用程式,API 會自動更新,不需使用者介入。 
- 如果未安裝 ADP 應用程式,API 會提示使用者接受安裝 ADP 應用程式。 
 
您可以註冊回呼來監控使用者選擇。詳情請參閱「在 ADP 應用程式安裝期間追蹤使用者互動」。
建議在新手上路 UX 流程中,從前景程序執行 prepareEnvironment 呼叫,以免 Install Android Device Policy 模態對話方塊突然出現,造成使用者困擾。如果無法從前景程序呼叫 (因為這是 Web 流程,且 Android 元件沒有 UI),則允許從背景呼叫,但必須在新手上路 UX 流程中進行。
環境設定完成後,即可存取裝置信任訊號。請參閱「存取裝置信任信號」。
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 應用程式安裝期間的互動
如果裝置需要在 prepareEnvironment 期間安裝 ADP 應用程式,您的應用程式可以實作 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"); } } }
已知問題
目前沒有已知問題。
