實作 eSIM 卡

行動裝置使用者可透過嵌入式 SIM 卡 (eSIM 卡或 eUICC) 技術 下載電信業者設定檔並啟用電信業者的服務,而沒有 實體 SIM 卡。這是由 GSMA 推動的全球規格 遠端 SIM 卡佈建 (RSP)。從 Android 開始 9,Android 架構提供了標準 API, 存取 eSIM 卡及管理 eSIM 卡的訂閱設定檔。這些 eUICC API 可讓第三方自行開發電信業者應用程式和本機設定檔 在支援 eSIM 卡的 Android 裝置上,使用 Google 助理 (LPA)。

LPA 是獨立的系統應用程式, Android 建構映像檔。如要管理 eSIM 卡的設定檔,通常是由 LPA 的作用是 SM-DP+ 準備、儲存及將設定檔套件傳送至裝置) 和 eUICC 晶片。 LPA APK 可選擇納入名為 LPA UI 或 LUI 的 UI 元件, 使用者可以集中一處管理所有內嵌的訂閱項目 Android 架構會自動探索並連線至 可用的 LPA,並透過 LPA 執行個體轉送所有 eUICC 作業。

簡化的遠端 SIM 卡佈建 (RSP) 架構

圖 1. 簡化的 RSP 架構

想要建立電信業者應用程式的行動網路業者: 以及 Google Cloud 控制台 EuiccManager、 這項服務提供各種進階設定檔管理作業 downloadSubscription()switchToSubscription()deleteSubscription()

如果您是裝置的原始設備製造商 (OEM),並想建立自己的 LPA 系統應用程式,請務必 延伸 EuiccService敬上 ,確保 Android 架構連線至 LPA 服務此外,您 使用 API EuiccCardManager、 ,其提供以 GSMA RSP v2.0 為基礎的 ES10x 函式。 這類函式的用途是向 eUICC 晶片發出指令,例如 prepareDownload()loadBoundProfilePackage()retrieveNotificationList()、 和 resetMemory()

API 中的 API EuiccManager敬上 您需要正確實作 LPA 應用程式才能正常運作,以及呼叫 EuiccCardManager API 必須是 LPA。這由 Android 架構強制執行。

搭載 Android 10 以上版本的裝置可支援 搭載多張 eSIM 卡的裝置。若需更多資訊,請參閲 支援多張 eSIM 卡

建立電信業者應用程式

Android 9 中的 eUICC API 可讓 行動網路業者建立電信業者品牌應用程式,以便管理 管理商家檔案包括下載及刪除訂閱項目個人資料 以及切換至其他電信業者擁有的設定檔。

EuiccManager

EuiccManager 是應用程式與 LPA。這包括下載、刪除及切換至 以及電信業者擁有的訂閱項目這也包括 LUI 系統應用程式 提供集中位置/使用者介面來管理「所有」嵌入式訂閱項目。 可以是獨立應用程式,與提供 EuiccService 的應用程式不同。

如要使用公用 API,電信業者應用程式必須先取得 EuiccManagerContext#getSystemService

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

執行任何操作前,請先檢查裝置是否支援 eSIM 卡 eSIM 卡作業。如果EuiccManager#isEnabled()true 已定義 android.hardware.telephony.euicc 功能,且 LPA 套件已 。

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

如何取得 eUICC 硬體和 eSIM 卡 OS 版本的相關資訊:

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

許多 API (例如 downloadSubscription()switchToSubscription()) 會使用 PendingIntent 回呼,因為這些程序可能需要幾秒鐘或幾分鐘才能完成。 傳送 PendingIntent 時,會包含以下結果代碼: EuiccManager#EMBEDDED_SUBSCRIPTION_RESULT_ 空間,提供 架構定義的錯誤代碼,以及任意的詳細結果代碼 已從 LPA 中傳播為 EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE, 以便進行記錄/偵錯。PendingIntent 回呼必須為 BroadcastReceiver

要下載指定的可下載訂閱項目 (從 啟用碼或 QR 圖碼):

// Register receiver.
static final String ACTION_DOWNLOAD_SUBSCRIPTION = "download_subscription";
static final String LPA_DECLARED_PERMISSION
    = "com.your.company.lpa.permission.BROADCAST";
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*/);

                // If the result code is a resolvable error, call startResolutionActivity
                if (resultCode == EuiccManager.EMBEDDED_SUBSCRIPTION_RESULT_RESOLVABLE_ERROR) {
                    PendingIntent callbackIntent = PendingIntent.getBroadcast(
                        getContext(), 0 /* requestCode */, intent,
                        PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE);
                    mgr.startResolutionActivity(
                        activity,
                        0 /* requestCode */,
                        intent,
                        callbackIntent);
                }

                resultIntent = intent;
            }
        };
