Wdróż kartę eSIM

Technologia karty SIM wbudowanej (eSIM lub eUICC) umożliwia użytkownikom urządzeń mobilnych pobieranie profilu operatora i aktywowanie usługi operatora bez posiadania fizycznej karty SIM. Jest to globalna specyfikacja oparta na standardzie GSMA, która umożliwia zdalne udostępnianie kart SIM (RSP) na dowolnym urządzeniu mobilnym. Począwszy od Androida 9, platforma Android udostępnia standardowe interfejsy API do uzyskiwania dostępu do eSIM i zarządzania profilami subskrypcji na eSIM. Te interfejsy API eUICC umożliwiają firmom zewnętrznym tworzenie własnych aplikacji operatora i asystentów lokalnych profili (LPA) na urządzeniach z Androidem obsługujących eSIM.

LPA to samodzielna aplikacja systemowa, która powinna być uwzględniona w obrazie kompilacji Androida. Profilami na karcie eSIM zwykle zarządza LPA, ponieważ stanowi ona pomost między SM-DP+ (usługa zdalna, która przygotowuje, przechowuje i dostarcza pakiety profili na urządzenia) a układem eUICC. Plik APK LPA może opcjonalnie zawierać element interfejsu użytkownika (LPA UI lub LUI), który umożliwia użytkownikowi końcowemu zarządzanie wszystkimi wbudowanymi profilami subskrypcji. Platforma Android automatycznie wykrywa i łączy się z najlepszym dostępnym LPA oraz kieruje wszystkie operacje eUICC przez instancję LPA.

Uproszczona architektura zdalnego przydzielania kart SIM (RSP)

Rysunek 1. Uproszczona architektura RSP

Operatorzy sieci komórkowych chcący utworzyć aplikację operatora, powinni się zapoznać z interfejsami API w EuiccManager, które umożliwiają ogólne działania zarządzania profilami, np. downloadSubscription(), switchToSubscription() i deleteSubscription().

Jeśli jesteś OEM-em urządzeń i chcesz utworzyć własną aplikację systemową LPA, musisz rozszerzyć EuiccService platformę Android, aby umożliwić jej połączenie z usługami LPA. Dodatkowo należy używać interfejsów API w EuiccCardManager, które zapewniają funkcje ES10x oparte na specyfikacji GSMA RSP w wersji 2.0. Te funkcje służą do wydawania poleceń do chipa eUICC, takich jak prepareDownload(), loadBoundProfilePackage(), retrieveNotificationList()resetMemory().

Interfejsy API w EuiccManager wymagają do działania prawidłowo wdrożonej aplikacji LPA, a wywołaniem interfejsów API EuiccCardManager musi być LPA. Jest to wymuszane przez platformę Androida.

Urządzenia z Androidem 10 lub nowszym mogą obsługiwać urządzenia z wieloma eSIM-ami. Więcej informacji znajdziesz w artykule Obsługa wielu kart eSIM.

Tworzenie aplikacji operatora

Interfejsy eUICC w Androidzie 9 umożliwiają operatorom sieci komórkowych tworzenie aplikacji z logo operatora, aby mogli bezpośrednio zarządzać swoimi profilami. Obejmuje to pobieranie i usuwanie profili subskrypcji należących do operatora, a także przełączanie się na profil należący do operatora.

EuiccManager

EuiccManager to główny punkt wejścia dla aplikacji do interakcji z LPA. Dotyczy to aplikacji operatora, które pobierają, usuwają i przełączają subskrypcje należące do operatora. Obejmuje to również aplikację systemową LUI, która zapewnia centralne miejsce/interfejs użytkownika do zarządzania wszystkimi osadzonymi subskrypcjami. Może to być aplikacja inna niż ta, która zapewnia EuiccService.

Aby korzystać z publicznych interfejsów API, aplikacja operatora musi najpierw uzyskać instancję EuiccManager za pomocą Context#getSystemService:

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

