Ten dokument powinien być głównym przewodnikiem po korzystaniu z pakietu AMAPI SDK w celu otrzymywania sygnałów zaufania urządzenia.
Pakiet SDK AMAPI umożliwia aplikacji (którą czasami nazywamy aplikacją towarzyszącą) dostęp do sygnałów zaufania urządzenia z aplikacji ADP (Android Device Policy). Aplikacja może następnie używać tych sygnałów do obliczania stanu zaufania urządzenia i wdrażania wybranej logiki biznesowej.
Wymagania wstępne
- Dostęp do sygnałów zaufania urządzenia jest ograniczony, aby zapobiec nieautoryzowanemu użyciu. Informacje o tym, jak złożyć wniosek, znajdziesz na stronie dostęp do sygnałów zaufania urządzenia.
- Android Enterprise zaleca zintegrowanie pakietu interfejsów Play Integrity API z aplikacją kliencką i odwoływanie się do wyniku przed odczytaniem sygnałów zaufania urządzenia i poleganiem na nich. Urządzenia, które nie przejdą weryfikacji interfejsu Play Integrity API, nie powinny być uznawane za zaufane. Nie należy też ufać żadnym sygnałom pochodzącym z urządzenia używanego do określania poziomu zaufania. Więcej informacji znajdziesz w dokumentacji usługi Play Integrity.
Integracja z pakietem AMAPI SDK w aplikacji
Aby uzyskać dostęp do sygnałów zaufania urządzenia, aplikacja musi być zintegrowana z pakietem AMAPI SDK. Więcej informacji o tej bibliotece i o tym, jak ją dodać do aplikacji, znajdziesz w przewodniku po integracji pakietu SDK AMAPI.
Dodawanie wymaganych uprawnień
Niektóre sygnały zwracane przez interfejs Device Trust z Androida Enterprise wymagają, aby aplikacja deklarowała to samo uprawnienie, które byłoby wymagane do uzyskania dostępu do tych informacji, w szczególności:
Sygnał | Wymagane uprawnienie |
---|---|
Stan sieci | ACCESS_NETWORK_STATE |
Stopień złożoności blokady ekranu | REQUEST_PASSWORD_COMPLEXITY |
Jeśli te uprawnienia nie są uwzględnione w AndroidManifest.xml
aplikacji, interfejs Device Trust z Androida Enterprise API zwróci PERMISSION_ISSUE
w metadanych powiązanego sygnału:
internalDeviceSettings=DeviceSettings{
screenLockComplexity=COMPLEXITY_UNSPECIFIED,
internalScreenLockComplexityMetadata=Metadata{
dataIssues=[
DataIssue{
issueType=PERMISSION_ISSUE,
issueLevel=WARNING,
issueDetails=IssueDetailsCase{none}
}
]
},
Więcej informacji znajdziesz na liście dostępnych sygnałów zaufania urządzenia.
Instrukcje uzyskiwania dostępu do sygnałów zaufania urządzenia
Aplikacje, które chcą uzyskać dostęp do sygnałów zaufania urządzenia, muszą sprawdzić, czy środowisko klienta jest aktualne, i w razie potrzeby je zaktualizować.
Aby uzyskać dostęp do sygnałów zaufania do urządzenia:
- Weryfikowanie środowiska klienta
- Przygotowywanie środowiska klienta
- Dostęp do sygnałów zaufania urządzenia
Weryfikacja środowiska klienta
Poniższy przykład kodu pokazuje, jak używać funkcji getEnvironment
do odczytywania bieżącego stanu aplikacji ADP. Aplikacja może następnie utworzyć obiekt deviceClient
, aby uzyskać dostęp do sygnałów zaufania urządzenia, jeśli środowisko jest gotowe i aktualne (patrz Uzyskiwanie dostępu do sygnałów zaufania urządzenia).
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()); }
Jeśli aplikacja ADP jest zainstalowana, ale nie jest aktualna, Twoja aplikacja powinna wywołać funkcję
prepareEnvironment
, aby dyskretnie zaktualizować aplikację ADP bez interakcji ze strony użytkownika.
Jeśli aplikacja ADP nie jest zainstalowana, Twoja aplikacja może wywołać prepareEnvironment
, aby poprosić użytkownika o jej zainstalowanie. Więcej informacji znajdziesz w sekcji Przygotowywanie środowiska klienta.
Przygotowywanie środowiska klienta
Jeśli aplikacja ADP jest już zainstalowana, interfejs API zaktualizuje ją w trybie cichym bez interwencji użytkownika.
Jeśli aplikacja ADP nie jest zainstalowana, interfejs API poprosi użytkownika o zaakceptowanie jej instalacji.
Możesz zarejestrować wywołanie zwrotne, aby monitorować wybór użytkownika. Więcej informacji znajdziesz w artykule Śledzenie interakcji użytkownika podczas instalacji aplikacji ADP.
Zalecamy, aby wywołanie prepareEnvironment
było wykonywane z procesu działającego na pierwszym planie podczas procesu wprowadzającego, aby uniknąć zaskoczenia użytkownika modalnym oknem Zainstaluj aplikację Android Device Policy.
Jeśli wywołanie z procesu na pierwszym planie nie jest możliwe, ponieważ jest to przepływ internetowy, a komponent Androida nie ma interfejsu, wywołanie z procesu w tle jest dozwolone pod warunkiem, że następuje w trakcie przepływu UX związanego z wprowadzeniem.
Po prawidłowym skonfigurowaniu środowiska można uzyskać dostęp do sygnałów zaufania urządzenia. Zobacz Dostęp do sygnałów zaufania urządzenia.
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()); }
Dostęp do sygnałów zaufania do urządzenia
Aby uzyskać dostęp do sygnałów zaufania urządzenia, które Cię interesują, możesz użyć instancji deviceClient
widocznej w poprzednim kroku, aby poprosić o obiekt 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()); }
Śledzenie interakcji użytkownika podczas instalacji aplikacji ADP
Jeśli urządzenie musi zainstalować aplikację ADP podczas prepareEnvironment
, Twoja aplikacja może śledzić interakcje użytkownika, implementując NotificationReceiverService
, aby otrzymywać powiadomienia zastępujące 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"); } } }
Znane problemy
Obecnie nie ma żadnych znanych problemów.