context.registerReceiver(receiver,
        new IntentFilter(ACTION_DOWNLOAD_SUBSCRIPTION),
        LPA_DECLARED_PERMISSION /* broadcastPermission*/,
        null /* handler */);

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

AndroidManifest.xml 中定義及使用權限:

    <permission android:protectionLevel="signature" android:name="com.your.company.lpa.permission.BROADCAST" />
    <uses-permission android:name="com.your.company.lpa.permission.BROADCAST"/>

如要改用具有該訂閱項目 ID 的訂閱項目,請按照下列步驟操作:

// Register receiver.
static final String ACTION_SWITCH_TO_SUBSCRIPTION = "switch_to_subscription";
static final String LPA_DECLARED_PERMISSION
    = "com.your.company.lpa.permission.BROADCAST";
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_SWITCH_TO_SUBSCRIPTION),
        LPA_DECLARED_PERMISSION /* broadcastPermission*/,
        null /* handler */);

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

如需 EuiccManager API 和程式碼範例的完整清單,請參閱 eUICC API

可解決的錯誤

在某些情況下,系統無法完成 eSIM 卡作業 但使用者可以解決錯誤例如:downloadSubscription 如果設定檔中繼資料顯示貨運公司確認碼,可能會失敗 必填。或者,如果「switchToSubscription」使用電信業者應用程式,則可能無法使用 可明確授予目的地設定檔的權限 (也就是由電信業者擁有),但 無法透過目前啟用的設定檔擁有電信業者權限,因此 必須提供使用者同意。

在這種情況下,系統會使用 EuiccManager#EMBEDDED_SUBSCRIPTION_RESULT_RESOLVABLE_ERROR。回呼 Intent 包含內部額外項目,在呼叫端將其傳遞至 EuiccManager#startResolutionActivity, 可以透過 LUI 要求解析度。使用以下應用程式的確認碼: 這個例子再次說明 EuiccManager#startResolutionActivity敬上 會觸發 LUI 畫面,讓使用者輸入確認碼。 之後就會繼續下載作業。這個方法 可讓電信業者應用程式完全控制 UI 顯示時機,但 LPA/LUI 的延伸方法,可添加新的使用者復原處理方法 而不必變更用戶端應用程式。

Android 9 會在 EuiccService、 LUI 應處理:

/**
 * Alert the user that this action will result in an active SIM being
 * deactivated. To implement the LUI triggered by the system, you need to define
 * this in AndroidManifest.xml.
 */
public static final String ACTION_RESOLVE_DEACTIVATE_SIM =
        "android.service.euicc.action.RESOLVE_DEACTIVATE_SIM";
/**
 * Alert the user about a download/switch being done for an app that doesn't
 * currently have carrier privileges.
 */
public static final String ACTION_RESOLVE_NO_PRIVILEGES =
        "android.service.euicc.action.RESOLVE_NO_PRIVILEGES";

/** Ask the user to resolve all the resolvable errors. */
public static final String ACTION_RESOLVE_RESOLVABLE_ERRORS =
        "android.service.euicc.action.RESOLVE_RESOLVABLE_ERRORS";

電信業者權限

如果你是電信業者自行開發電信業者應用程式,且應用程式會呼叫 EuiccManager 如要將設定檔下載到裝置,你的設定檔應包含電信業者 中繼資料內相應的電信業者應用程式權限規則。這是 因為屬於不同電信業者的訂閱資料 裝置的 eUICC,且每個電信業者應用程式只能存取 與該電信業者擁有的個人資料舉例來說,A 電信業者可能無法 下載、啟用或停用 B 電信業者擁有的設定檔。

為確保只有擁有者可以存取個人資料,Android 會透過以下機制 授予商家檔案擁有者應用程式 (即電信業者應用程式) 的特殊權限。 Android 平台載入儲存在設定檔存取規則檔案的憑證 (ARF),並授予由這些憑證簽署的應用程式發出呼叫的權限 至 EuiccManager API。大致流程如下:

  1. 電信業者簽署電信業者應用程式 APK。這個 apksigner 工具會將公開金鑰憑證附加至 APK。
  2. 操作人員/SM-DP+ 準備設定檔與中繼資料,包括 ARF ,其中包含:

    1. 電信業者應用程式公開金鑰憑證的簽名 (SHA-1 或 SHA-256) (必填)
    2. 電信業者應用程式的套件名稱 (強烈建議使用)
  3. 電信業者應用程式嘗試透過 EuiccManager API 執行 eUICC 作業。

  4. Android 平台會驗證呼叫端應用程式的 SHA-1 或 SHA-256 雜湊 憑證的簽章與 目標設定檔的 ARF如果電信業者應用程式的套件名稱 ARF,也必須符合呼叫端應用程式的套件名稱。

  5. 簽名和套件名稱 (如有提供) 之後, 已透過目標設定檔將電信業者權限授予呼叫端應用程式。