Zanim wykonasz jakiekolwiek operacje związane z kartą eSIM, sprawdź, czy jest ona obsługiwana na urządzeniu. Funkcja EuiccManager#isEnabled() zwraca zwykle wartość true, jeśli zdefiniowana jest funkcja android.hardware.telephony.euicc i obecny jest pakiet LPA.

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

Aby uzyskać informacje o sprzęcie eUICC i wersji systemu operacyjnego eSIM:

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

Wiele interfejsów API, takich jak downloadSubscription()switchToSubscription(), używa wywołań zwrotnych PendingIntent, ponieważ ich wykonanie może zająć kilka sekund lub minut. PendingIntent jest wysyłany z kodem wyniku w polu EuiccManager#EMBEDDED_SUBSCRIPTION_RESULT_, który zawiera zdefiniowane przez framework kody błędów, a także dowolny szczegółowy kod wyniku propagowany z LPA jako EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE, co pozwala aplikacji operatora śledzić te informacje na potrzeby rejestrowania i debugowania. Wywołanie zwrotne PendingIntent musi być BroadcastReceiver.

Aby pobrać daną subskrypcję do pobrania (utworzoną za pomocą kodu aktywacyjnego lub kodu 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);

Zdefiniuj uprawnienie i używaj go w AndroidManifest.xml:

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

Aby przejść na subskrypcję o podanym identyfikatorze:

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

Pełną listę interfejsów API EuiccManager i przykładów kodu znajdziesz na stronie interfejsów API eUICC.

Błędy możliwe do naprawienia

W niektórych przypadkach system nie może wykonać operacji dotyczącej karty eSIM, ale użytkownik może rozwiązać ten problem. Na przykład downloadSubscriptionmoże się nie udać, jeśli metadane profilu wskazują, że wymagany jest kod potwierdzenia operatora. switchToSubscription może się nie udać, jeśli aplikacja operatora ma uprawnienia operatora w przypadku profilu docelowego (czyli profil należy do operatora), ale nie ma uprawnień operatora w przypadku aktualnie włączonego profilu, dlatego wymagana jest zgoda użytkownika.

W takich przypadkach wywołanie zwrotne dzwoniącego jest wywoływane z parametrem EuiccManager#EMBEDDED_SUBSCRIPTION_RESULT_RESOLVABLE_ERROR. WywołanieIntent zawiera wewnętrzne dodatki, dzięki którym gdy wywołujący przekaże je doEuiccManager#startResolutionActivity, można będzie poprosić o rozwiązanie problemu za pomocą interfejsu LUI. W przypadku kodu potwierdzenia, na przykład EuiccManager#startResolutionActivity, uruchamia się ekran LUI, na którym użytkownik może wpisać kod potwierdzenia. Po wpisaniu kodu wznawia się operacja pobierania. Dzięki temu podejściu aplikacja operatora ma pełną kontrolę nad tym, kiedy wyświetla interfejs użytkownika, ale daje też LPA/LUI rozszerzalną metodę dodawania nowych sposobów rozwiązywania problemów, które użytkownik może rozwiązać samodzielnie, bez konieczności zmiany aplikacji klienta.

Android 9 definiuje w EuiccService te możliwe do naprawienia błędy, które ten interfejs powinien rozwiązać:

