Uzantı uygulamaları ve yerel komutlar

Android Management API (AMAPI) SDK'sı, EMM tarafından belirtilen bir uzantı uygulamasının doğrudan Android Device Policy (ADP) ile iletişim kurmasına ve cihazda Commands yürütmesine olanak tanır.

AMAPI SDK'sı ile entegrasyon bölümünde bu kitaplık ve uygulamanıza nasıl ekleneceği hakkında daha fazla bilgi verilmektedir.

SDK entegre edildikten sonra uzantı uygulamanız ADP ile iletişim kurarak şunları yapabilir:

Komut verme

Uzantı uygulaması, ADP kullanılarak komutların verilmesini isteyebilir. IssueCommandRequest, verilecek komut ve belirli parametrelerle ilgili ayrıntıları içeren istek nesnesini içerir.

Uygulama verilerini temizleme

Aşağıdaki snippet'te, paketin verilerini temizleme isteğinin nasıl gönderileceği gösterilmektedir:

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

Önceki örnekte, belirtilen paketler için uygulama verilerini temizleme isteğinin nasıl gönderildiği ve komutun başarıyla gönderilmesinin nasıl beklendiği gösterilmektedir. Başarıyla verilirse geçerli komut durumunu ve daha sonra uzun süre çalışan komutların durumunu sorgulamak için kullanılabilecek komut kimliğini içeren bir Command nesnesi döndürülür.

Cihazı veya iş profilini silme

BT yöneticisi, LOCAL_DEVICE_WIPE_COMMAND_ALLOWED ek özelliğiyle COMPANION_APP rolünü atadığında tamamlayıcı uygulama yerel bir Wipe komutu verebilir. Şirkete ait cihazlarda bu işlem, cihazı fabrika ayarlarına sıfırlar. İş profili olan kişisel cihazlarda ise iş profilini kaldırır. Uygulama bu role ve ek özelliğe sahip değilse istek başarısız olur. Ayrıntılı bilgi için Politika Yapılandırması başlıklı makaleyi inceleyin.

Her iki Wipe parametresi de isteğe bağlıdır. Bir değer belirtmek istemiyorsanız oluşturucu ayarlayıcıyı atlayın veya boş bir koleksiyon ya da boş bir dize iletin (null değerini iletmeyin).

  • WipeDataFlag değerleri, hangi verilerin silineceğini kontrol eder:
    • PRESERVE_RESET_PROTECTION_DATA: Varsayılan olarak silinen fabrika ayarlarına sıfırlama koruması verilerini saklar. Yalnızca şirkete ait cihazlar için geçerlidir.
    • WIPE_EXTERNAL_STORAGE: SD kartlar gibi harici depolama alanlarını da siler. Yalnızca şirkete ait cihazlar için geçerlidir.
    • WIPE_ESIMS: Şirkete ait cihazlardan tüm eSIM'leri kaldırır. Kişisel cihazlarda yalnızca yönetilen eSIM'leri kaldırır (Android 16 veya sonraki sürümlerde, bu işaretin ayarlanıp ayarlanmadığına bakılmaksızın yönetilen eSIM'ler her zaman iş profiliyle birlikte kaldırılır).
  • wipeReason: İş profili kişisel bir cihazdan kaldırıldığında kullanıcıya gösterilen, en fazla 200 karakterlik kısa bir mesaj. Şirkete ait cihazları etkilemez.

Aşağıdaki snippet'te, cihazı veya iş profilini silme isteğinin nasıl gönderileceği gösterilmektedir:

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

Komutu Al

Uzantı uygulaması, daha önce gönderilen komut isteklerinin durumunu sorgulayabilir. Bir komutun durumunu almak için komut kimliğine ihtiyacınız vardır (komut verme isteğinden edinilebilir). Aşağıdaki snippet'te, ADP'ye nasıl GetCommandRequest gönderileceği gösterilmektedir.

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

Komut durumu değişikliği geri çağırmalarını dinleme

Uzantı uygulaması, aşağıdaki adımları uygulayarak uzun süre çalışan komutların durum değişiklikleriyle ilgili güncellemeleri almak için isteğe bağlı olarak bir geri çağırma kaydedebilir:

  1. Komut durumu değişiklikleri CommandListener'ye bildirilir. Bu arayüzü uygulamanızda uygulayın ve alınan durum güncellemelerinin nasıl işleneceğine dair uygulama sağlayın.
  2. NotificationReceiverService sınıfını genişletin ve getCommandListener yöntemiyle bir CommandListener örneği sağlayın.
  3. Uygulamanıza COMPANION_APP rolünü atamak için uygulama politikasını yapılandırın (Politika Yapılandırması bölümüne bakın).

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

Politika Yapılandırması

Tamamlayıcı uygulamanın ADP ile doğrudan iletişim kurmasını sağlamak için EMM'nin, uygulama politikasındaki roles alanını kullanarak uygulamaya COMPANION_APP rolünü ataması gerekir:

 "applications": [{
   "packageName": "com.amapi.extensibility.demo",
   "installType": "FORCE_INSTALLED",
   "roles": [
     { "roleType": "COMPANION_APP" }
   ]
 }]

Tamamlayıcı uygulamanın yerel bir Wipe komutu vermesine izin vermek için extraCapabilities.localDeviceWipeCommand değerini LOCAL_DEVICE_WIPE_COMMAND_ALLOWED olarak ayarlayın:

 "applications": [{
   "packageName": "com.amapi.extensibility.demo",
   "installType": "FORCE_INSTALLED",
   "roles": [
     {
       "roleType": "COMPANION_APP",
       "extraCapabilities": {
         "localDeviceWipeCommand": "LOCAL_DEVICE_WIPE_COMMAND_ALLOWED"
       }
     }
   ]
 }]

Kullanabileceğiniz diğer seçenekler için Uygulama rolü politikalarıyla cihazın temel hazırlığını yapma başlıklı makaleyi inceleyin.

Komut durumu değişikliklerini dinleyen hizmet, ADP tarafından uygulamanın manifest dosyasındaki meta veriler kullanılarak otomatik olarak bulunur ve artık politikada notificationReceiver olarak belirtilmesi gerekmez. Uygulamanızı ve manifestinizi nasıl hazırlayacağınızla ilgili ayrıntılar için Uygulama rollerini yönetme başlıklı makaleyi inceleyin.

Test

Birim testi

LocalCommandClient bir arayüzdür ve bu nedenle test edilebilir bir uygulama sunulmasına olanak tanır.

Entegrasyon testi

ADP ile test yapmak için aşağıdaki bilgilere ihtiyacınız olacaktır:

  1. Uzantı uygulamasının paket adı.
  2. Uygulama paketiyle ilişkili imzanın Base64 kodlu SHA-256 karması.
  3. İsteğe bağlı olarak, geri çağırma test ediliyorsa geri çağırmayı desteklemek için yeni eklenen hizmetten hizmetin tam adı. (Örnekte CommandService'nin tam adı).