Device Trust from Android Enterprise - คู่มือการผสานรวม

เอกสารนี้ควรเป็นคำแนะนำหลักสำหรับการใช้งาน AMAPI SDK เพื่อ วัตถุประสงค์ในการรับสัญญาณความน่าเชื่อถือของอุปกรณ์

AMAPI SDK ช่วยให้แอปพลิเคชันของคุณ (ซึ่งเราอาจเรียกว่าแอป "คู่หู" ในบางครั้ง) เข้าถึงสัญญาณความน่าเชื่อถือของอุปกรณ์จากแอป ADP (Android Device Policy) ได้ จากนั้นแอปของคุณจะใช้สัญญาณเหล่านี้เพื่อคำนวณสถานะความน่าเชื่อถือของอุปกรณ์และบังคับใช้ตรรกะทางธุรกิจตามที่เลือกได้

ข้อกำหนดเบื้องต้น

  • ระบบจำกัดการเข้าถึงสัญญาณความน่าเชื่อถือของอุปกรณ์เพื่อป้องกันการใช้งานโดยไม่ได้รับอนุญาต ดูข้อมูลเกี่ยวกับวิธีสมัครได้ที่หน้าสิทธิ์เข้าถึงสัญญาณความน่าเชื่อถือของอุปกรณ์
  • Android Enterprise ขอแนะนำให้ผสานรวมชุด API ของ Play Integrity เข้ากับแอปพลิเคชันไคลเอ็นต์และอ้างอิงผลลัพธ์ก่อนที่จะอ่านและ ใช้สัญญาณความน่าเชื่อถือของอุปกรณ์ ไม่ควรเชื่อถืออุปกรณ์ที่ไม่ผ่านการตรวจสอบ Play Integrity API รวมถึงสัญญาณใดๆ ที่ได้จากอุปกรณ์ที่ใช้ในการ กำหนดท่าทางความน่าเชื่อถือ ดูรายละเอียดเพิ่มเติมได้ในเอกสารประกอบของ Play Integrity

ผสานรวมกับ AMAPI SDK ในแอปพลิเคชัน

หากต้องการเข้าถึงสัญญาณความน่าเชื่อถือของอุปกรณ์ แอปพลิเคชันของคุณต้องผสานรวมกับ AMAPI SDK ดูข้อมูลเพิ่มเติมเกี่ยวกับไลบรารีนี้และวิธีเพิ่มลงในแอปพลิเคชันได้ในคู่มือการผสานรวม AMAPI SDK

เพิ่มสิทธิ์ที่จำเป็น

สัญญาณบางอย่างที่ส่งคืนจาก Device Trust จาก Android Enterprise API กำหนดให้แอปต้องประกาศสิทธิ์เดียวกันกับที่จำเป็นต้องใช้เพื่อ เข้าถึงข้อมูลนี้ตั้งแต่แรก โดยเฉพาะอย่างยิ่ง

สัญญาณ สิทธิ์ที่จำเป็น
สถานะเครือข่าย ACCESS_NETWORK_STATE
ความซับซ้อนของการล็อกหน้าจอ REQUEST_PASSWORD_COMPLEXITY

หากไม่ได้รวมสิทธิ์เหล่านี้ไว้ใน AndroidManifest.xml ของแอป Device Trust จาก 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();

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

หากติดตั้งแอป ADP แต่ไม่ได้อัปเดตแอปให้เป็นเวอร์ชันล่าสุด แอปพลิเคชันของคุณควรเรียกใช้ prepareEnvironment เพื่ออัปเดตแอป ADP แบบเงียบโดยไม่ต้องมีการโต้ตอบจากผู้ใช้

หากไม่ได้ติดตั้งแอป ADP แอปพลิเคชันของคุณสามารถเรียกใช้ prepareEnvironment เพื่อแจ้งให้ผู้ใช้ติดตั้งแอป ADP ได้ โปรดดูเตรียมสภาพแวดล้อมของไคลเอ็นต์

เตรียมสภาพแวดล้อมของไคลเอ็นต์

  • หากติดตั้งแอป ADP ไว้แล้ว API จะอัปเดตแอปโดยอัตโนมัติโดยไม่ต้องมีการดำเนินการจากผู้ใช้

  • หากไม่ได้ติดตั้งแอป ADP ไว้ API จะแจ้งให้ผู้ใช้ยอมรับการติดตั้งแอป ADP

ติดตั้ง Android Device Policy

คุณสามารถลงทะเบียนการเรียกกลับเพื่อตรวจสอบตัวเลือกของผู้ใช้ได้ ดูรายละเอียดเพิ่มเติมได้ที่ ติดตามการโต้ตอบของผู้ใช้ระหว่างการติดตั้งแอป ADP

เราขอแนะนำให้เรียกใช้ prepareEnvironment จากกระบวนการเบื้องหน้า ในระหว่างขั้นตอน UX การเริ่มต้นใช้งานเพื่อหลีกเลี่ยงไม่ให้ผู้ใช้ประหลาดใจกับกล่องโต้ตอบโมดอลติดตั้ง Android Device Policy หากเรียกจากกระบวนการที่ทำงานอยู่เบื้องหน้าไม่ได้เนื่องจากเป็นโฟลว์ของเว็บและคอมโพเนนต์ 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
    );

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

เข้าถึงสัญญาณความน่าเชื่อถือของอุปกรณ์

ท่าทางของอุปกรณ์

หากต้องการเข้าถึงสัญญาณความน่าเชื่อถือของอุปกรณ์ที่คุณสนใจ คุณสามารถใช้ 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 {
    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());
}

ติดตามการโต้ตอบของผู้ใช้ระหว่างการติดตั้งแอป ADP

หากอุปกรณ์ต้องติดตั้งแอป ADP ในช่วง prepareEnvironment แอปพลิเคชันของคุณจะติดตามการโต้ตอบของผู้ใช้ได้โดยใช้ 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");
        }
    }
}

ปัญหาที่ทราบ

ขณะนี้ยังไม่มีปัญหาที่ทราบ