SDK ของ Android Management API (AMAPI) ช่วยให้แอปส่วนขยายที่ EMM ระบุสามารถสื่อสารกับ Android Device Policy (ADP) ได้โดยตรงและเรียกใช้ Commands ในอุปกรณ์
ผสานรวมกับ AMAPI SDK ให้ข้อมูลเพิ่มเติมเกี่ยวกับไลบรารีนี้และวิธีเพิ่มลงในแอปพลิเคชัน
เมื่อผสานรวม SDK แล้ว แอปส่วนขยายจะสื่อสารกับ ADP เพื่อดำเนินการต่อไปนี้ได้
ออกคำสั่ง
แอปส่วนขยายสามารถขอให้ออกคำสั่งโดยใช้ ADP ได้
IssueCommandRequest มีออบเจ็กต์คำขอซึ่งจะมีรายละเอียดเกี่ยวกับคำสั่งที่จะออกและพารามิเตอร์ที่เฉพาะเจาะจง
ล้างข้อมูลแอป
ข้อมูลโค้ดต่อไปนี้แสดงวิธีส่งคำขอเพื่อล้างข้อมูลของแพ็กเกจ
import android.util.Log;
...
import com.google.android.managementapi.commands.LocalCommandClientFactory;
import com.google.android.managementapi.commands.model.Command;
import com.google.android.managementapi.commands.model.GetCommandRequest;
import com.google.android.managementapi.commands.model.IssueCommandRequest;
import com.google.android.managementapi.commands.model.IssueCommandRequest.ClearAppsData;
import com.google.common.collect.ImmutableList;
import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.MoreExecutors;
...
void issueClearAppDataCommand(ImmutableList<String> packageNames) {
Futures.addCallback(
LocalCommandClientFactory.create(getContext())
.issueCommand(createClearAppRequest(packageNames)),
new FutureCallback<Command>() {
@Override
public void onSuccess(Command result) {
// Process the returned command result here
Log.i(TAG, "Successfully issued command");
}
@Override
public void onFailure(Throwable t) {
Log.e(TAG, "Failed to issue command", t);
}
},
MoreExecutors.directExecutor());
}
IssueCommandRequest createClearAppRequest(ImmutableList<String> packageNames) {
return IssueCommandRequest.builder()
.setClearAppsData(
ClearAppsData.builder()
.setPackageNames(packageNames)
.build()
)
.build();
}
...
ตัวอย่างก่อนหน้านี้แสดงการออกคำขอล้างข้อมูลแอปสำหรับแพ็กเกจที่ระบุและรอจนกว่าจะออกคำสั่งเรียบร้อยแล้ว หากออกคำสั่งสำเร็จ ระบบจะแสดงผลออบเจ็กต์ Command พร้อมสถานะคำสั่งปัจจุบันและรหัสคำสั่ง ซึ่งสามารถใช้เพื่อค้นหาสถานะของคำสั่งที่ใช้เวลานานในภายหลังได้
ล้างข้อมูลในอุปกรณ์หรือโปรไฟล์งาน
แอปที่ใช้ร่วมกันสามารถออกคำสั่ง Wipe ในเครื่องได้เมื่อผู้ดูแลระบบไอทีมอบหมายบทบาท COMPANION_APP ที่มีความสามารถพิเศษ LOCAL_DEVICE_WIPE_COMMAND_ALLOWED ในอุปกรณ์ของบริษัท การดำเนินการนี้จะรีเซ็ตอุปกรณ์เป็นค่าเริ่มต้น ส่วนในอุปกรณ์ส่วนตัวที่มีโปรไฟล์งาน การดำเนินการนี้จะนำโปรไฟล์งานออก หากแอปไม่มีบทบาทและความสามารถเพิ่มเติมนี้ คำขอจะดำเนินการไม่สำเร็จ โปรดดูรายละเอียดที่หัวข้อการกำหนดค่านโยบาย
พารามิเตอร์ Wipe ทั้ง 2 รายการเป็นพารามิเตอร์ที่ไม่บังคับ หากไม่ต้องการระบุค่า ให้ละเว้นเมธอด Setter ของ Builder หรือส่งคอลเล็กชันว่างหรือสตริงว่าง (อย่าส่ง null)
- ค่า
WipeDataFlagจะควบคุมข้อมูลที่จะล้าง ดังนี้PRESERVE_RESET_PROTECTION_DATA: เก็บข้อมูลการป้องกันการรีเซ็ตเป็นค่าเริ่มต้น ซึ่งจะถูกล้างโดยค่าเริ่มต้น มีผลกับอุปกรณ์ของบริษัทเท่านั้นWIPE_EXTERNAL_STORAGE: ล้างข้อมูลในที่จัดเก็บข้อมูลภายนอก เช่น การ์ด SD ด้วย มีผลกับอุปกรณ์ของบริษัทเท่านั้นWIPE_ESIMS: นำ eSIM ทั้งหมดออกจากอุปกรณ์ของบริษัท ในอุปกรณ์ส่วนตัว ระบบจะนำเฉพาะ eSIM ที่มีการจัดการออก (ใน Android 16 ขึ้นไป ระบบจะนำ eSIM ที่มีการจัดการออกพร้อมกับโปรไฟล์งานเสมอ ไม่ว่าจะตั้งค่าแฟล็กนี้หรือไม่ก็ตาม)
wipeReason: ข้อความสั้นๆ ไม่เกิน 200 อักขระที่จะแสดงให้ผู้ใช้เห็นเมื่อมีการนำโปรไฟล์งานออกจากอุปกรณ์ส่วนตัว แต่จะไม่มีผลกับอุปกรณ์ของบริษัท
ข้อมูลโค้ดต่อไปนี้แสดงวิธีส่งคำขอเพื่อล้างข้อมูลในอุปกรณ์หรือโปรไฟล์งาน
Kotlin
import android.content.Context
import android.util.Log
...
import com.google.android.managementapi.commands.CommandException
import com.google.android.managementapi.commands.LocalCommandClientFactory
import com.google.android.managementapi.commands.model.IssueCommandRequest
import com.google.android.managementapi.commands.model.IssueCommandRequest.Wipe
import com.google.android.managementapi.commands.model.IssueCommandRequest.Wipe.WipeDataFlag
...
suspend fun issueWipeCommand(
context: Context,
wipeDataFlags: List<WipeDataFlag>,
wipeReason: String,
) {
try {
val command =
LocalCommandClientFactory.create(context)
.issueCommandAwait(createWipeRequest(wipeDataFlags, wipeReason))
Log.i(TAG, "Successfully issued wipe command: ${command.commandId}")
} catch (e: CommandException) {
Log.e(TAG, "Failed to issue wipe command", e)
}
}
fun createWipeRequest(
wipeDataFlags: List<WipeDataFlag>,
wipeReason: String,
): IssueCommandRequest =
IssueCommandRequest.builder()
.setWipe(
Wipe.builder()
.setWipeDataFlags(wipeDataFlags)
.setWipeReason(wipeReason)
.build()
)
.build()
...
Java
import android.content.Context;
import android.util.Log;
...
import com.google.android.managementapi.commands.LocalCommandClientFactory;
import com.google.android.managementapi.commands.model.Command;
import com.google.android.managementapi.commands.model.IssueCommandRequest;
import com.google.android.managementapi.commands.model.IssueCommandRequest.Wipe;
import com.google.android.managementapi.commands.model.IssueCommandRequest.Wipe.WipeDataFlag;
import com.google.common.collect.ImmutableList;
import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.MoreExecutors;
...
void issueWipeCommand(
Context context,
ImmutableList<WipeDataFlag> wipeDataFlags,
String wipeReason) {
Futures.addCallback(
LocalCommandClientFactory.create(context)
.issueCommand(createWipeRequest(wipeDataFlags, wipeReason)),
new FutureCallback<Command>() {
@Override
public void onSuccess(Command result) {
Log.i(TAG, "Successfully issued wipe command: " + result.getCommandId());
}
@Override
public void onFailure(Throwable t) {
Log.e(TAG, "Failed to issue wipe command", t);
}
},
MoreExecutors.directExecutor());
}
IssueCommandRequest createWipeRequest(
ImmutableList<WipeDataFlag> wipeDataFlags, String wipeReason) {
return IssueCommandRequest.builder()
.setWipe(
Wipe.builder()
.setWipeDataFlags(wipeDataFlags)
.setWipeReason(wipeReason)
.build())
.build();
}
...
รับคำสั่ง
แอปส่วนขยายสามารถค้นหาสถานะของคำขอคำสั่งที่ออกก่อนหน้านี้ได้ หากต้องการเรียกดูสถานะของคำสั่ง คุณจะต้องใช้รหัสคำสั่ง (ดูได้จากคำขอคำสั่งปัญหา) ข้อมูลโค้ดต่อไปนี้แสดงวิธีส่ง GetCommandRequest ไปยัง ADP
import android.util.Log;
...
import com.google.android.managementapi.commands.LocalCommandClientFactory;
...
import com.google.android.managementapi.commands.model.GetCommandRequest;
import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.MoreExecutors;
...
void getCommand(String commandId) {
Futures.addCallback(
LocalCommandClientFactory.create(getApplication())
.getCommand(GetCommandRequest.builder().setCommandId(commandId).build()),
new FutureCallback<Command>() {
@Override
public void onSuccess(Command result) {
// Process the returned command result here
Log.i(Constants.TAG, "Successfully issued command");
}
@Override
public void onFailure(Throwable t) {
Log.e(Constants.TAG, "Failed to issue command", t);
}
},
MoreExecutors.directExecutor());
}
...
ฟัง Callback การเปลี่ยนแปลงสถานะคำสั่ง
แอปส่วนขยายสามารถเลือกที่จะลงทะเบียน Callback เพื่อรับข้อมูลอัปเดตเกี่ยวกับการเปลี่ยนแปลงสถานะของคำสั่งที่ใช้เวลานานได้โดยทำตามขั้นตอนต่อไปนี้
- ระบบจะแจ้งการเปลี่ยนแปลงสถานะคำสั่งไปยัง
CommandListenerใช้อินเทอร์เฟซนี้ในแอปและระบุการติดตั้งใช้งานเกี่ยวกับวิธีจัดการการอัปเดตสถานะที่ได้รับ - ขยาย
NotificationReceiverServiceและระบุอินสแตนซ์CommandListenerผ่านเมธอดgetCommandListener กำหนดค่านโยบายแอปพลิเคชันเพื่อมอบหมายบทบาท
COMPANION_APPให้กับแอป (ดูการกำหนดค่านโยบาย)import com.google.android.managementapi.commands.CommandListener; import com.google.android.managementapi.notification.NotificationReceiverService; ... public class SampleCommandService extends NotificationReceiverService { @Override public CommandListener getCommandListener() { // return the concrete implementation from previous step return ...; } }
การกำหนดค่านโยบาย
หากต้องการเปิดใช้แอปที่ใช้ร่วมกันเพื่อสื่อสารกับ ADP โดยตรง EMM จะต้องมอบหมายบทบาท COMPANION_APP ให้กับแอปโดยใช้ช่อง roles ในนโยบายสำหรับแอปพลิเคชัน ดังนี้
"applications": [{
"packageName": "com.amapi.extensibility.demo",
"installType": "FORCE_INSTALLED",
"roles": [
{ "roleType": "COMPANION_APP" }
]
}]
หากต้องการอนุญาตให้แอปที่ใช้ร่วมกันออกคำสั่ง Wipe ในเครื่อง ให้ตั้งค่า extraCapabilities.localDeviceWipeCommand เป็น LOCAL_DEVICE_WIPE_COMMAND_ALLOWED ดังนี้
"applications": [{
"packageName": "com.amapi.extensibility.demo",
"installType": "FORCE_INSTALLED",
"roles": [
{
"roleType": "COMPANION_APP",
"extraCapabilities": {
"localDeviceWipeCommand": "LOCAL_DEVICE_WIPE_COMMAND_ALLOWED"
}
}
]
}]
ดูตัวเลือกอื่นๆ ที่มีได้ที่หัวข้อจัดสรรอุปกรณ์ด้วยนโยบายบทบาทของแอป
ADP จะค้นพบบริการที่คอยฟังการเปลี่ยนแปลงสถานะคำสั่งโดยอัตโนมัติโดยใช้ข้อมูลเมตาในไฟล์ Manifest ของแอป และไม่จำเป็นต้องระบุในนโยบายเป็น notificationReceiver อีกต่อไป โปรดดูรายละเอียดเกี่ยวกับวิธีเตรียมแอปและไฟล์ Manifest ที่หัวข้อจัดการบทบาทของแอปพลิเคชัน
การทดสอบ
การทำ Unit Test
LocalCommandClient เป็นอินเทอร์เฟซ จึงช่วยให้คุณระบุการใช้งานที่ทดสอบได้
การทดสอบการผสานรวม
คุณจะต้องใช้ข้อมูลต่อไปนี้เพื่อทดสอบกับ ADP
- ชื่อแพ็กเกจของแอปส่วนขยาย
- แฮช SHA-256 ที่เข้ารหัส Base64 ของลายเซ็นที่เชื่อมโยงกับแพ็กเกจแอป
- ไม่บังคับ หากทดสอบ Callback - ชื่อที่สมบูรณ์ในตัวเองของบริการจากบริการที่เปิดตัวใหม่เพื่อรองรับ Callback (ชื่อที่สมบูรณ์ในตัวเองของ
CommandServiceในตัวอย่าง)