eUICC API

Android 9에서는 EuiccManager 클래스를 통해 프로필 관리 API(공개 및 @SystemApi)를 사용할 수 있습니다. eUICC 통신 API(@SystemApi만 해당함)는 EuiccCardManager 클래스를 통해 사용할 수 있습니다.

eUICC 정보

이동통신사는 그림 1과 같이 EuiccManager를 사용하여 프로필을 관리하는 이동통신사 앱을 만들 수 있습니다. 이동통신사 앱이 시스템 앱일 필요는 없지만, 이동통신사 앱에 eUICC 프로필에서 부여한 이동통신사 권한이 있어야 합니다. LPA 앱(LUI 및 LPA 백엔드)은 @SystemApi를 호출하는 시스템 앱(즉, 시스템 이미지에 포함되어야 함)이어야 합니다.

이동통신사 앱 및 OEM LPA를 사용하는 Android 휴대전화

그림 1. 이동통신사 앱 및 OEM LPA를 사용하는 Android 휴대전화

EuiccCardManager를 호출하고 eUICC와 통신하는 논리 외에 LPA 앱은 다음을 구현해야 합니다.

  • SM-DP+ 서버와 통신하여 프로필을 인증하고 다운로드하는 SM-DP+ 클라이언트
  • [선택사항] 다운로드할 가능성이 더 높은 프로필을 가져오는 SM-DS.
  • 서버에 알림을 보내 프로필 상태를 업데이트하는 알림 처리 기능.
  • [선택사항] eSIM 및 pSIM 로직 간 전환을 포함한 슬롯 관리 기능. 이는 스마트폰에 eSIM 칩만 있다면 선택사항임.
  • eSIM OTA

하나의 Android 휴대전화에 둘 이상의 LPA 앱이 있을 수 있지만 각 앱의 AndroidManifest.xml 파일에 정의된 우선순위에 따라 하나의 LPA만 실제 작동하는 LPA로 선택할 수 있습니다.

EuiccManager 사용

LPA API는 android.telephony.euicc 패키지 아래에 있는 EuiccManager를 통해 공개됩니다. 이동통신사 앱은 EuiccManager의 인스턴스를 가져올 수 있고 EuiccManager의 메서드를 호출하여 eUICC 정보를 가져오고 SubscriptionInfo 인스턴스로 구독(GSMA RSP 문서에서는 프로필이라고 함)을 관리합니다.

구독을 다운로드, 전환 및 삭제하는 작업을 포함한 공개 API를 호출하려면 이동통신사 앱에 필요한 권한이 있어야 합니다. 이동통신사 권한은 이동통신사에서 프로필 메타데이터에 추가합니다. 이에 따라 eUICC API는 이동통신사 권한 규칙을 적용합니다.

Android 플랫폼은 프로필 정책 규칙을 처리하지 않습니다. 정책 규칙을 프로필 메타데이터에 선언했다면 LPA는 프로필 다운로드 및 설치 절차의 처리 방법을 선택할 수 있습니다. 예를 들어, 서드 파티 OEM LPA가 특별 오류 코드를 사용하여 정책 규칙을 처리할 수 있습니다(OEM LPA에서 플랫폼으로 오류 코드를 전달하면 플랫폼은 OEM LUI로 코드를 전달함).

다중 지원 프로필 API에 대한 자세한 내용은 다중 지원 프로필을 참고하세요.

API

다음 API는 EuiccManager 참조 문서EuiccManager.java에서 찾을 수 있습니다.

인스턴스 가져오기(공개)

Context#getSystemService를 통해 EuiccManager의 인스턴스를 가져옵니다. 자세한 내용은 getSystemService를 참고하세요.

EuiccManager mgr = (EuiccManager) context.getSystemService(Context.EUICC_SERVICE);

사용 설정 확인(공개)

삽입된 구독이 사용 설정되어 있는지 확인합니다. LPA API에 액세스하기 전에 이를 확인해야 합니다. 자세한 내용은 isEnabled을 참고하세요.

boolean isEnabled = mgr.isEnabled();
if (!isEnabled) {
    return;
}

EID 가져오기(공개)