/**
 * 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";

Uprawnienia operatora

Jeśli jesteś operatorem i tworzysz własną aplikację, która wywołuje funkcję EuiccManagerw celu pobrania profili na urządzenie, profil powinien zawierać reguły dotyczące uprawnień operatora odpowiadające aplikacji w metadanych. Dzieje się tak, ponieważ profile subskrypcji należące do różnych operatorów mogą współistnieć na eUICC urządzenia, a każda aplikacja operatora powinna mieć dostęp tylko do profili należących do tego operatora. Na przykład operator A nie powinien być w stanie pobrać, włączyć ani wyłączyć profilu należącego do operatora B.

Aby zapewnić, że profil jest dostępny tylko dla jego właściciela, Android używa mechanizmu przyznawania specjalnych uprawnień aplikacji właściciela profilu (czyli aplikacji operatora). Platforma Android wczytuje certyfikaty zapisane w pliku reguł dostępu profilu (ARF) i wydaje aplikacjom podpisanym tymi certyfikatami uprawnienia do wywoływania interfejsów API EuiccManager. Ogólny proces:

  1. Operator podpisuje plik APK aplikacji operatora, a narzędzie apksigner dołącza do pliku APK certyfikat klucza publicznego.
  2. Operator/SM-DP+ przygotowuje profil i jego metadane, w tym plik ARF zawierający:

    1. podpis (SHA-1 lub SHA-256) certyfikatu klucza publicznego aplikacji operatora (wymagany).
    2. Nazwa pakietu aplikacji operatora (zdecydowanie zalecana)
  3. Aplikacja operatora próbuje wykonać operację eUICC za pomocą interfejsu EuiccManager API.

  4. Platforma Android sprawdza, czy skrót SHA-1 lub SHA-256 certyfikatu aplikacji wywołującej jest zgodny z podpisem certyfikatu uzyskanego z ARF profilu docelowego. Jeśli nazwa pakietu aplikacji operatora znajduje się w ARF, musi też być zgodna z nazwą pakietu aplikacji wywołującej.

  5. Po zweryfikowaniu podpisu i nazwy pakietu (jeśli są uwzględnione) aplikacja wywołująca otrzymuje uprawnienia operatora w profilu docelowym.

Metadane profilu mogą być dostępne poza samym profilem (aby LPA mogła pobrać metadane profilu z SM-DP+ przed pobraniem profilu lub z ISD-R, gdy profil jest wyłączony), dlatego powinny zawierać te same zasady dotyczące uprawnień operatora co profil.

Systemy eUICC OS i SM-DP+ muszą obsługiwać w metadanych profilu zastrzeżony tag BF76. Treść tagu powinna być takimi samymi regułami uprawnień operatora jak te zwracane przez aplet reguł dostępu (ARA) zdefiniowane w uprawnieniach operatora 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
    }
}

Więcej informacji o podpisywaniu aplikacji znajdziesz w artykule Podpisywanie aplikacji. Szczegółowe informacje o uprawnieniach operatora znajdziesz w artykule Uprawnienia operatora dotyczące kart UICC.

Tworzenie aplikacji asystenta lokalnego profilu

Producenci urządzeń mogą wdrażać własne lokalne profile asystenta (LPA), które muszą być połączone z interfejsami Euicc Androida. W sekcjach poniżej znajdziesz krótkie omówienie tworzenia aplikacji LPA i integracji jej z systemem Android.

Wymagania dotyczące sprzętu i modemu

LPA i system operacyjny eSIM w układzie eUICC muszą obsługiwać co najmniej GSMA RSP (zdalne udostępnianie karty SIM) w wersji 2.0 lub 2.2. Należy też zaplanować użycie serwerów SM-DP+ i SM-DS z odpowiednią wersją RSP. Szczegółowe informacje o architekturze RSP znajdziesz w specyfikacji GSMA SGP.21 RSP Architecture Specification.

Ponadto, aby umożliwić integrację z interfejsami eUICC w Androidzie 9, modem urządzenia powinien wysyłać informacje o możliwościach terminala z zakodowanymi możliwościami eUICC (zarządzanie lokalnym profilem i pobieranie profilu). Musi też implementować te metody:

  • IRadio HAL wer. 1.1: setSimPower
  • IRadio HAL w wersji 1.2: getIccCardStatus

  • IRadioConfig HAL v1.0: getSimSlotsStatus

  • IRadioConfig AIDL v1.0: getAllowedCarriers

    Usługa LPA Google musi znać stan blokady operatora, aby umożliwić pobieranie lub przenoszenie eSIM tylko dla dozwolonego operatora. W przeciwnym razie użytkownik może pobrać i przenieść kartę SIM, a potem się zorientować, że urządzenie jest zablokowane w sieci operatora.

    • Dostawcy lub OEM-y muszą zaimplementować interfejs HAL IRadioSim.getAllowedCarriers().

    • Dostawca RIL / Modem powinien wypełnić stan blokady i identyfikator operatora, do którego urządzenie jest zablokowane, w ramach interfejsu HAL IRadioSimResponse.getAllowedCarriersResponse().

Modem powinien rozpoznać kartę eSIM z włączonym domyślnym profilem rozruchu jako prawidłową kartę SIM i utrzymać zasilanie karty SIM.

W przypadku urządzeń z Androidem 10 należy zdefiniować nieusuwalny tablicowy identyfikator slotu karty eUICC. Zobacz np. 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>

Pełną listę wymagań modemu znajdziesz w artykule Wymagania dotyczące modemu na potrzeby obsługi eSIM.

Usługa EuiccService

LPA składa się z 2 oddzielnych komponentów (oba mogą być zaimplementowane w tym samym pliku APK): backendu LPA i interfejsu LPA lub LUI.

Aby zaimplementować backend LPA, musisz rozszerzyć EuiccService i zadeklarować tę usługę w pliku manifestu. Usługa musi wymagać uprawnień systemowych android.permission.BIND_EUICC_SERVICE, aby możliwe było powiązanie z nią tylko systemu. Usługa musi też zawierać filtr intencji z działaniem android.service.euicc.EuiccService. Priorytet filtra intencji powinien mieć wartość niezerową na wypadek, gdyby na urządzeniu było zainstalowanych kilka implementacji. Na przykład:

<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>

Wewnętrznie platforma Android określa aktywny interfejs LPA i współdziała z nim w sposób potrzebny do obsługi interfejsów eUICC API na Androida. PackageManager jest zapytaniem o wszystkie aplikacje z uprawnieniem android.permission.WRITE_EMBEDDED_SUBSCRIPTIONS, które określa usługę dla działania android.service.euicc.EuiccService. Wybierana jest usługa o najwyższym priorytecie. Jeśli nie zostanie znaleziona żadna usługa, obsługa LPA jest wyłączona.

Aby wdrożyć LUI, musisz podać aktywność dla tych działań:

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

Tak jak w przypadku usługi, każda aktywność musi wymagać uprawnień systemowych android.permission.BIND_EUICC_SERVICE. Każdy z nich powinien mieć filtr intencji z odpowiednim działaniem, kategorią android.service.euicc.category.EUICC_UI i priorytetem innym niż 0. Do wyboru implementacji tych działań używana jest podobna logika, co do wyboru implementacji EuiccService. Na przykład:

<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>

Oznacza to, że interfejs użytkownika implementujący te ekrany może pochodzić z innego pliku APK niż ten, który implementuje interfejsEuiccService. Możesz zdecydować, czy masz pojedynczy plik APK, czy kilka plików APK (np. jeden z implementacją EuiccService i jeden z działaniami LUI).

EuiccCardManager

EuiccCardManager to interfejs do komunikacji z układem eSIM. Udostępnia funkcje ES10 (opisane w specyfikacji GSMA RSP) oraz obsługuje proste polecenia żądania/odpowiedzi APDU oraz analizowanie ASN.1. EuiccCardManager to interfejs API systemu, którego mogą używać tylko aplikacje z przywilejami systemowymi.

Aplikacje operatora, interfejsy LPA i Euicc API

Rysunek 2. Aplikacje operatora i LPA używają interfejsów API Euicc

Interfejsy API operacji na profilu przez EuiccCardManager wymagają, aby wywołujący był LPA. Jest to wymuszane przez platformę Androida. Oznacza to, że wywołujący musi rozszerzać interfejs EuiccService i być zadeklarowany w pliku manifestu zgodnie z opisem w poprzednich sekcjach.

Podobnie jak w przypadku EuiccManager, aby można było korzystać z interfejsów API EuiccCardManager, LPA musi najpierw uzyskać instancję EuiccCardManager do Context#getSystemService:

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

Aby uzyskać wszystkie profile na 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);

Wewnętrznie EuiccCardManager łączy się z EuiccCardController (który działa w procesie telefonu) za pomocą interfejsu AIDL, a każda metoda EuiccCardManager otrzymuje wywołanie zwrotne z procesu telefonu za pomocą innego, dedykowanego interfejsu AIDL. Podczas korzystania z interfejsów API EuiccCardManager wywołujący (LPA) musi podać obiekt Executor, za pomocą którego wywoływane jest callback. Ten obiekt Executor może działać w pojedynczym wątku lub w wybranej puli wątków.

Większość interfejsów API EuiccCardManager ma ten sam schemat użycia. Aby na przykład załadować na eUICC pakiet profilu przychodzącego:

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

Aby przełączyć się na inny profil z danym identyfikatorem ICCID:

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

Aby uzyskać domyślny adres SM-DP+ z urządzenia eUICC:

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

Aby pobrać listę powiadomień z danymi zdarzeniami powiadomień:

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

Aktywowanie profilu eSIM w aplikacji operatora

Na urządzeniach z Androidem 9 lub nowszym możesz użyć aplikacji operatora, aby aktywować eSIM i pobrać profile. Aplikacja operatora może pobrać profile, wywołując bezpośrednio usługę downloadSubscription lub podając kod aktywacyjny do LPA.

Gdy aplikacja operatora pobiera profil, wywołując funkcję downloadSubscription, wywołanie to zapewnia aplikacji możliwość zarządzania profilem za pomocą BF76 tagu metadanych, który koduje zasady uprawnień operatora dla profilu. Jeśli profil nie ma tagu BF76 lub jeśli jego tag BF76 nie pasuje do podpisu aplikacji operatora, pobieranie jest odrzucane.

W sekcji poniżej opisaliśmy aktywowanie eSIM w aplikacji operatora za pomocą kodu aktywacyjnego.

Aktywuj kartę eSIM za pomocą kodu aktywacyjnego

Gdy do aktywacji profilu eSIM używasz kodu aktywacyjnego, LPA pobiera kod aktywacyjny z aplikacji operatora i pobiera profil. Ten proces może zostać zainicjowany przez LPA, który może kontrolować cały proces na interfejsie użytkownika, co oznacza, że nie jest wyświetlany żaden interfejs aplikacji operatora. Dzięki temu można pominąć sprawdzanie tagu BF76, a operatorzy sieci nie muszą wdrażać całego procesu aktywacji eSIM w interfejsie użytkownika, w tym pobierania profilu eSIM i obsługi błędów.

Zdefiniuj usługę obsługi eUICC operatora

Aplikacja LPA i aplikacja operatora komunikują się za pomocą 2 interfejsów AIDL:ICarrierEuiccProvisioningServiceIGetActivationCodeCallback. Aplikacja operatora musi implementować interfejs ICarrierEuiccProvisioningService i ujawnić go w deklaracji pliku manifestu. LPA musi być powiązana z poziomem ICarrierEuiccProvisioningService i wdrażać IGetActivationCodeCallback. Więcej informacji o wdrażaniu i wyświetlaniu interfejsu AIDL znajdziesz w artykule Definiowanie interfejsu AIDL.

Aby zdefiniować interfejsy AIDL, utwórz te pliki AIDL zarówno dla aplikacji LPA, jak i aplikacji operatora.

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

Przykładowa implementacja LPA

Aby powiązać z implementacją ICarrierEuiccProvisioningService aplikacji operatora, lokalna reklamacja musi skopiować do Twojego projektu zarówno ICarrierEuiccProvisioningService.aidl, jak i IGetActivationCodeCallback.aidl oraz wdrożyć ServiceConnection.

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

Po powiązaniu z implementacją aplikacji operatora ICarrierEuiccProvisioningServiceLPA wywołuje funkcję getActivationCode lub getActivationCodeForEid, aby uzyskać kod aktywacyjny z aplikacji operatora, przekazując implementację klasy stub IGetActivationCodeCallback.

Różnica między getActivationCodegetActivationCodeForEid polega na tym, że getActivationCodeForEid umożliwia operatorowi wstępne powiązanie profilu z identyfikatorem EID urządzenia przed rozpoczęciem procesu pobierania.

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
    }
}

Przykładowa implementacja w aplikacji operatora

Aby usługa LPA mogła się wiązać z aplikacją operatora, aplikacja operatora musi skopiować do Twojego projektu pliki ICarrierEuiccProvisioningService.aidlIGetActivationCodeCallback.aidl oraz zadeklarować usługę ICarrierEuiccProvisioningService w pliku AndroidManifest.xml. Usługa musi wymagać uprawnienia systemowego android.permission.WRITE_EMBEDDED_SUBSCRIPTIONS, aby mieć pewność, że tylko aplikacja LPA, czyli aplikacja z uprawnieniami systemowymi, może się z nią powiązać. Usługa musi też zawierać filtr intencji z działaniem 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>
    

Aby zaimplementować usługę aplikacji operatora AIDL, utwórz usługę, rozszerz klasę Stub i zaimplementuj metody getActivationCodegetActivationCodeForEid. Następnie LPA może wywołać dowolną z tych metod, aby pobrać kod aktywacyjny profilu. Aplikacja operatora powinna odpowiedzieć, wywołując IGetActivationCodeCallback#onSuccess z kodem aktywacyjnym, jeśli kod został pomyślnie pobrany z serwera operatora. W przeciwnym razie aplikacja operatora powinna odpowiedzieć 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);
              }
          }
    }
    

Uruchom interfejs aplikacji operatora w ramach procesu aktywacji LPA

Na urządzeniach z Androidem 11 lub nowszym LPA może uruchomić interfejs aplikacji operatora. Jest to przydatne, ponieważ aplikacja operatora może wymagać od użytkownika dodatkowych informacji przed przekazaniem kodu aktywacyjnego do LPA. Na przykład operatorzy mogą wymagać od użytkowników zalogowania się w celu aktywacji numeru telefonu lub wykonania innych usług przenoszenia.

Oto jak uruchomić interfejs aplikacji operatora w LPA:

  1. LPA uruchamia proces aktywacji aplikacji operatora, wysyłając intencję android.service.euicc.action.START_CARRIER_ACTIVATION do pakietu aplikacji operatora zawierającego działanie. (W celu uniknięcia otrzymywania intencji z aplikacji, które nie są zgodne z LPA, odbiornik aplikacji operatora musi być chroniony w deklaracji pliku manifestu za pomocą flagi android:permission="android.permission.WRITE_EMBEDDED_SUBSCRIPTIONS".)

    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. Aplikacja operatora używa własnego interfejsu użytkownika. Na przykład rejestrowanie danych użytkownika lub wysyłanie żądań HTTP do backendu operatora.

  3. Aplikacja operatora odpowiada na LPA, wywołując setResult(int, Intent) i finish().

    1. Jeśli aplikacja operatora odpowie RESULT_OK, LPA kontynuuje proces aktywacji. Jeśli aplikacja operatora ustali, że użytkownik powinien zeskanować kod QR, zamiast pozwolić aplikacji LPA na powiązanie usługi aplikacji operatora, aplikacja operatora odpowiada na LPA za pomocą polecenia setResult(int, Intent) z parametrem RESULT_OK i instancji Intent zawierającej dodatkową wartość logiczną android.telephony.euicc.extra.USE_QR_SCANNER ustawioną na true. Następnie LPA sprawdza dodatkowe informacje i uruchamia skaner kodów QR zamiast implementacji ICarrierEuiccProvisioningService w aplikacji operatora.
    2. Jeśli aplikacja operatora ulegnie awarii lub odpowie kodem RESULT_CANCELED (jest to domyślny kod odpowiedzi), LPA anuluje proces aktywacji eSIM.
    3. Jeśli aplikacja operatora odpowie czymś innym niż RESULT_OK lub RESULT_CANCELED, LPA uzna to za błąd.

    Ze względów bezpieczeństwa LPA nie powinna bezpośrednio akceptować kodu aktywacyjnego podanego w intencji wyniku, aby osoby dzwoniące, które nie korzystają z LPA, nie mogły uzyskać kodu aktywacyjnego z aplikacji operatora.

Uruchom proces aktywacji LPA w aplikacji operatora

Od Androida 11 aplikacje operatora mogą używać interfejsów eUICC do uruchamiania interfejsu LUI na potrzeby aktywacji eSIM. Ta metoda wyświetla interfejs użytkownika procesu aktywacji eSIM w LPA, aby aktywować profil eSIM. Gdy aktywacja profilu eSIM się zakończy, LPA wyśle transmisję.

  1. LPA musi zadeklarować działanie zawierające filtr intencji z działaniem android.service.euicc.action.START_EUICC_ACTIVATION. Priorytet filtra intencji powinien mieć wartość niezerową na wypadek, gdyby na urządzeniu było kilka implementacji. Na przykład:

    <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. Aplikacja operatora działa przy użyciu własnego interfejsu. Na przykład rejestrowanie danych użytkownika lub wysyłanie żądań HTTP do backendu operatora.

  3. W tym momencie aplikacja operatora musi być gotowa do udostępnienia kodu aktywacyjnego za pomocą implementacji ICarrierEuiccProvisioningService. Aplikacja operatora uruchamia LPA, wywołując funkcję startActivityForResult(Intent, int) z działaniem android.telephony.euicc.action.START_EUICC_ACTIVATION. LPA sprawdza też wartość logiczną dodatkowego atrybutu android.telephony.euicc.extra.USE_QR_SCANNER. Jeśli wartość to true, LPA uruchamia skaner kodów QR, aby umożliwić użytkownikowi zeskanowanie kodu QR profilu.

  4. Po stronie LPA platforma LPA wiąże się z implementacją ICarrierEuiccProvisioningService aplikacji operatora, aby pobrać kod aktywacyjny i pobrać odpowiedni profil. Podczas pobierania LPA wyświetla wszystkie niezbędne elementy interfejsu użytkownika, np. ekran wczytywania.

  5. Gdy proces aktywacji LPA się zakończy, LPA odpowiada aplikacji operatora, przesyłając kod wyniku obsługiwany przez aplikację operatora w onActivityResult(int, int, Intent).

    1. Jeśli LPA pobierze nowy profil eSIM, otrzyma odpowiedź RESULT_OK.
    2. Jeśli użytkownik anuluje aktywację profilu eSIM w LPA, odpowiedź będzie zawierać wartość RESULT_CANCELED.
    3. Jeśli LPA odpowie czymś innym niż RESULT_OK lub RESULT_CANCELED, aplikacja operatora uzna to za błąd.

    Ze względów bezpieczeństwa LPA nie akceptuje kodu aktywacyjnego bezpośrednio w podanej intencji, aby osoby dzwoniące z poza LPA nie mogły uzyskać kodu aktywacyjnego z aplikacji operatora.

Obsługuj wiele kart eSIM

.

W przypadku urządzeń z Androidem 10 lub nowszym klasa EuiccManager obsługuje urządzenia z wieloma kartami eSIM. Urządzenia z pojedynczą kartą eSIM, które są uaktualniane do Androida 10, nie wymagają żadnych zmian w implementacji LPA, ponieważ platforma automatycznie wiąże instancję EuiccManager z domyślną wartością eUICC. Domyślna wartość eUICC jest określana przez platformę w przypadku urządzeń z radiem HAL w wersji 1.2 lub nowszej oraz przez LPA w przypadku urządzeń z radiem w wersji HAL starszej niż 1.2.

Wymagania

Aby obsługiwać wiele kart eSIM, urządzenie musi mieć więcej niż 1 kartę eUICC, która może być wbudowana lub fizyczna. Karta eUICC może być wkładana do gniazda na kartę SIM.

Do obsługi wielu kart eSIM wymagany jest radio HAL w wersji 1.2 lub nowszej. Zaleca się korzystanie z radia HAL w wersji 1.4 i RadioConfig HAL w wersji 1.2.

Implementacja

Aby obsługiwać wiele kart eSIM (w tym wyjmowane karty eUICC lub programowalne karty SIM), LPA musi zaimplementować element EuiccService, który otrzymuje identyfikator slotu odpowiadający identyfikatorowi karty podanemu przez wywołującego.

Zasób non_removable_euicc_slots określony w zadaniu arrays.xml to tablica liczb całkowitych reprezentujących identyfikatory wbudowanych numerów eUICC urządzenia. Musisz określić ten zasób, aby umożliwić platformie określenie, czy włożona karta eUICC jest wymienna.

Aplikacja operatora na urządzenie z wieloma kartami eSIM

Gdy tworzysz aplikację operatora na urządzenie z wieloma kartami eSIM, użyj metody createForCardId w EuiccManager, aby utworzyć obiekt EuiccManager, który będzie przypięty do podanego identyfikatora karty. Identyfikator karty to wartość całkowita, która jednoznacznie identyfikuje kartę UICC lub eUICC na urządzeniu.

Aby uzyskać identyfikator karty domyślnego eUICC urządzenia, użyj metody getCardIdForDefaultEuiccTelephonyManager. Ta metoda zwraca UNSUPPORTED_CARD_ID, jeśli wersja radiowa HAL jest niższa niż 1.2, i zwraca UNINITIALIZED_CARD_ID, jeśli urządzenie nie odczytało eUICC.

Możesz też uzyskać identyfikatory kart z getUiccCardsInfo i getUiccSlotsInfo (systemowy interfejs API) w TelephonyManager, a getCardId w SubscriptionInfo.

Gdy obiekt EuiccManager został utworzony z określonym identyfikatorem karty, wszystkie operacje są kierowane do eUICC z tym identyfikatorem karty. Jeśli karta eUICC stanie się niedostępna (na przykład, gdy zostanie wyłączona lub usunięta), EuiccManager przestanie działać.

Aby utworzyć aplikację operatora, możesz skorzystać z poniższych przykładów kodu.

Przykład 1. Pobieranie aktywnej subskrypcji i tworzenie instancji 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);

Przykład 2. Przechodzenie przez karty UICC i tworzenie instancji EuiccManager dla wymiennych kart 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);
}

Weryfikacja

AOSP nie zawiera implementacji LPA i nie jest ona dostępna we wszystkich wersjach Androida (nie każdy telefon obsługuje eSIM). Dlatego nie ma tu kompleksowych przypadków testowych. Jednak podstawowe przypadki testowe są dostępne w AOSP, aby zapewnić, że ujawnione interfejsy eUICC są prawidłowe w kompilacji Androida.

Upewnij się, że kompilacje przechodzą te testy CTS (w przypadku publicznych interfejsów API): /platform/cts/tests/tests/telephony/current/src/android/telephony/euicc/cts.

Operatorzy, którzy wdrażają aplikację operatora, powinni przejść normalny cykl kontroli jakości, aby mieć pewność, że wszystkie wdrożone funkcje działają zgodnie z oczekiwaniami. Aplikacja operatora powinna mieć możliwość wyświetlania wszystkich profili subskrypcji należących do tego samego operatora, pobierania i instalowania profilu, aktywowania usługi na profilu, przełączania się między profilami i usuwania profili.

Jeśli tworzysz własną umowę LPA, musisz przeprowadzić znacznie bardziej rygorystyczne testy. Aby rozwiązać problemy i zapewnić interoperacyjność LPA z architekturą RSP, skontaktuj się z dostawcą modemu, układem eUICC lub dostawcą systemu operacyjnego eSIM, SM-DP+ i operatorami. Pewna ilość testów ręcznych jest nieunikniona. Aby uzyskać najlepsze wyniki testów, postępuj zgodnie z planem testów RSP stowarzyszenia GSMA (SGP.23).