Device Trust from Android Enterprise – Integrationsanleitung

Dieses Dokument sollte Ihr primärer Leitfaden für die Verwendung des AMAPI SDK zum Empfangen von Gerätevertrauenssignalen sein.

Mit dem AMAPI SDK kann Ihre Anwendung (die wir manchmal auch als „Companion“-App bezeichnen) auf Gerätezustandssignale der ADP-App (Android Device Policy) zugreifen. Ihre App kann diese Signale dann verwenden, um den Vertrauensstatus des Geräts zu berechnen und die ausgewählte Geschäftslogik auszuführen.

Vorbereitung

  • Der Zugriff auf die Device-Trust-Signale ist eingeschränkt, um eine unbefugte Nutzung zu verhindern. Informationen zur Bewerbung finden Sie auf der Seite Zugriff auf Device-Trust-Signale.
  • Android Enterprise empfiehlt, die Play Integrity-APIs in Ihre Clientanwendung zu integrieren und das Ergebnis zu berücksichtigen, bevor Sie die Gerätevertrauenssignale lesen und sich darauf verlassen. Geräte, die die Prüfungen der Play Integrity API nicht bestehen, sollten nicht als vertrauenswürdig eingestuft werden. Das gilt auch für alle Signale, die vom Gerät abgeleitet werden und zur Bestimmung des Vertrauensstatus verwendet werden. Weitere Informationen finden Sie in der Dokumentation zur Play Integrity API.

AMAPI SDK in Ihre Anwendung einbinden

Um auf die Signale für das Gerätevertrauen zuzugreifen, muss Ihre Anwendung in das AMAPI SDK eingebunden werden. Weitere Informationen zu dieser Bibliothek und dazu, wie Sie sie Ihrer Anwendung hinzufügen, finden Sie im Integrationsleitfaden für das AMAPI SDK.

Erforderliche Berechtigungen hinzufügen

Für einige der Signale, die von der Device Trust from Android Enterprise API zurückgegeben werden, muss die App dieselbe Berechtigung deklarieren, die erforderlich wäre, um auf diese Informationen zuzugreifen, insbesondere:

Signal Erforderliche Berechtigung
Netzwerkstatus ACCESS_NETWORK_STATE
Komplexität der Displaysperre REQUEST_PASSWORD_COMPLEXITY

Wenn diese Berechtigungen nicht im AndroidManifest.xml der App enthalten sind, gibt die Device Trust from Android Enterprise API PERMISSION_ISSUE in den Metadaten des zugehörigen Signals zurück:

internalDeviceSettings=DeviceSettings{
  screenLockComplexity=COMPLEXITY_UNSPECIFIED,
  internalScreenLockComplexityMetadata=Metadata{
    dataIssues=[
      DataIssue{
        issueType=PERMISSION_ISSUE,
        issueLevel=WARNING,
        issueDetails=IssueDetailsCase{none}
      }
    ]
  },

Weitere Informationen finden Sie in der Liste der verfügbaren Device Trust-Signale.

Schritte für den Zugriff auf die Device-Trust-Signale

Anwendungen, die auf die Device-Trust-Signale zugreifen möchten, müssen überprüfen, ob die Clientumgebung auf dem neuesten Stand ist, und sie gegebenenfalls aktualisieren.

So greifen Sie auf die Device-Trust-Signale zu:

Schritte für den Zugriff auf die Device-Trust-Signale

Clientumgebung überprüfen

Das folgende Codebeispiel zeigt, wie Sie getEnvironment verwenden, um den aktuellen Status der ADP-App zu lesen. Ihre Anwendung kann dann ein deviceClient erstellen, um auf die Device-Trust-Signale zuzugreifen, wenn die Umgebung bereit und aktuell ist (siehe Auf Device-Trust-Signale zugreifen).

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();

    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());
}

Wenn die ADP-App installiert, aber nicht auf dem neuesten Stand ist, sollte Ihre Anwendung prepareEnvironment aufrufen, um die ADP-App im Hintergrund ohne Nutzereingriff zu aktualisieren.

Wenn die ADP-App nicht installiert ist, kann Ihre Anwendung prepareEnvironment aufrufen, um den Nutzer aufzufordern, die ADP-App zu installieren. Weitere Informationen finden Sie unter Clientumgebung vorbereiten.

Clientumgebung vorbereiten

  • Wenn die ADP-App bereits installiert ist, wird sie von der API automatisch aktualisiert, ohne dass der Nutzer eingreifen muss.

  • Wenn die ADP-App nicht installiert ist, werden Nutzer von der API aufgefordert, die Installation der ADP-App zu akzeptieren.

Android Device Policy installieren

Es ist möglich, einen Callback zu registrieren, um die Auswahl des Nutzers zu überwachen. Weitere Informationen finden Sie unter Nutzerinteraktion während der Installation der ADP-App erfassen.

Wir empfehlen, den prepareEnvironment-Aufruf während des Onboarding-UX-Ablaufs über einen Vordergrundprozess auszuführen, um zu vermeiden, dass der Nutzer vom Modal-Dialogfeld Android Device Policy installieren überrascht wird. Wenn ein Aufruf über einen Vordergrundprozess nicht möglich ist, weil es sich um einen Web-Ablauf handelt und die Android-Komponente keine Benutzeroberfläche hat, ist ein Aufruf im Hintergrund zulässig. Dies muss jedoch während des Onboarding-UX-Ablaufs erfolgen.

Sobald die Umgebung richtig eingerichtet ist, können Sie auf die Device-Trust-Signale zugreifen. Weitere Informationen finden Sie unter Auf Device-Trust-Signale zugreifen.

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
    );

    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());
}

Auf Device-Trust-Signale zugreifen

Um auf die Device-Trust-Signale zuzugreifen, die Sie interessieren, können Sie die im vorherigen Schritt gezeigte deviceClient-Instanz verwenden, um das Device-Objekt anzufordern.

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 {
    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());
}

Nutzerinteraktionen während der Installation von ADP-Apps erfassen

Wenn auf dem Gerät die ADP-App während der prepareEnvironment installiert werden muss, kann Ihre Anwendung die Nutzerinteraktion mithilfe von NotificationReceiverService verfolgen, um Benachrichtigungen zu erhalten, die getPrepareEnvironmentListener überschreiben:

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");
        }
    }
}

Bekannte Probleme

Derzeit sind keine Probleme bekannt.