除了個人資料本身外,也可以存取個人資料中繼資料 (因此 LPA 可以從 SM-DP+ 擷取設定檔中繼資料,然後 或在停用設定檔的情況下從 ISD-R 下載),其中應包含 與設定檔中的電信業者權限規則相同

eUICC OS 和 SM-DP+ 必須支援設定檔中的專屬標記 BF76 中繼資料。標記內容應與傳回的電信業者權限規則相同 所參照的存取規則小工具 (ARA) UICC 電信業者權限

RefArDo ::= [PRIVATE 2] SEQUENCE {  -- Tag E2
    refDo [PRIVATE 1] SEQUENCE {  -- Tag E1
        deviceAppIdRefDo [PRIVATE 1] OCTET STRING (SIZE(20|32)),  -- Tag C1
        pkgRefDo [PRIVATE 10] OCTET STRING (SIZE(0..127)) OPTIONAL  -- Tag CA
    },
    arDo [PRIVATE 3] SEQUENCE {  -- Tag E3
        permArDo [PRIVATE 27] OCTET STRING (SIZE(8))  -- Tag DB
    }
}

如要進一步瞭解應用程式簽署,請參閱 簽署應用程式。 如要進一步瞭解電信業者權限,請參閱 UICC 電信業者權限

建立本機設定檔小幫手應用程式

裝置製造商可導入自己的本機設定檔助理 (LPA)。 這必須是 Android Euicc API以下各節將概略介紹 製作 LPA 應用程式,並與 Android 系統整合。

硬體/模組需求

eUICC 晶片上的 LPA 和 eSIM 卡 OS 必須支援至少 GSMA RSP (遙控器 SIM 卡佈建) 2.0 或 2.2 版。以及 SM-DP+ 和 SM-DS 下載相同 RSP 版本的伺服器如需詳細的 RSP 架構,請參閱 GSMA SGP.21 RSP 架構規格

此外,為了在 Android 中整合 eUICC API 9,裝置數據機應傳送終端機功能 並支援 eUICC 功能編碼 (本機設定檔管理 設定檔下載)。並且需要實作下列方法:

  • IRadio HAL v1.1:setSimPower
  • IRadio HAL v1.2:getIccCardStatus

  • IRadioConfig HAL v1.0 版:getSimSlotsStatus

  • IRadioConfig AIDL v1.0 版:getAllowedCarriers

    Google LPA 必須瞭解電信業者鎖定狀態,才能僅允許透過允許的電信業者下載 eSIM 卡或轉移 eSIM 卡。否則使用者可能會下載並轉移 SIM 卡,但之後發現裝置綁定其他電信業者的服務。

    • 供應商或原始設備製造商 (OEM) 必須導入 IRadioSim.getAllowedCarriers()HAL API。

    • 供應商 RIL / 數據機應根據 IRadioSimResponse.getAllowedCarriersResponse()HAL API 的一部分,填入裝置鎖定的電信業者鎖定狀態和 CarrierId。

數據機應可辨識已啟用預設啟動設定檔做為 有效的 SIM 卡,並將 SIM 卡電源保持開啟。

搭載 Android 10 的裝置不可移除的 eUICC 必須定義版位 ID 陣列。舉例來說,請參閱 arrays.xml

<resources>
   <!-- Device-specific array of SIM slot indexes which are are embedded eUICCs.
        e.g. If a device has two physical slots with indexes 0, 1, and slot 1 is an
        eUICC, then the value of this array should be:
            <integer-array name="non_removable_euicc_slots">
                <item>1</item>
            </integer-array>
        If a device has three physical slots and slot 1 and 2 are eUICCs, then the value of
        this array should be:
            <integer-array name="non_removable_euicc_slots">
               <item>1</item>
               <item>2</item>
            </integer-array>
        This is used to differentiate between removable eUICCs and built in eUICCs, and should
        be set by OEMs for devices which use eUICCs. -->

   <integer-array name="non_removable_euicc_slots">
       <item>1</item>
   </integer-array>
</resources>

