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 opracowana przez GSMA, która umożliwia zdalne konfigurowanie kart SIM 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. Zarządzanie profilami na eSIM jest zwykle realizowane przez LPA, ponieważ pełni ono rolę łącznika między SM-DP+ (usługą zdalną, która przygotowuje, przechowuje i przesyła pakiety profili na urządzenia) a chipem 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, którzy chcą tworzyć aplikacje operatora, powinni zapoznać się z interfejsami API w EuiccManager, które umożliwiają ogólne operacje zarządzania profilem, takie jak downloadSubscription(), switchToSubscription()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żyć 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().

Aby interfejsy API w EuiccManager mogły działać, wymagana jest prawidłowo zaimplementowana aplikacja LPA, a wywołujący interfejs API EuiccCardManager musi być aplikacją LPA. Jest to wymuszane przez platformę Android.

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 funkcja android.hardware.telephony.euicc jest zdefiniowana, a pakiet LPA jest obecny.

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, które mogą trwać kilka sekund lub nawet 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ć dane 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żyj 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 przełączyć się na subskrypcję podając jej identyfikator:

// 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łady kodu znajdziesz w artykule Interfejsy API eUICC.

Rozwiązywanie błędów

W niektórych przypadkach system nie może wykonać operacji dotyczącej karty eSIM, ale błąd może zostać naprawiony przez użytkownika. 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 rozmówca 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 te możliwe do rozwiązania błędy w EuiccService, które LUI powinien obsługiwać:

