扩展程序应用和本地命令
使用集合让一切井井有条
根据您的偏好保存内容并对其进行分类。
Android Management API (AMAPI) SDK 支持 EMM 指定的扩展应用直接与 Android 设备政策 (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,该 ID 稍后可用于查询任何长时间运行的命令的状态。
获取命令
扩展程序可以查询之前发出的命令请求的状态。如需检索命令的状态,您需要提供命令 ID(可从发出命令请求中获取)。以下代码段展示了如何向 ADP 发送 GetCommandRequest
。
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
实例。
在 Android Management API 政策中指定扩展 NotificationReceiverService
的类名称(请参阅政策配置)。
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 必须提供 extensionConfig
政策。
"applications": [{
"packageName": "com.amapi.extensibility.demo",
...
"extensionConfig": {
"signingKeyFingerprintsSha256": [
// Include signing key of extension app
],
// Optional if callback is implemented
"notificationReceiver": "com.amapi.extensibility.demo.notification.SampleCommandService"
}
}]
测试
单元测试
LocalCommandClient
是一个接口,因此可以提供可测试的实现。
集成测试
如需使用 ADP 进行测试,您需要提供以下信息:
- 扩展程序应用的软件包名称。
- 与应用软件包关联的签名的十六进制编码 SHA-256 哈希值。
- 可选(如果测试回调)- 新引入的服务中支持回调的服务的完全限定名称。(示例中
CommandService
的完全限定名称)。
如未另行说明,那么本页面中的内容已根据知识共享署名 4.0 许可获得了许可,并且代码示例已根据 Apache 2.0 许可获得了许可。有关详情,请参阅 Google 开发者网站政策。Java 是 Oracle 和/或其关联公司的注册商标。
最后更新时间 (UTC):2025-07-26。
[null,null,["最后更新时间 (UTC):2025-07-26。"],[[["\u003cp\u003eThe Android Management API (AMAPI) SDK enables extension apps to communicate directly with Android Device Policy (ADP) to execute commands on the device.\u003c/p\u003e\n"],["\u003cp\u003eThe SDK currently supports the \u003ccode\u003eClearAppData\u003c/code\u003e command, which allows for the clearing of specified app data.\u003c/p\u003e\n"],["\u003cp\u003eExtension apps can issue command requests to ADP, query the status of these requests, and receive updates on status changes through callbacks.\u003c/p\u003e\n"],["\u003cp\u003eTo enable communication between the extension app and ADP, the EMM must provide an \u003ccode\u003eextensionConfig\u003c/code\u003e policy that includes the extension app's package name, signing key fingerprint, and optionally, a notification receiver service.\u003c/p\u003e\n"],["\u003cp\u003eTesting can be achieved through unit testing with the \u003ccode\u003eLocalCommandClient\u003c/code\u003e interface, or through integration testing, using the package name, SHA-256 hash, and notification service.\u003c/p\u003e\n"]]],["The Android Management API (AMAPI) SDK allows an extension app to interact with Android Device Policy (ADP). It enables sending command requests, querying their status, and receiving status change callbacks. The SDK supports the `ClearAppData` command to clear specified apps' data. To issue a command, `IssueCommandRequest` is used, and the status can be retrieved with `GetCommandRequest`, providing a Command Id. The `CommandListener` interface and `NotificationReceiverService` class allow the app to receive updates on status changes. The `extensionConfig` policy, specified by an EMM, enables this communication.\n"],null,["# Extension apps and local commands\n\nThe Android Management API (AMAPI) SDK enables an EMM-specified extension app to\ncommunicate directly with Android Device Policy (ADP) and execute [`Commands`](/android/management/reference/amapi/com/google/android/managementapi/commands/package-summary)\non the device.\n| **Note:** Only the [`ClearAppData`](/android/management/reference/rest/v1/enterprises.devices/issueCommand#CommandType.ENUM_VALUES.CLEAR_APP_DATA) command is supported.\n\n[Integrate with the AMAPI SDK](/android/management/sdk-integration) provides more information about\nthis library and how to add it to your application.\n\nOnce integrated the SDK, your extension app can communicate with ADP to:\n\n- [send command requests](#issue_command)\n- [query the status of command requests](#get_command)\n- [receive command status changes](#listen_to_callbacks)\n\nIssue Command\n-------------\n\nAn extension app can request for commands to be issued using ADP.\n[`IssueCommandRequest`](/android/management/reference/amapi/com/google/android/managementapi/commands/model/IssueCommandRequest) contains the request object that will contain detail on\nthe command to be issued and specific parameters.\n\nThe following snippet shows how to issue a request to clear the package's data: \n\n import android.util.Log;\n ...\n import com.google.android.managementapi.commands.LocalCommandClientFactory;\n import com.google.android.managementapi.commands.model.Command;\n import com.google.android.managementapi.commands.model.GetCommandRequest;\n import com.google.android.managementapi.commands.model.IssueCommandRequest;\n import com.google.android.managementapi.commands.model.IssueCommandRequest.ClearAppsData;\n import com.google.common.collect.ImmutableList;\n import com.google.common.util.concurrent.FutureCallback;\n import com.google.common.util.concurrent.Futures;\n import com.google.common.util.concurrent.MoreExecutors;\n\n ...\n void issueClearAppDataCommand(ImmutableList\u003cString\u003e packageNames) {\n Futures.addCallback(\n LocalCommandClientFactory.create(getContext())\n .issueCommand(createClearAppRequest(packageNames)),\n new FutureCallback\u003cCommand\u003e() {\n @Override\n public void onSuccess(Command result) {\n // Process the returned command result here\n Log.i(TAG, \"Successfully issued command\");\n }\n\n @Override\n public void onFailure(Throwable t) {\n Log.e(TAG, \"Failed to issue command\", t);\n }\n },\n MoreExecutors.directExecutor());\n }\n\n IssueCommandRequest createClearAppRequest(ImmutableList\u003cString\u003e packageNames) {\n return IssueCommandRequest.builder()\n .setClearAppsData(\n ClearAppsData.builder()\n .setPackageNames(packageNames)\n .build()\n )\n .build();\n }\n ...\n\nThe earlier example shows issuing a clear app data request for specified\npackages and waiting until the command has been successfully issued. If\nsuccessfully issued, a `Command` object will be returned with the current\ncommand status and the command ID which can later be used to query the status of\nany long running commands.\n\nGet Command\n-----------\n\nAn extension app can query the status of previously issued command requests. To\nretrieve a command's status, you will need the command ID (available from the\nissue command request). The following snippet shows how to send a\n[`GetCommandRequest`](/android/management/reference/amapi/com/google/android/managementapi/commands/model/GetCommandRequest) to ADP. \n\n import android.util.Log;\n ...\n import com.google.android.managementapi.commands.LocalCommandClientFactory;\n ...\n import com.google.android.managementapi.commands.model.GetCommandRequest;\n import com.google.common.util.concurrent.FutureCallback;\n import com.google.common.util.concurrent.Futures;\n import com.google.common.util.concurrent.MoreExecutors;\n\n ...\n void getCommand(String commandId) {\n Futures.addCallback(\n LocalCommandClientFactory.create(getApplication())\n .getCommand(GetCommandRequest.builder().setCommandId(commandId).build()),\n new FutureCallback\u003cCommand\u003e() {\n @Override\n public void onSuccess(Command result) {\n // Process the returned command result here\n Log.i(Constants.TAG, \"Successfully issued command\");\n }\n\n @Override\n public void onFailure(Throwable t) {\n Log.e(Constants.TAG, \"Failed to issue command\", t);\n }\n },\n MoreExecutors.directExecutor());\n }\n ...\n\nListen to Command status change callbacks\n-----------------------------------------\n\nAn extension app can optionally register a callback to receive updates for\nstatus changes of long running commands following these steps:\n\n1. Command status changes are notified to [`CommandListener`](/android/management/reference/amapi/com/google/android/managementapi/commands/CommandListener), implement this interface in your app and provide implementation on how to handle the received status updates.\n2. Extend [`NotificationReceiverService`](/android/management/sdk-integration#notification_receiver_service) and provide a `CommandListener` instance through the `getCommandListener` method.\n3. Specify class name of extended `NotificationReceiverService` in the Android\n Management API policy ([see Policy Configuration](#policy)).\n\n import com.google.android.managementapi.commands.CommandListener;\n import com.google.android.managementapi.notification.NotificationReceiverService;\n\n ...\n\n public class SampleCommandService extends NotificationReceiverService {\n\n @Override\n public CommandListener getCommandListener() {\n // return the concrete implementation from previous step\n return ...;\n }\n }\n\nPolicy Configuration\n--------------------\n\nTo enable the extension app to communicate directly with ADP, the EMM has to\nprovide an [`extensionConfig`](/android/management/reference/rest/v1/enterprises.policies#ExtensionConfig) policy. \n\n \"applications\": [{\n \"packageName\": \"com.amapi.extensibility.demo\",\n ...\n \"extensionConfig\": {\n \"signingKeyFingerprintsSha256\": [\n // Include signing key of extension app\n ],\n // Optional if callback is implemented\n \"notificationReceiver\": \"com.amapi.extensibility.demo.notification.SampleCommandService\"\n }\n }]\n\n### Testing\n\n#### Unit testing\n\n[`LocalCommandClient`](/android/management/reference/amapi/com/google/android/managementapi/commands/LocalCommandClient) is an interface and thus allows to provide a testable\nimplementation.\n\n#### Integration testing\n\nThe following information will be needed to test with ADP:\n\n1. Package name of the extension app.\n2. The hex-encoded SHA-256 hash of the Signature associated with the app package.\n3. Optionally, if testing callback - fully qualified name of the service from the newly introduced service to support callback. (Fully qualified name of `CommandService` in the example)."]]