如需數據機需求的完整清單,請參閱 eSIM 卡支援的現代需求條件

EuiccService

單一 LPA 是由兩個不同的元件組成 (或許可以在 APK):LPA 後端,以及 LPA UI 或 LUI。

如要實作 LPA 後端 EuiccService敬上 並在資訊清單檔案中宣告這項服務服務必須要求 android.permission.BIND_EUICC_SERVICE 系統權限,能確保 才能繫結至該物件服務也必須包含 執行 android.service.euicc.EuiccService 動作。意圖的優先順序 如果有多項導入項目,則將其設為非零的值 。例如:

<service
    android:name=".EuiccServiceImpl"
    android:permission="android.permission.BIND_EUICC_SERVICE">
    <intent-filter android:priority="100">
        <action android:name="android.service.euicc.EuiccService" />
    </intent-filter>
</service>

Android 架構會在內部判斷有效的 LPA,並將這類資源與 以便支援 Android eUICC API有人查詢「PackageManager」的時間: 擁有 android.permission.WRITE_EMBEDDED_SUBSCRIPTIONS 權限的所有應用程式。 會指定 android.service.euicc.EuiccService 動作的服務。 系統會選取優先順序最高的服務。如果找不到服務,LPA 支援功能已停用。

如要實作 LUI,您必須為以下動作提供活動:

  • android.service.euicc.action.MANAGE_EMBEDDED_SUBSCRIPTIONS
  • android.service.euicc.action.PROVISION_EMBEDDED_SUBSCRIPTION

就像服務一樣,每項活動都必須具備 android.permission.BIND_EUICC_SERVICE 系統權限。每個都應該要有 意圖篩選器指定適當動作 android.service.euicc.category.EUICC_UI類別,以及非零的優先順序。 類似的邏輯可用來挑選這些活動的實作方式, 包括選出實作 EuiccService。 例如:

<activity android:name=".MyLuiActivity"
          android:exported="true"
          android:permission="android.permission.BIND_EUICC_SERVICE">
    <intent-filter android:priority="100">
        <action android:name="android.service.euicc.action.MANAGE_EMBEDDED_SUBSCRIPTIONS" />
        <action android:name="android.service.euicc.action.PROVISION_EMBEDDED_SUBSCRIPTION" />
        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.service.euicc.category.EUICC_UI" />
    </intent-filter>
</activity>

