eUICC API

В Android 9 API управления профилями (публичные и @SystemApi) доступны через класс EuiccManager . API связи с eUICC (только @SystemApi) доступны через класс EuiccCardManager .

О eUICC

Операторы связи могут создавать приложения, используя EuiccManager для управления профилями, как показано на рисунке 1. Приложения операторов связи не обязательно должны быть системными приложениями, но должны иметь права доступа, предоставленные профилями eUICC. Приложение LPA (LUI и бэкэнд LPA) должно быть системным приложением (т.е. включенным в образ системы), чтобы вызывать @SystemApi.

Телефон Android с приложением оператора и OEM LPA

Рисунок 1. Телефоны Android с приложением оператора связи и OEM LPA.

Помимо логики вызова EuiccCardManager и взаимодействия с eUICC, приложения LPA должны реализовывать следующее:

  • Клиент SM-DP+ взаимодействует с сервером SM-DP+ для аутентификации и загрузки профилей.
  • [Необязательно] SM-DS для получения большего количества потенциальных профилей для скачивания.
  • Обработка уведомлений для отправки на сервер уведомлений об обновлении состояния профиля.
  • [Необязательно] Управление слотами, включая переключение между режимами eSIM и pSIM. Эта опция необязательна, если телефон оснащен только чипом eSIM.
  • eSIM OTA

Хотя на телефоне Android может быть установлено более одного приложения LPA, в зависимости от приоритета, определенного в файле AndroidManifest.xml каждого приложения, в качестве фактически работающего приложения может быть выбрано только одно.

Используйте EuiccManager

API LPA доступны через EuiccManager (в пакете android.telephony.euicc ). Приложение оператора связи может получить экземпляр EuiccManager и вызвать методы EuiccManager для получения информации об eUICC и управления подписками (в документах GSMA RSP они называются профилями) в виде экземпляров SubscriptionInfo.

Для вызова общедоступных API, включая операции загрузки, переключения и удаления подписки, приложение оператора связи должно обладать необходимыми привилегиями. Привилегии оператора добавляются мобильным оператором в метаданные профиля. API eUICC соответствующим образом применяет правила привилегий оператора.

Платформа Android не обрабатывает правила политики профиля. Если правило политики объявлено в метаданных профиля, LPA может выбрать способ обработки процедуры загрузки и установки профиля. Например, сторонний OEM LPA может обрабатывать правила политики с помощью специального кода ошибки (код ошибки передается от OEM LPA к платформе, а затем платформа передает код в OEM LUI).

Для получения информации об API для работы с несколькими включенными профилями см. раздел «Несколько включенных профилей» .

API

Следующие API можно найти в справочной документации EuiccManager и в EuiccManager.java .

Получить экземпляр (публичный)

Получает экземпляр EuiccManager через Context#getSystemService . Подробности см. в getSystemService .

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

Отметка включена (общедоступно)

Проверяет, включена ли встроенная подписка. Это следует проверить перед доступом к API LPA. Подробнее см. isEnabled .

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

Получить EID (публичный)

Получает EID, идентифицирующий оборудование eUICC. Он может быть равен null, если eUICC еще не готов. Вызывающий абонент должен иметь права оператора связи или разрешение READ_PRIVILEGED_PHONE_STATE . Подробнее см. getEid .

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

Получить EuiccInfo (общедоступный ресурс)

Получает информацию об eUICC. Она включает версию операционной системы. Подробнее см. 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 .

Удалить подписку (публичную)

Удаляет подписку с идентификатором подписки. Если подписка в данный момент активна, она сначала отключается. Вызывающая сторона должна иметь либо 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 , чтобы определить, следует ли удалить все тестовые, операционные или оба типа подписок. Вызывающая сторона должна иметь разрешение 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);

Константы

Чтобы увидеть список public констант в EuiccManager , см. раздел «Константы» .