Device Trust from Android Enterprise – Hướng dẫn tích hợp

Tài liệu này sẽ là hướng dẫn chính của bạn về cách sử dụng AMAPI SDK cho mục đích nhận tín hiệu tin cậy của thiết bị.

AMAPI SDK cho phép ứng dụng của bạn (đôi khi chúng tôi có thể gọi là ứng dụng "Đồng hành") truy cập vào các tín hiệu tin cậy của thiết bị từ ứng dụng ADP (Chính sách thiết bị Android). Sau đó, ứng dụng của bạn có thể sử dụng các tín hiệu này để tính toán trạng thái tin cậy của thiết bị và thực hiện logic nghiệp vụ theo lựa chọn.

Điều kiện tiên quyết

  • Quyền truy cập vào tín hiệu tin cậy của thiết bị bị hạn chế để ngăn chặn việc sử dụng trái phép. Để biết thông tin về cách đăng ký, hãy truy cập trang quyền truy cập vào tín hiệu tin cậy của thiết bị.
  • Android Enterprise đề xuất tích hợp bộ API Tính toàn vẹn của Play vào ứng dụng khách và tham khảo kết quả trước khi đọc và dựa vào các tín hiệu tin cậy của thiết bị. Bạn không nên tin tưởng các thiết bị không vượt qua quy trình kiểm tra của API Tính toàn vẹn của Play, cũng như mọi tín hiệu bắt nguồn từ thiết bị được dùng để xác định trạng thái tin cậy. Bạn có thể tham khảo tài liệu của API Tính toàn vẹn của Play để biết thêm thông tin chi tiết.

Tích hợp với AMAPI SDK trong ứng dụng của bạn

Để truy cập vào các tín hiệu tin cậy của thiết bị, ứng dụng của bạn phải tích hợp với SDK AMAPI. Bạn có thể tìm thêm thông tin về thư viện này và cách thêm thư viện này vào ứng dụng của mình trong hướng dẫn tích hợp AMAPI SDK.

Thêm các quyền bắt buộc

Một số tín hiệu do Device Trust từ Android Enterprise API trả về yêu cầu ứng dụng khai báo cùng một quyền cần thiết để truy cập vào thông tin này ngay từ đầu, cụ thể là:

Tín hiệu Quyền bắt buộc
Trạng thái mạng ACCESS_NETWORK_STATE
Độ phức tạp của khoá màn hình REQUEST_PASSWORD_COMPLEXITY

Nếu các quyền này không có trong AndroidManifest.xml của ứng dụng, thì Device Trust from Android Enterprise API sẽ trả về PERMISSION_ISSUE trong siêu dữ liệu của tín hiệu liên quan:

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

Để biết thêm thông tin chi tiết, hãy xem danh sách các tín hiệu tin cậy của thiết bị hiện có.

Các bước để truy cập vào tín hiệu tin cậy của thiết bị

Những ứng dụng muốn truy cập vào tín hiệu tin cậy của thiết bị phải xác minh rằng môi trường máy khách đã được cập nhật và cập nhật nếu cần.

Các bước để truy cập vào tín hiệu tin cậy của thiết bị là:

Các bước để truy cập vào tín hiệu tin cậy của thiết bị

Xác minh môi trường máy khách

Ví dụ về mã sau đây cho biết cách sử dụng getEnvironment để đọc trạng thái hiện tại của ứng dụng ADP. Sau đó, ứng dụng của bạn có thể tạo một deviceClient để truy cập vào các tín hiệu tin cậy của thiết bị nếu môi trường đã sẵn sàng và được cập nhật (xem phần Truy cập vào các tín hiệu tin cậy của thiết bị).

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

Nếu ứng dụng ADP đã được cài đặt nhưng chưa được cập nhật, thì ứng dụng của bạn nên gọi prepareEnvironment để cập nhật ứng dụng ADP mà không cần người dùng can thiệp.

Nếu ứng dụng ADP chưa được cài đặt, ứng dụng của bạn có thể gọi prepareEnvironment để nhắc người dùng cài đặt ứng dụng ADP. Hãy xem phần Chuẩn bị môi trường máy khách.

Chuẩn bị môi trường máy khách

  • Nếu ứng dụng ADP đã được cài đặt, API sẽ tự động cập nhật ứng dụng đó mà không cần người dùng can thiệp.

  • Nếu ứng dụng ADP chưa được cài đặt, API sẽ nhắc người dùng chấp nhận cài đặt ứng dụng ADP.

Cài đặt Android Device Policy

Bạn có thể đăng ký một lệnh gọi lại để theo dõi lựa chọn của người dùng. Hãy xem phần Theo dõi hoạt động tương tác của người dùng trong quá trình cài đặt ứng dụng ADP để biết thêm thông tin chi tiết.

Bạn nên thực hiện lệnh gọi prepareEnvironment từ một quy trình nền trước, trong quy trình trải nghiệm người dùng khi bắt đầu sử dụng để tránh làm người dùng ngạc nhiên bằng hộp thoại phương thức Cài đặt Chính sách thiết bị Android. Nếu không thể gọi từ một quy trình trên nền trước, vì đây là một luồng Web và thành phần Android không có giao diện người dùng, thì bạn được phép gọi từ nền với yêu cầu là việc này xảy ra trong luồng trải nghiệm người dùng khi bắt đầu.

Sau khi thiết lập môi trường đúng cách, bạn có thể truy cập vào Tín hiệu tin cậy của thiết bị. Xem phần Truy cập vào tín hiệu tin cậy của thiết bị.

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

Truy cập vào tín hiệu tin tưởng thiết bị

Để truy cập vào các tín hiệu tin cậy của thiết bị mà bạn quan tâm, bạn có thể sử dụng thực thể deviceClient xuất hiện ở bước trước để yêu cầu đối tượng 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 {
    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());
}

Theo dõi hoạt động tương tác của người dùng trong quá trình cài đặt ứng dụng ADP

Nếu thiết bị cần cài đặt ứng dụng ADP trong prepareEnvironment, ứng dụng của bạn có thể theo dõi hoạt động tương tác của người dùng bằng cách triển khai NotificationReceiverService để nhận thông báo ghi đè 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");
        }
    }
}

Vấn đề đã biết

Hiện không có vấn đề nào đã biết.