Android Management API (AMAPI) SDK 可讓 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 物件,其中包含目前的指令狀態和指令 ID,日後可用於查詢任何長時間執行指令的狀態。
抹除裝置或工作資料夾
當 IT 管理員指派 COMPANION_APP 角色並授予 LOCAL_DEVICE_WIPE_COMMAND_ALLOWED 額外功能時,隨附應用程式可以發出本機 Wipe 指令。如果是公司擁有的裝置,系統會將裝置恢復原廠設定;如果是設有工作資料夾的個人裝置,系統會移除工作資料夾。如果應用程式不具備這個角色和額外功能,要求就會失敗。詳情請參閱「政策設定」。
兩個 Wipe 參數皆為選用。如不想指定值,請省略建構工具 setter,或傳遞空白集合或空白字串 (請勿傳遞 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();
}
...
取得指令
擴充功能應用程式可以查詢先前發出的指令要求狀態。如要擷取指令狀態,您需要指令 ID (可從發出指令要求取得)。下列程式碼片段說明如何將 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());
}
...
監聽指令狀態變更回呼
擴充功能應用程式可選擇註冊回呼,接收長時間執行指令的狀態變更更新,步驟如下:
- 指令狀態變更會通知
CommandListener,請在應用程式中實作這個介面,並提供如何處理收到的狀態更新。 - 擴充
NotificationReceiverService,並透過getCommandListener方法提供CommandListener例項。 設定應用程式政策,將
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 必須使用應用程式政策中的 roles 欄位,將 COMPANION_APP 角色指派給應用程式:
"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 會使用應用程式資訊清單中的中繼資料,自動探索監聽指令狀態變更的服務,因此不再需要在政策中指定為 notificationReceiver。如要進一步瞭解如何準備應用程式和資訊清單,請參閱「管理應用程式角色」。
測試
單元測試
LocalCommandClient 是介面,因此可提供可測試的
實作。
整合測試
如要使用 ADP 進行測試,請提供下列資訊:
- 擴充功能應用程式的套件名稱。
- 與應用程式套件相關聯的簽章,採用 Base64 編碼的 SHA-256 雜湊。
- (選用) 如果要測試回呼,請提供新推出服務的完整名稱,以支援回呼。(範例中
CommandService的完整名稱)。