這表示實作這些畫面的 UI 可能來自不同的內容 APK EuiccService。 使用單一 APK 或多個 APK (例如實作的 APK EuiccService 和提供 LUI 活動的一種設計是設計選項。

EuiccCardManager

EuiccCardManager 是與 eSIM 卡晶片通訊的介面。這項服務 提供 ES10 函式 (如 GSMA RSP 規格中所述),並處理 低階 APDU 要求/回應指令,以及 ASN.1 剖析。 EuiccCardManager 是系統 API,只能由系統特殊權限呼叫 應用程式。

電信業者應用程式、LPA 和 Euicc API

圖 2. 電信業者應用程式和 LPA 都使用 Euicc API

透過 EuiccCardManager 執行設定檔作業 API 時,呼叫端必須是 提供 LPA這由 Android 架構強制執行。這表示呼叫端必須 擴充 EuiccService,並且必須在資訊清單檔案中宣告,如以下所述: 請參閱先前的章節

EuiccManager 類似,如要使用 EuiccCardManager API,您的 LPA 必須 先取得 EuiccCardManager 的例項 Context#getSystemService:

EuiccCardManager cardMgr = (EuiccCardManager) context.getSystemService(Context.EUICC_CARD_SERVICE);

然後,在 eUICC 上取得所有設定檔:

ResultCallback<EuiccProfileInfo[]> callback =
       new ResultCallback<EuiccProfileInfo[]>() {
           @Override
           public void onComplete(int resultCode,
                   EuiccProfileInfo[] result) {
               if (resultCode == EuiccCardManagerReflector.RESULT_OK) {
                   // handle result
               } else {
                   // handle error
               }
           }
       };

cardMgr.requestAllProfiles(eid, AsyncTask.THREAD_POOL_EXECUTOR, callback);

EuiccCardManager 在內部會繫結至 EuiccCardController (於 手機處理程序),以及每個 EuiccCardManager 方法 透過其他專門的 AIDL,從手機程序接收回呼 存取 API使用 EuiccCardManager API 時,呼叫端 (LPA) 必須提供 Executor 物件。這個 Executor 物件可能會在以下位置執行: 或自行選擇執行緒集區。

大多數 EuiccCardManager API 的使用模式都相同。舉例來說,如要載入 將設定檔套件繫結至 eUICC:

...
cardMgr.loadBoundProfilePackage(eid, boundProfilePackage,
        AsyncTask.THREAD_POOL_EXECUTOR, callback);

如要切換至指定 ICCID 的其他設定檔,請按照下列步驟操作:

...
cardMgr.switchToProfile(eid, iccid, true /* refresh */,
        AsyncTask.THREAD_POOL_EXECUTOR, callback);

如要從 eUICC 晶片取得預設的 SM-DP+ 位址,請按照下列步驟操作:

...
cardMgr.requestDefaultSmdpAddress(eid, AsyncTask.THREAD_POOL_EXECUTOR,
        callback);

如要擷取指定通知事件的通知清單:

...
cardMgr.listNotifications(eid,
        EuiccNotification.Event.INSTALL
              | EuiccNotification.Event.DELETE /* events */,
        AsyncTask.THREAD_POOL_EXECUTOR, callback);

透過電信業者應用程式啟用 eSIM 卡設定檔

在搭載 Android 9 以上版本的裝置上,你可以使用電信業者應用程式來啟用 以及下載設定檔電信業者應用程式可透過下列方式下載設定檔: 撥號中 downloadSubscription敬上 或向 LPA 提供啟用代碼

電信業者應用程式透過撥號方式下載設定檔 downloadSubscription、 呼叫會強制執行應用程式可透過 BF76 管理設定檔 metadata 標記 會將電信業者權限規則編碼 如果設定檔沒有 BF76 標記,或是其 BF76 標記沒有 與呼叫端電信業者應用程式的簽名相同,下載作業就會遭到拒絕。

下一節將說明如何使用 啟用代碼。

使用啟用代碼啟用 eSIM 卡

使用啟用代碼啟用 eSIM 卡設定檔時,LPA 會擷取 啟用代碼 下載設定檔這個流程可由 LPA 啟動 LPA 可控管整個 UI 流程,也就是說,系統不會提供任何電信業者應用程式 UI 。這個方法會略過 BF76 標記檢查,網路業者則不會 必須執行整個 eSIM 卡啟用 UI 流程,包括下載 eSIM 卡設定檔和錯誤處理機制。

定義電信業者 eUICC 佈建服務

LPA 和電信業者應用程式會透過 AIDL 介面: ICarrierEuiccProvisioningServiceIGetActivationCodeCallback。貨運公司 應用程式必須實作 ICarrierEuiccProvisioningService 介面。 執行 資訊清單宣告。 LPA 必須繫結至 ICarrierEuiccProvisioningService 並實作 IGetActivationCodeCallback。如要進一步瞭解如何實作 提供了 AIDL 介面,請參閱定義與 AIDL 介面

如要定義 AIDL 介面,請建立下列 AIDL 檔案 LPA 和電信業者應用程式

  • ICarrierEuiccProvisioningService.aidl

    package android.service.euicc;
    
    import android.service.euicc.IGetActivationCodeCallback;
    
    oneway interface ICarrierEuiccProvisioningService {
        // The method to get the activation code from the carrier app. The caller needs to pass in
        // the implementation of IGetActivationCodeCallback as the parameter.
        void getActivationCode(in IGetActivationCodeCallback callback);
    
        // The method to get the activation code from the carrier app. The caller needs to pass in
        // the activation code string as the first parameter and the implementation of
        // IGetActivationCodeCallback as the second parameter. This method provides the carrier
        // app the device EID which allows a carrier to pre-bind a profile to the device's EID before
        // the download process begins.
        void getActivationCodeForEid(in String eid, in IGetActivationCodeCallback callback);
    }
    
    
  • IGetActivationCodeCallback.aidl

    package android.service.euicc;
    
    oneway interface IGetActivationCodeCallback {
        // The call back method needs to be called when the carrier app gets the activation
        // code successfully. The caller needs to pass in the activation code string as the
        // parameter.
        void onSuccess(String activationCode);
    
        // The call back method needs to be called when the carrier app failed to get the
        // activation code.
        void onFailure();
    }
    

LPA 導入範例

如要繫結至電信業者應用程式的 ICarrierEuiccProvisioningService 實作項目, LPA 必須同時複製 ICarrierEuiccProvisioningService.aidl 和 對專案並實作 IGetActivationCodeCallback.aidl ServiceConnection

@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
    mCarrierProvisioningService = ICarrierEuiccProvisioningService.Stub.asInterface(iBinder);
}