eUICC 하드웨어를 식별하는 EID를 가져옵니다. 이는 eUICC가 준비되지 않았다면 null이 될 수 있습니다. 호출자에는 이동통신사 권한 또는 READ_PRIVILEGED_PHONE_STATE 권한이 있어야 합니다. 자세한 내용은 getEid를 참고하세요.

String eid = mgr.getEid();
if (eid == null) {
  // Handle null case.
}

EuiccInfo 가져오기(공개)

eUICC 정보를 가져옵니다. 여기에는 OS 버전이 포함됩니다. 자세한 내용은 getEuiccInfo를 참고하세요.

EuiccInfo info = mgr.getEuiccInfo();
String osVer = info.getOsVersion();

구독 다운로드(공개)

지정된 구독을 다운로드합니다(GSMA RSP 문서에서는 '프로필'이라고 함). 구독은 활성화 코드에서 만들 수 있습니다. 예를 들어, 활성화 코드는 QR 코드에서 파싱할 수 있습니다. 구독 다운로드는 비동기 작업입니다.

호출자에는 WRITE_EMBEDDED_SUBSCRIPTIONS 권한 또는 타겟 구독을 위한 이동통신사 권한이 있어야 합니다. 자세한 내용은 downloadSubscription를 참고하세요.

// Register receiver.
String action = "download_subscription";
BroadcastReceiver receiver =
        new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                if (!action.equals(intent.getAction())) {
                    return;
                }
                resultCode = getResultCode();
                detailedCode = intent.getIntExtra(
                    EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE,
                    0 /* defaultValue*/);
                resultIntent = intent;
            }
        };
context.registerReceiver(
        receiver,
        new IntentFilter(action),
        "example.broadcast.permission" /* broadcastPermission*/, null /* handler */);

// Download subscription asynchronously.
DownloadableSubscription sub =
        DownloadableSubscription.forActivationCode(code /* encodedActivationCode*/);
Intent intent = new Intent(action);
PendingIntent callbackIntent = PendingIntent.getBroadcast(
        getContext(), 0 /* requestCode */, intent, PendingIntent.FLAG_UPDATE_CURRENT);
mgr.downloadSubscription(sub, true /* switchAfterDownload */, callbackIntent);

구독 전환(공개)

지정된 구독으로 전환(사용 설정)합니다. 호출자에는 WRITE_EMBEDDED_SUBSCRIPTIONS 또는 현재 사용 설정된 구독 및 타겟 구독을 위한 이동통신사 권한이 있어야 합니다. 자세한 내용은 switchToSubscription를 참고하세요.

// Register receiver.
String action = "switch_to_subscription";
BroadcastReceiver receiver =
        new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                if (!action.equals(intent.getAction())) {
                    return;
                }
                resultCode = getResultCode();
                detailedCode = intent.getIntExtra(
                    EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE, 0 /* defaultValue*/);
                resultIntent = intent;
            }
        };
context.registerReceiver(receiver, new IntentFilter(action),
        "example.broadcast.permission" /* broadcastPermission*/, null /* handler */);

// Switch to a subscription asynchronously.
Intent intent = new Intent(action);
PendingIntent callbackIntent = PendingIntent.getBroadcast(
        getContext(), 0 /* requestCode */, intent, PendingIntent.FLAG_UPDATE_CURRENT);
mgr.switchToSubscription(1 /* subscriptionId */, callbackIntent);

포트로 구독 전환(공개)

(Android 13에서 사용 가능) 지정된 포트 색인이 있는 특정 구독으로 전환(사용 설정)합니다. 호출자에는 WRITE_EMBEDDED_SUBSCRIPTIONS 또는 현재 사용 설정된 구독 및 타겟 구독을 위한 이동통신사 권한이 있어야 합니다. 자세한 내용은 switchToSubscription를 참고하세요.

// Register receiver.
String action = "switch_to_subscription";
BroadcastReceiver receiver =
        new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                if (!action.equals(intent.getAction())) {
                    return;
                }
                resultCode = getResultCode();
                detailedCode = intent.getIntExtra(
                    EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE, 0 /* defaultValue*/);
                resultIntent = intent;
            }
        };
