برنامه‌های افزونه و فرمان‌های محلی

کیت توسعه نرم‌افزار Android Management API (AMAPI) به برنامه افزونه مشخص‌شده توسط EMM امکان می‌دهد مستقیماً با Android Device Policy (ADP) ارتباط برقرار کند و Commands را در دستگاه اجرا کند.

ادغام با AMAPI 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 با وضعیت فرمان فعلی و شناسه فرمان برگردانده می‌شود که بعداً می‌توان از آن برای پرسمان وضعیت هر فرمان طولانی‌مدت استفاده کرد.

پاک کردن دستگاه یا نمایه کاری

وقتی سرپرست فناوری اطلاعات نقش COMPANION_APP را با قابلیت اضافی LOCAL_DEVICE_WIPE_COMMAND_ALLOWED اختصاص می‌دهد، برنامه همراه می‌تواند فرمان محلی Wipe را صادر کند. در دستگاه‌های متعلق به شرکت، این کار دستگاه را بازنشانی کارخانه‌ای می‌کند؛ در دستگاه‌های متعلق به شخص با نمایه کاری، نمایه کاری را برمی‌دارد. اگر برنامه این نقش و قابلیت اضافی را نداشته باشد، درخواست ناموفق خواهد بود. برای جزئیات، به پیکربندی خط‌مشی مراجعه کنید.

هر دو پارامتر Wipe اختیاری هستند. اگر نمی‌خواهید مقداری را مشخص کنید، سازنده تنظیم‌کننده را حذف کنید یا مجموعه خالی یا رشته خالی ارسال کنید (null را ارسال نکنید).

  • WipeDataFlag مقادیر کنترل می‌کنند چه داده‌هایی پاک شود:
    • PRESERVE_RESET_PROTECTION_DATA: داده‌های محافظت پس‌از بازنشانی کارخانه‌ای را که به‌طور پیش‌فرض پاک می‌شود نگه می‌دارد. فقط برای دستگاه‌های متعلق به شرکت اعمال می‌شود.
    • WIPE_EXTERNAL_STORAGE: همچنین فضای ذخیره‌سازی خارجی، مانند کارت‌های SD را پاک می‌کند. فقط برای دستگاه‌های متعلق به شرکت اعمال می‌شود.
    • ‫WIPE_ESIMS: همه سیم‌کارت‌های داخلی را از دستگاه‌های متعلق به شرکت برمی‌دارد. در دستگاه‌های تحت مالکیت شخصی، فقط سیم‌کارت‌های داخلی مدیریت‌شده را برمی‌دارد (در Android 16 یا بالاتر، سیم‌کارت‌های داخلی مدیریت‌شده همیشه با نمایه کاری برداشته می‌شوند، چه این پرچم تنظیم شده باشد چه نشده باشد).
  • wipeReason: پیام کوتاهی با حداکثر ۲۰۰ نویسه که وقتی نمایه کاری از دستگاه تحت مالکیت شخصی برداشته می‌شود به کاربر نشان داده می‌شود. این تنظیم بر دستگاه‌های تحت مالکیت شرکت تأثیری ندارد.

قطعه کد زیر نحوه صدور درخواست برای پاک کردن دستگاه یا نمایه کاری را نشان می‌دهد:

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

جاوا

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

گوش دادن به فراخوانی‌های برگشتی تغییر وضعیت فرمان

برنامه افزونه می‌تواند به‌طور اختیاری یک فراخوان برگشتی را ثبت کند تا به‌روزرسانی‌های مربوط به تغییرات وضعیت فرمان‌های طولانی‌مدت را با دنبال کردن این مراحل دریافت کند:

  1. تغییرات وضعیت فرمان به CommandListener اطلاع داده می‌شود، این میانای کاربری را در برنامه‌تان پیاده‌سازی کنید و نحوه مدیریت به‌روزرسانی‌های وضعیت دریافتی را ارائه دهید.
  2. NotificationReceiverService را گسترش دهید و نمونه CommandListener را ازطریق روش getCommandListener ارائه دهید.
  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 باید نقش 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 بااستفاده از فراداده در مانیفست برنامه شناسایی می‌شود و دیگر لازم نیست در خط‌مشی به‌عنوان notificationReceiver مشخص شود. برای جزئیات درباره نحوه آماده‌سازی برنامه و مانیفست، به مدیریت نقش‌های برنامه مراجعه کنید.

آزمایش

آزمون واحد

LocalCommandClient یک میانای کاربر است و بنابراین امکان ارائه یک پیاده‌سازی قابل‌آزمایش را فراهم می‌کند.

آزمایش یکپارچه‌سازی

برای آزمایش با ADP به اطلاعات زیر نیاز است:

  1. نام بسته برنامه افزونه.
  2. درهم‌سازی SHA-256 کدبندی‌شده با base64 از «امضای» مرتبط با بسته برنامه.
  3. اختیاراً، اگر آزمایش فراخوانی برگشتی - نام کاملاً واجد شرایط سرویس از سرویس جدیداً معرفی‌شده برای پشتیبانی از فراخوانی برگشتی. (نام کاملاً واجدشرایط CommandService در مثال).