本文是使用 AMAPI SDK 接收裝置信任訊號的主要指南。
AMAPI SDK 可讓應用程式 (有時也稱為「隨附」應用程式) 存取 ADP (Android Device Policy) 應用程式的裝置信任信號。應用程式接著可使用這些信號計算裝置的信任狀態,並根據選擇執行業務邏輯。
必要條件
- 為防止未經授權的使用行為,裝置信任訊號的存取權受到限制。如要瞭解如何申請,請前往「裝置信任訊號存取權」頁面。
- 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()); }
追蹤使用者在 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"); } } }
已知問題
目前沒有已知問題。