擴充功能應用程式和本機指令

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

監聽指令狀態變更回呼

擴充功能應用程式可選擇註冊回呼,接收長時間執行指令的狀態變更更新,步驟如下:

  1. 指令狀態變更會通知 CommandListener,請在應用程式中實作這個介面,並提供如何處理收到的狀態更新。
  2. 擴充 NotificationReceiverService,並透過 getCommandListener 方法提供 CommandListener 例項。
  3. 設定應用程式政策,將 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 進行測試,請提供下列資訊:

  1. 擴充功能應用程式的套件名稱。
  2. 與應用程式套件相關聯的簽章,採用 Base64 編碼的 SHA-256 雜湊。
  3. (選用) 如果要測試回呼,請提供新推出服務的完整名稱,以支援回呼。(範例中 CommandService 的完整名稱)。