Ce document doit être votre guide principal pour l'utilisation du SDK AMAPI afin de recevoir des signaux de confiance de l'appareil.
Le SDK AMAPI permet à votre application (que nous appelons parfois application "compagnon") d'accéder aux signaux de fiabilité de l'appareil à partir de l'application ADP (Android Device Policy). Votre application peut ensuite utiliser ces signaux pour calculer l'état de fiabilité de l'appareil et appliquer la logique métier de votre choix.
Prérequis
- L'accès aux signaux de confiance de l'appareil est limité pour empêcher toute utilisation non autorisée. Pour savoir comment faire votre demande, consultez la page Accès aux signaux de confiance des appareils.
- Android Enterprise recommande d'intégrer la suite d'API Play Integrity à votre application cliente et de consulter le résultat avant de lire et d'utiliser les signaux de confiance de l'appareil. Les appareils qui échouent aux vérifications de l'API Play Integrity ne doivent pas être considérés comme fiables, ni les signaux dérivés de l'appareil utilisé pour déterminer la posture de confiance. Pour en savoir plus, consultez la documentation de Play Integrity.
Intégrer le SDK AMAPI à votre application
Pour accéder aux signaux de confiance de l'appareil, votre application doit s'intégrer au SDK AMAPI. Pour en savoir plus sur cette bibliothèque et sur la façon de l'ajouter à votre application, consultez le guide d'intégration du SDK AMAPI.
Ajouter les autorisations requises
Certains des signaux renvoyés par l'API Device Trust from Android Enterprise exigent que l'application déclare la même autorisation que celle requise pour accéder à ces informations en premier lieu, en particulier :
Signal | Autorisation requise |
---|---|
État du réseau | ACCESS_NETWORK_STATE |
Complexité du verrouillage de l'écran | REQUEST_PASSWORD_COMPLEXITY |
Si ces autorisations ne sont pas incluses dans le AndroidManifest.xml
de l'application, l'API Device Trust from Android Enterprise renverra PERMISSION_ISSUE
dans les métadonnées du signal associé :
internalDeviceSettings=DeviceSettings{
screenLockComplexity=COMPLEXITY_UNSPECIFIED,
internalScreenLockComplexityMetadata=Metadata{
dataIssues=[
DataIssue{
issueType=PERMISSION_ISSUE,
issueLevel=WARNING,
issueDetails=IssueDetailsCase{none}
}
]
},
Pour en savoir plus, consultez la liste des signaux de confiance des appareils disponibles.
Étapes à suivre pour accéder aux signaux de confiance des appareils
Les applications qui souhaitent accéder aux signaux de confiance de l'appareil doivent vérifier que l'environnement client est à jour et le mettre à jour si nécessaire.
Pour accéder aux signaux de confiance des appareils :
- Vérifier l'environnement client
- Préparer l'environnement client
- Accéder aux signaux de confiance des appareils
Vérifier l'environnement client
L'exemple de code suivant montre comment utiliser getEnvironment
pour lire l'état actuel de l'application ADP. Votre application peut ensuite créer un deviceClient
pour accéder aux signaux de confiance des appareils si l'environnement est prêt et à jour (voir Accéder aux signaux de confiance des appareils).
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()); }
Si l'application ADP est installée, mais pas à jour, votre application doit appeler prepareEnvironment
pour mettre à jour l'application ADP de manière silencieuse, sans intervention de l'utilisateur.
Si l'application ADP n'est pas installée, votre application peut appeler prepareEnvironment
pour inviter l'utilisateur à l'installer. Consultez Préparer l'environnement client.
Préparer l'environnement client
Si l'application ADP est déjà installée, l'API la mettra à jour en mode silencieux, sans intervention de l'utilisateur.
Si l'application ADP n'est pas installée, l'API invite l'utilisateur à accepter l'installation de l'application ADP.
Il est possible d'enregistrer un rappel pour surveiller le choix de l'utilisateur. Pour en savoir plus, consultez Suivre l'interaction de l'utilisateur lors de l'installation de l'application ADP.
Nous vous recommandons d'effectuer l'appel prepareEnvironment
à partir d'un processus de premier plan, pendant le flux UX d'intégration, afin d'éviter de surprendre l'utilisateur avec la boîte de dialogue modale Installer Android Device Policy.
Si l'appel à partir d'un processus de premier plan n'est pas possible, car il s'agit d'un flux Web et que le composant Android n'a pas d'UI, l'appel à partir de l'arrière-plan est autorisé à condition qu'il se produise pendant le flux UX d'intégration.
Une fois l'environnement correctement configuré, il est possible d'accéder aux signaux de confiance de l'appareil. Consultez Accéder aux signaux de confiance des appareils.
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()); }
Accéder aux signaux de confiance des appareils
Pour accéder aux signaux de confiance de l'appareil qui vous intéressent, vous pouvez utiliser l'instance deviceClient
vue à l'étape précédente pour demander l'objet 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()); }
Suivre l'interaction des utilisateurs lors de l'installation de l'application ADP
Si l'appareil doit installer l'application ADP pendant l'état prepareEnvironment
, votre application peut suivre l'interaction de l'utilisateur en implémentant un NotificationReceiverService
pour recevoir des notifications en remplaçant 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"); } } }
Problèmes connus
Il n'y a aucun problème connu pour le moment.