繫結至電信業者應用程式的 ICarrierEuiccProvisioningService 後 LPA 會呼叫 getActivationCodegetActivationCodeForEid,以便透過電信業者應用程式取得啟用碼 傳遞 IGetActivationCodeCallback 虛設常式類別的實作。

getActivationCodegetActivationCodeForEid 的差異在於 getActivationCodeForEid 可讓電信業者將設定檔預先繫結至裝置的 下載程序開始前的 EID。

void getActivationCodeFromCarrierApp() {
    IGetActivationCodeCallback.Stub callback =
            new IGetActivationCodeCallback.Stub() {
                @Override
                public void onSuccess(String activationCode) throws RemoteException {
                    // Handle the case LPA success to get activation code from a carrier app.
                }

                @Override
                public void onFailure() throws RemoteException {
                    // Handle the case LPA failed to get activation code from a carrier app.
                }
            };
    
    try {
        mCarrierProvisioningService.getActivationCode(callback);
    } catch (RemoteException e) {
        // Handle Remote Exception
    }
}

電信業者應用程式的導入範例

如要將 LPA 繫結至電信業者應用程式,電信業者應用程式必須複製 ICarrierEuiccProvisioningService.aidlIGetActivationCodeCallback.aidl到 並宣告 ICarrierEuiccProvisioningService 服務中的 AndroidManifest.xml 檔案。服務必須要求 android.permission.WRITE_EMBEDDED_SUBSCRIPTIONS 系統權限,以確保 只有 LPA (具有系統特殊權限的應用程式) 才能繫結至該應用程式。服務必須 也包括具有下列條件的意圖篩選器: android.service.euicc.action.BIND_CARRIER_PROVISIONING_SERVICE

  • AndroidManifest.xml

    <application>
      ...
      <service
          android:name=".CarrierEuiccProvisioningService"
          android:exported="true"
          android:permission="android.permission.WRITE_EMBEDDED_SUBSCRIPTIONS">
        <intent-filter>
          <action android:name="android.service.euicc.action.BIND_CARRIER_PROVISIONING_SERVICE"/>
        </intent-filter>
      </service>
      ...
    </application>
    

如要導入 AIDL 電信業者應用程式服務,請建立服務,並擴充 Stub 並實作 getActivationCodegetActivationCodeForEid 方法。接著,LPA 即可呼叫任一方法以擷取設定檔啟用狀態 再也不是件繁重乏味的工作電信業者應用程式應透過電話回應 使用啟用代碼 IGetActivationCodeCallback#onSuccess (如果代碼為 成功從電信業者伺服器擷取。如果無法成功執行,表示電信業者應用程式 應以 IGetActivationCodeCallback#onFailure 回應。

  • CarrierEuiccProvisioningService.java

    import android.service.euicc.ICarrierEuiccProvisioningService;
    import android.service.euicc.ICarrierEuiccProvisioningService.Stub;
    import android.service.euicc.IGetActivationCodeCallback;
    
    public class CarrierEuiccProvisioningService extends Service {
        private final ICarrierEuiccProvisioningService.Stub binder =
            new Stub() {
              @Override
              public void getActivationCode(IGetActivationCodeCallback callback) throws RemoteException {
                String activationCode = // do whatever work necessary to get an activation code (HTTP requests to carrier server, fetch from storage, etc.)
                callback.onSuccess(activationCode);
              }
    
              @Override
              public void getActivationCodeForEid(String eid, IGetActivationCodeCallback callback) throws RemoteException {
                String activationCode = // do whatever work necessary (HTTP requests, fetch from storage, etc.)
                callback.onSuccess(activationCode);
              }
          }
    }
    

在 LPA 啟用流程中啟動電信業者應用程式 UI

在搭載 Android 11 以上版本的裝置上,LPA 可 並啟動電信業者應用程式的 UI 這項功能很實用,因為電信業者應用程式可能需要 使用者,再向 LPA 提供啟用代碼。例如電信業者 要求使用者登入才能啟用電話號碼或執行其他攜碼轉移程序 免費 Google Cloud 服務

