AMAPI SDK와 통합

AMAPI SDK를 사용하면 EMM 지정 확장 프로그램 앱이 Android Device Policy와 직접 통신할 수 있습니다. 현재는 Commands의 로컬 실행을 지원하고 ClearAppData 명령어만 지원합니다. SDK와 통합하려면 다음 단계를 수행해야 합니다.

  1. 확장 프로그램 앱에 라이브러리 추가
  2. 제공된 API를 사용하여 필요에 따라 명령어를 실행합니다.
  3. 타겟 SDK가 30 이상인 경우 쿼리 요소를 추가합니다.
  4. 원하는 경우 명령어 상태 변경 콜백을 수신 대기하는 서비스 구현을 제공할 수 있습니다.
  5. 확장성 정책으로 기기를 프로비저닝합니다.

기본 요건

  • 확장 프로그램 앱의 minSdkVersion이 API 수준 21 이상으로 설정되어 있는지 확인합니다.

확장 프로그램 애플리케이션에 라이브러리 추가

최상위 build.gradle 파일에서 SDK 라이브러리가 포함된 Google Maven 저장소를 관련 모듈에 추가하고 종속 항목을 라이브러리에 추가합니다.

repositories {
  ...
  google()
}

그런 다음 라이브러리를 모듈의 종속 항목 블록에 추가합니다.

dependencies {
  implementation 'com.google.android.libraries.enterprise.amapi:amapi:1.0.0'
}

Android Device Policy에 요청 보내기

이제 ADP에 요청을 보낼 수 있습니다. 지원되는 요청은 다음과 같습니다.

명령어 실행

확장 프로그램 앱은 ADP를 사용하여 실행할 명령어를 요청할 수 있습니다. IssueCommandRequest에는 실행할 명령어의 세부정보와 특정 매개변수가 포함된 요청 객체가 포함됩니다. 자세한 내용은 Javadoc을 참조하세요.

다음 스니펫은 패키지의 데이터 삭제를 요청하는 방법을 보여줍니다.

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

위의 예는 지정된 패키지에 관해 명확한 앱 데이터 요청을 실행하고 명령어가 성공적으로 실행될 때까지 기다리는 방법을 보여줍니다. 성공적으로 실행되면 현재 명령어 상태와 나중에 장기 실행 명령어의 상태를 쿼리하는 데 사용할 수 있는 명령어 ID와 함께 명령어 객체가 반환됩니다.

명령어 가져오기

확장 프로그램 앱은 이전에 실행된 명령어 요청의 상태를 쿼리할 수도 있습니다. 명령어의 상태를 검색하려면 명령어 ID가 필요합니다(실행 명령어 요청에서 사용 가능). 다음 스니펫은 ADP에 GetCommand 요청을 전송하는 방법을 보여줍니다.

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

쿼리 요소 추가 중

앱이 SDK 30 이상을 타겟팅하는 경우 매니페스트에 쿼리 요소가 있어야 이 요소가 ADP와 상호작용하도록 지정할 수 있습니다.

<queries>
    <package android:name="com.google.android.apps.work.clouddpc" />
</queries>

자세한 내용은 Android에서 패키지 공개 상태 필터링 을 참고하세요.

명령어 상태 변경 콜백 수신 대기

  1. 명령어 상태 변경은 CommandListener에 알림을 전송합니다. 앱에서 이 인터페이스를 구현하고 수신된 상태 업데이트를 처리하는 방법에 관한 구현을 제공합니다.
  2. NotificationReceiverService를 확장하고 CommandListener 인스턴스를 제공합니다.
  3. Android Management API 정책에서 확장된 NotificationReceiverService의 클래스 이름을 지정합니다 (정책 구성 참고).

    import com.google.android.managementapi.commands.CommandListener;
    import com.google.android.managementapi.notification.NotificationReceiverService;
    
    ...
    
    public class SampleCommandService extends NotificationReceiverService {
    
      @Override
      protected void setupInjection() {
        // (Optional) If using DI and needs initialisation then use this method.
      }
    
      @Override
      public CommandListener getCommandListener() {
        // return the concrete implementation from previous step
        return ...;
      }
    }
    
  4. AndroidManifest.xml에 서비스를 추가하고 내보내기되었는지 확인합니다.

    <service
     android:name = ".notification.SampleCommandService"
     android:exported = "true" />
    

정책 구성

 "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는 인터페이스이므로 테스트를 통해 테스트 가능한 구현을 쉽게 제공할 수 있습니다.

통합 테스트

Android Device Policy로 테스트하려면 다음 정보가 필요합니다.

  1. 확장 프로그램의 패키지 이름입니다.
  2. 앱 패키지와 연결된 서명의 16진수로 인코딩된 SHA-256 해시입니다.
  3. (선택사항) 콜백 테스트의 경우 새로 도입된 서비스의 서비스 정규화된 이름으로 콜백을 지원합니다. (예시에서는 CommandService의 정규화된 이름)