eUICC API

在 Android 9 中,配置文件管理 API(公共和 @SystemApi)可通過類EuiccManager 。 eUICC 通信 API(僅限 @SystemApi)可通過類EuiccCardManager

關於eUICC

運營商可以使用 EuiccManager 製作運營商應用來管理配置文件,如圖 1 所示。運營商應用不需要是系統應用,但需要具有 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 通過EuiccManager公開(在android.telephony.euicc包下)。運營商應用可以獲取EuiccManager的實例,並調用EuiccManager中的方法獲取 eUICC 信息,並將訂閱(在 GSMA RSP 文檔中稱為配置文件)作為 SubscriptionInfo 實例進行管理。

調用公共API,包括下載、切換和刪除​​訂閱操作,運營商應用程序必須具有所需的權限。運營商權限由移動運營商在配置文件元數據中添加。 eUICC API 相應地執行運營商特權規則。

Android 平台不處理配置文件策略規則。如果在配置文件元數據中聲明了策略規則,LPA 可以選擇如何處理配置文件下載和安裝過程。例如,第三方 OEM LPA 可以使用特殊的錯誤代碼來處理策略規則(錯誤代碼從 OEM LPA 傳遞到平台,然後平台將代碼傳遞給 OEM LUI)。

蜜蜂

可以在EuiccManager參考文檔EuiccManager.java中找到以下 API。

獲取實例(公共)

通過Context#getSystemService獲取EuiccManager的實例。

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

檢查啟用(公共)

檢查是否啟用了嵌入式訂閱。這應該在訪問 LPA API 之前進行檢查。

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

獲取 EID(公開)

獲取標識 eUICC 硬件的 EID。如果 eUICC 沒有準備好,這可能為空。呼叫者必須具有運營商特權或READ_PRIVILEGED_PHONE_STATE權限。

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

獲取 EuiccInfo(公共)

獲取有關 eUICC 的信息。這包含操作系統版本。

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

下載訂閱(公開)

下載給定的訂閱(在 GSMA RSP 文檔中稱為“配置文件”)。可以從激活碼創建訂閱。例如,可以從二維碼中解析激活碼。下載訂閱是一個異步操作。

調用者必須具有WRITE_EMBEDDED_SUBSCRIPTIONS權限或具有目標訂閱的運營商權限。

// 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或對當前啟用的訂閱和目標訂閱具有運營商權限。

// 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);

刪除訂閱(公開)

刪除具有訂閱 ID 的訂閱。如果訂閱當前處於活動狀態,則首先將其禁用。調用者必須具有目標訂閱的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 */);

// 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);

常數

要查看EuiccManager中的public常量列表,請參閱常量