在 LPA 中啟動電信業者應用程式的 UI 的程序如下:

  1. LPA 將 android.service.euicc.action.START_CARRIER_ACTIVATION 意圖 內含動作的電信業者應用程式套件(電信業者應用程式接收器必須 以獲得保護的資訊清單 android:permission="android.permission.WRITE_EMBEDDED_SUBSCRIPTIONS"到 避免接收非 LPA 應用程式的意圖)。

    String packageName = // The carrier app's package name
    
    Intent carrierAppIntent =
        new Intent(“android.service.euicc.action.START_CARRIER_ACTIVATION”)
            .setPackage(packageName);
    
    ResolveInfo activity =
        context.getPackageManager().resolveActivity(carrierAppIntent, 0);
    
    carrierAppIntent
        .setClassName(activity.activityInfo.packageName, activity.activityInfo.name);
    
    startActivityForResult(carrierAppIntent, requestCode);
    
  2. 電信業者應用程式使用自己的 UI 執行作業。例如,Logging 或傳送 HTTP 要求至電信業者的後端

  3. 電信業者應用程式會呼叫 setResult(int, Intent) 回應 LPA 和 finish()

    1. 如果電信業者應用程式回應 RESULT_OK,LPA 繼續進行啟用流程。如果電信業者應用程式判定 請掃描 QR code,不要讓 LPA 繫結電信業者 應用程式服務,電信業者應用程式就會使用 具有 RESULT_OKIntent 執行個體的 setResult(int, Intent) 包含布林值額外項目 android.telephony.euicc.extra.USE_QR_SCANNER已設為 true。LPA 然後檢查該額外項目並啟動 QR 掃描器,而非進行繫結 電信業者應用程式的 ICarrierEuiccProvisioningService 實作。
    2. 如果電信業者應用程式當機,或傳回「RESULT_CANCELED」 (這是預設回應代碼),LPA 就會取消 eSIM 卡 啟用流程。
    3. 如果電信業者應用程式回應 RESULT_OKRESULT_CANCELED,LPA 會將其視為錯誤。

    基於安全考量,LPA 不應直接接受 在結果意圖中提供的啟用程式碼,確保非 LPA 來電者無法透過電信業者應用程式取得啟用碼。

在電信業者應用程式中啟動 LPA 啟用流程

從 Android 11 開始,電信業者應用程式可以使用 eUICC API 以便啟用 eSIM 卡的 LUI 啟用。這個方法會顯示 LPA 的 eSIM 卡啟用流程 UI,以便啟用 eSIM 卡設定檔LPA 會在 eSIM 卡設定檔時傳送廣播訊息 啟用完畢。

  1. LPA 必須使用 android.service.euicc.action.START_EUICC_ACTIVATION。優先順序 的意圖篩選器應設為非零值,如果有多個 。例如:

    <application>
      ...
    <activity
        android:name=".CarrierAppInitActivity"
        android:exported="true">
    
        <intent-filter android:priority="100">
            <action android:name="android.service.euicc.action.START_EUICC_ACTIVATION" />
        </intent-filter>
    </activity>
      ...
    </application>
    
  2. 電信業者應用程式使用自己的 UI 執行作業。例如,Logging 或傳送 HTTP 要求至電信業者的後端

  3. 目前,電信業者應用程式必須準備就緒,可以提供啟用服務 透過 ICarrierEuiccProvisioningService 實作嵌入程式碼。 電信業者應用程式 startActivityForResult(Intent, int),其中包含 android.telephony.euicc.action.START_EUICC_ACTIVATION 動作。LPA 也會檢查布林值額外項目 android.telephony.euicc.extra.USE_QR_SCANNER。如果值為 true,則 LPA 會啟動 QR 掃描器,讓使用者掃描個人資料 QR code。

  4. LPA 端會繫結至電信業者應用程式的 用於擷取啟用項目的 ICarrierEuiccProvisioningService 實作 並下載對應的設定檔LPA 會完整列出 下載期間的 UI 元素,例如載入畫面。

  5. 完成 LPA 啟用流程後,LPA 會回應 含有結果代碼的電信業者應用程式,供電信業者應用程式處理 onActivityResult(int, int, Intent)

    1. 如果 LPA 成功下載新的 eSIM 卡設定檔, 回應為 RESULT_OK
    2. 如果使用者取消 LPA 中的 eSIM 卡設定檔啟用作業, 回應為 RESULT_CANCELED
    3. 如果 LPA 回覆不是 RESULT_OKRESULT_CANCELED,電信業者應用程式會將這個問題視為錯誤。

    基於安全考量,LPA 不接受啟用代碼 直接使用指定的意圖,確保非 LPA 呼叫端無法 透過電信業者應用程式提供的啟用碼

支援多張 eSIM 卡

搭載 Android 10 以上版本的裝置: EuiccManager 類別支援裝置 以及多張 eSIM 卡已升級成單一 eSIM 卡的裝置 Android 10 且平台不需要修改 LPA 導入 會自動將 EuiccManager 執行個體與預設的 eUICC 建立關聯。 eUICC 的預設 eUICC 版本為無線電 HAL 版本的裝置 1.2 以上版本。LPA 適用於無線電 HAL 版本低於 1.2.