context.registerReceiver(receiver, new IntentFilter(action),
        "example.broadcast.permission" /* broadcastPermission*/, null /* handler */);

// Switch to a subscription asynchronously.
Intent intent = new Intent(action);
PendingIntent callbackIntent = PendingIntent.getBroadcast(
        getContext(), 0 /* requestCode */, intent, PendingIntent.FLAG_UPDATE_CURRENT);
mgr.switchToSubscription(1 /* subscriptionId */, 0 /*portIndex*/, callbackIntent);

SIM 포트 사용 가능 여부(공개)

public boolean isSimPortAvailable(int portIndex)

(Android 13에서 사용 가능) 전달하는 포트 인덱스의 사용 가능 여부를 반환합니다. 포트는 구독이 사용 설정되지 않았거나 호출하는 앱이 선택한 포트에 설치된 구독에 대해 이동통신사 권한을 보유하고 있는 경우 사용할 수 있습니다. 자세한 내용은 isSimPortAvailable을 참고하세요.

구독 삭제(공개)

구독 ID로 구독을 삭제합니다. 구독이 현재 활성화되어 있다면 먼저 구독이 중지됩니다. 호출자에는 WRITE_EMBEDDED_SUBSCRIPTIONS 또는 타겟 구독을 위한 이동통신사 권한이 있어야 합니다. 자세한 내용은 deleteSubscription를 참고하세요.

// Register receiver.
String action = "delete_subscription";
BroadcastReceiver receiver =
        new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                if (!action.equals(intent.getAction())) {
                    return;
                }
                resultCode = getResultCode();
                detailedCode = intent.getIntExtra(
                    EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE,
                    0 /* defaultValue*/);
                resultIntent = intent;
            }
        };
context.registerReceiver(receiver, new IntentFilter(action),
        "example.broadcast.permission" /* broadcastPermission*/,
        null /* handler */);

// Delete a subscription asynchronously.
Intent intent = new Intent(action);
PendingIntent callbackIntent = PendingIntent.getBroadcast(
        getContext(), 0 /* requestCode */, intent, PendingIntent.FLAG_UPDATE_CURRENT);
mgr.deleteSubscription(1 /* subscriptionId */, callbackIntent);

모든 구독 삭제(시스템 API)

기기의 모든 구독을 삭제합니다. Android 11부터는 EuiccCardManager#ResetOption enum 값을 제공하여 모든 테스트, 운영 또는 두 가지 유형의 구독을 모두 삭제할지 지정합니다. 호출자에는 WRITE_EMBEDDED_SUBSCRIPTIONS 권한이 있어야 합니다.

// Register receiver.
String action = "delete_subscription";
BroadcastReceiver receiver =
        new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                if (!action.equals(intent.getAction())) {
                    return;
                }
                resultCode = getResultCode();
                detailedCode = intent.getIntExtra(
                    EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE,
                    0 /* defaultValue*/);
                resultIntent = intent;
            }
        };
context.registerReceiver(receiver, new IntentFilter(action),
        "example.broadcast.permission" /* broadcastPermission*/,
        null /* handler */);

// Erase all operational subscriptions asynchronously.
Intent intent = new Intent(action);
PendingIntent callbackIntent = PendingIntent.getBroadcast(
        getContext(), 0 /* requestCode */, intent, PendingIntent.FLAG_UPDATE_CURRENT);
mgr.eraseSubscriptions(
        EuiccCardManager.RESET_OPTION_DELETE_OPERATIONAL_PROFILES, callbackIntent);

해결 활동 시작(공개)

사용자가 해결할 수 있는 오류를 해결하기 위한 활동을 시작합니다. 작업이 EuiccManager#EMBEDDED_SUBSCRIPTION_RESULT_RESOLVABLE_ERROR를 반환하면 사용자에게 문제 해결을 요구하기 위해 이 메서드를 호출할 수 있습니다. 이 메서드는 특정 오류당 한 번만 호출할 수 있습니다.

...
mgr.startResolutionActivity(getActivity(), 0 /* requestCode */, resultIntent, callbackIntent);

상수

EuiccManagerpublic 상수 목록을 보려면 상수를 참조하세요.