/**
 * 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, Twój profil powinien zawierać reguły 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 mieć możliwości pobierania, włączania ani wyłączania 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 przyznaje aplikacjom podpisanym tymi certyfikatami uprawnienia do wywoływania interfejsów API EuiccManager. Ogólny proces:

  1. Operator podpisuje plik APK aplikacji operatora. 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 (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 pliku ARF, musi też odpowiadać nazwie pakietu aplikacji wywołującej.

  5. Po zweryfikowaniu podpisu i nazwy pakietu (jeśli jest podana) aplikacji wywołującej przyznawane są uprawnienia operatora dotyczące profilu docelowego.

Metadane profilu mogą być dostępne poza samym profilem (aby usługa 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 na profilu.

System operacyjny eUICC i SM-DP+ musi obsługiwać zastrzeżony tag BF76 w metadanych profilu. Treść tagu powinna być taka sama jak reguły uprawnień operatora zwracane przez applet reguły dostępu (ARA) zdefiniowany 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 następnych sekcjach znajdziesz krótkie omówienie tworzenia aplikacji LPA i jej integrowania z systemem Android.

Wymagania dotyczące sprzętu i modemu

LPA i system eSIM na chipie eUICC muszą obsługiwać co najmniej GSMA RSP (Remote SIM Provisioning) 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 v1.1: setSimPower
  • IRadio HAL v1.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żytkownicy mogą pobrać i przenosić kartę SIM, a później zorientować się, że urządzenie jest zablokowane u innego 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ć 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 musisz zdefiniować nieusuwalny tablicowy identyfikator slotu karty eUICC. Przykład: 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ń dotyczących modemu znajdziesz w artykule Wymagania dotyczące modemu w przypadku obsługi eSIM.

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ć uprawnienia systemowego android.permission.BIND_EUICC_SERVICE, aby tylko system mógł się z nią powiązać. Usługa musi też zawierać filtr intencji z działaniem android.service.euicc.EuiccService. Priorytet filtra intencji powinien mieć wartość niezerową, jeśli na urządzeniu jest obecnych wiele implementacji. 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 wysyłany do wszystkich aplikacji 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

Podobnie jak w przypadku usługi, każda aktywność musi wymagać uprawnienia systemowego 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 implementacji EuiccService. 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. To, czy chcesz mieć 1 czy kilka plików APK (np. jeden z implementacją EuiccService i jeden z aktywnościami LUI), zależy od projektu.

EuiccCardManager

EuiccCardManager to interfejs do komunikacji z kartą eSIM. Udostępnia funkcje ES10 (opisane w specyfikacji GSMA RSP) i obsługuje polecenia żądania/odpowiedzi APDU niskiego poziomu oraz analizę 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. Zarówno aplikacja operatora, jak i LPA korzystają z interfejsów Euicc API

Interfejsy API operacji na profilu przez EuiccCardManager wymagają, aby wywołujący był LPA. Jest to wymuszane przez platformę Android. 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 interfejsu EuiccManager, aby korzystać z interfejsów API EuiccCardManager, dostawca usług w zakresie reklamy w Google musi najpierw uzyskać instancję EuiccCardManager za pomocą 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. Obiekt Executor może działać w pojedynczym wątku lub w wybranym przez Ciebie 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 układu 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 pobierać profile, wywołując funkcję downloadSubscription bezpośrednio lub przekazując kod aktywacyjny do LPA.

Gdy aplikacja operatora pobiera profil, wywołując downloadSubscription, wywołanie to zapewnia aplikacji możliwość zarządzania profilem za pomocą BF76 tagu metadanych, który zawiera reguły uprawnień operatora dotyczące 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.

Aktywowanie 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 implementować 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ład implementacji LPA

Aby umożliwić wiązanie z implementacją ICarrierEuiccProvisioningService w aplikacji operatora, LPA musi skopiować do projektu zarówno ICarrierEuiccProvisioningService.aidl, jak i IGetActivationCodeCallback.aidl, oraz zaimplementować 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 funkcję 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ę, aby aktywować ich numery telefonów lub wykonać inne usługi przenoszenia.

Oto jak uruchomić interfejs aplikacji operatora w ramach 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 deklaracji manifestu odbiornik aplikacji operatora musi być chroniony za pomocą parametru android:permission="android.permission.WRITE_EMBEDDED_SUBSCRIPTIONS", aby uniknąć otrzymywania intencji z aplikacji bez 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. 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. 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ć LPA na powiązanie usługi aplikacji operatora, aplikacja operatora odpowiada LPA za pomocą setResult(int, Intent)RESULT_OK i instancją Intent zawierającą dodatkowy parametr logiczny android.telephony.euicc.extra.USE_QR_SCANNER ustawiony na wartość 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, usługa 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.

Uruchamianie procesu 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 deklarować aktywność, która zawiera 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. 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 usługa LPA łączy się z implementacją aplikacji operatora ICarrierEuiccProvisioningService, aby pobrać kod aktywacyjny i pobrać odpowiedni profil. Podczas pobierania LPA wyświetla wszystkie niezbędne elementy interfejsu użytkownika, np. ekran wczytywania.

  5. Po zakończeniu procesu aktywacji LPA LPA odpowiada aplikacji operatora kodem wyniku, który aplikacja operatora obsługuje w onActivityResult(int, int, Intent).

    1. Jeśli LPA pomyślnie pobierze nowy profil eSIM, odpowie 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 spoza LPA nie mogły uzyskać kodu aktywacyjnego z aplikacji operatora.

Obsługa wielu kart eSIM

W przypadku urządzeń z Androidem 10 lub nowszym klasa EuiccManager obsługuje urządzenia z wieloma eSIM-ami. Urządzenia z 1 kartą eSIM, które są aktualizowane do Androida 10, nie wymagają wprowadzania żadnych zmian w implementacji LPA, ponieważ platforma automatycznie powiąże instancję EuiccManager z domyślną kartą eUICC. Domyślny eUICC jest określany przez platformę w przypadku urządzeń z wersją interfejsu radiowego HAL 1.2 lub nowszą oraz przez LPA w przypadku urządzeń z wersją interfejsu radiowego HAL niższą 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.

Aby obsługiwać wiele eSIM, wymagana jest wersja Radio HAL 1.2 lub nowsza. Zalecane są wersje 1.4 interfejsu Radio HAL i 1.2 interfejsu RadioConfig HAL.

Implementacja

Aby obsługiwać wiele kart eSIM (w tym wyjmowane karty eUICC lub programowalne karty SIM), LPA musi zaimplementować EuiccService, która otrzymuje identyfikator slotu odpowiadający identyfikatorowi karty podanemu przez osobę dzwoniącą.

Zasób non_removable_euicc_slots określony w arrays.xmlto tablica liczb całkowitych, która reprezentuje identyfikatory slotów wbudowanych kart 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ądzeniu z kilkoma kartami eSIM

Podczas tworzenia aplikacji operatora na urządzeniu z wieloma kartami eSIM użyj metody createForCardIdEuiccManager, aby utworzyć obiekt EuiccManager przypięty do danego 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 wartość UNSUPPORTED_CARD_ID, jeśli wersja HAL radia jest niższa niż 1.2, oraz UNINITIALIZED_CARD_ID, jeśli urządzenie nie odczyta eUICC.

Identyfikatory kart możesz też pobrać z getUiccCardsInfogetUiccSlotsInfo (interfejs API systemu) w TelephonyManager oraz z getCardIdSubscriptionInfo.

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 użyć tych 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). Z tego powodu nie ma przypadków testowych CTS obejmujących cały proces. W AOSP dostępne są jednak podstawowe przypadki testowe, które umożliwiają sprawdzenie, czy 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 wdrażający aplikację operatora powinni przejść przez normalne cykle zapewnienia jakości, aby mieć pewność, że wszystkie zaimplementowane 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 oraz usuwania profili.

Jeśli tworzysz własną umowę LPA, musisz przeprowadzić znacznie bardziej rygorystyczne testy. Aby rozwiązać problemy i zapewnić interoperacyjność LPA w ramach architektury RSP, należy współpracować z dostawcą modemu, dostawcą chipa eUICC lub systemu operacyjnego eSIM, dostawcami SM-DP+ oraz operatorami. Spora część testów ręcznych jest nieunikniona. Aby uzyskać najlepsze wyniki testów, postępuj zgodnie z planem testów RSP stowarzyszenia GSMA SGP.23.