需求條件

如要支援多張 eSIM 卡,則必須有多部 eUICC, 可以是內建 eUICC,或是可拆卸的 eUICC 的實體 SIM 卡插槽 已插入

如要支援多張 eSIM 卡,請搭載 1.2 以上版本的無線電 HAL。HAL 無線電 建議使用 1.4 版和 RadioConfig HAL 1.2 版。

實作

如要支援多張 eSIM 卡 (包括可拆卸的 eUICC 或可程式 SIM 卡),請 必須導入 LPA EuiccService、 會接收與來電者提供的卡片 ID 對應的運算單元 ID。

non_removable_euicc_slots敬上 資源中指定的資源 arrays.xml 是整數陣列,代表裝置內建運算單元的 ID eUICC。您必須指定這項資源,平台才能判斷 插入的 eUICC 是否可卸除。

搭配多張 eSIM 卡的裝置使用電信業者應用程式

為裝有多張 eSIM 卡的裝置時,請使用 createForCardId敬上 EuiccManager 中的方法,建立 EuiccManager 物件並固定至 指定的卡片 ID。卡片 ID 是專門用於識別 UICC 的整數值 或 eUICC。

如要取得裝置預設 eUICC 的卡片 ID,請使用 getCardIdForDefaultEuicc敬上 TelephonyManager 中的方法。這個方法會傳回 UNSUPPORTED_CARD_ID敬上 如果無線電 HAL 版本低於 1.2 UNINITIALIZED_CARD_ID

你也可以透過以下管道取得卡片 ID: getUiccCardsInfo敬上 和 TelephonyManager 中的 getUiccSlotsInfo (系統 API),和 getCardId 位置:SubscriptionInfo

EuiccManager 物件已使用特定卡片 ID 執行個體化時, 作業就會導向至具有該卡片 ID 的 eUICC。如果 eUICC 變為 無法連上 (例如關閉或移除) EuiccManager 否 時間越長越好

你可以使用下列程式碼範例建立電信業者應用程式。

範例 1:取得有效的訂閱項目並對 EuiccManager 執行個體化

// Get the active subscription and instantiate an EuiccManager for the eUICC which holds
// that subscription
SubscriptionManager subMan = (SubscriptionManager)
        mContext.getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE);
int cardId = subMan.getActiveSubscriptionInfo().getCardId();
EuiccManager euiccMan = (EuiccManager) mContext.getSystemService(Context.EUICC_SERVICE)
            .createForCardId(cardId);

範例 2:透過 UICC 疊代並對 EuiccManager 執行個體化 可拆式 eUICC

// On a device with a built-in eUICC and a removable eUICC, iterate through the UICC cards
// to instantiate an EuiccManager associated with a removable eUICC
TelephonyManager telMan = (TelephonyManager)
        mContext.getSystemService(Context.TELEPHONY_SERVICE);
List<UiccCardInfo> infos = telMan.getUiccCardsInfo();
int removableCardId = -1; // valid cardIds are 0 or greater
for (UiccCardInfo info : infos) {
    if (info.isRemovable()) {
        removableCardId = info.getCardId();
        break;
    }
}
if (removableCardId != -1) {
    EuiccManager euiccMan = (EuiccManager) mContext.getSystemService(Context.EUICC_SERVICE)
            .createForCardId(removableCardId);
}

驗證

Android 開放原始碼計畫並未導入 LPA,因此預期不會有 適用於所有 Android 版本 (並非所有手機都支援 eSIM 卡)。適用對象 因此沒有端對端 CTS 測試案例。不過,基本測試案例 已在 Android 開放原始碼計畫中發布,確保公開的 eUICC API 都是適用於 Android 版本的有效網址

您應確認建構已通過下列 CTS 測試案例 (公開 API):/platform/cts/tests/tests/telephony/current/src/android/telephony/euicc/cts

實作電信業者應用程式的電信業者,應在內部自行處理 品質保證 週期,以確保所有導入的功能正常運作。在 電信業者應用程式應該可以列出所有訂閱設定檔 下載及安裝設定檔、啟用服務 在個人資料上切換、切換設定檔及刪除設定檔

如果想自行設計 LPA 進行測試。請與您的數據機廠商、eUICC 晶片或 eSIM 卡 OS 廠商合作。 SM-DP+ 廠商和電信業者,一同解決問題並確保 確保 LPA 架構充分的手動測試 不可避免為了獲得最佳測試涵蓋率,請遵循以下指示: GSMA SGP.23 RSP 測試計畫