Technologia wbudowanej karty SIM (eSIM lub eUICC) umożliwia użytkownikom urządzeń mobilnych pobieranie profilu operatora i aktywowanie jego usług bez fizycznej karty SIM. Jest to globalna specyfikacja opracowana przez GSMA, która umożliwia zdalne udostępnianie kart SIM (RSP) na dowolnym urządzeniu mobilnym. Od Androida 9 platforma Androida udostępnia standardowe interfejsy API do uzyskiwania dostępu do karty eSIM i zarządzania profilami subskrypcji na karcie eSIM. Te interfejsy API eUICC umożliwiają firmom zewnętrznym tworzenie własnych aplikacji operatorów i asystentów profili lokalnych (LPA) na urządzeniach z Androidem obsługujących karty eSIM.
LPA to samodzielna aplikacja systemowa, która powinna być uwzględniona w obrazie kompilacji Androida. Zarządzanie profilami na karcie eSIM odbywa się zwykle za pomocą aplikacji LPA, która pełni funkcję pomostu między SM-DP+ (usługą zdalną, która przygotowuje, przechowuje i dostarcza pakiety profili na urządzenia) a chipem eUICC. Aplikacja LPA może opcjonalnie zawierać komponent interfejsu użytkownika, zwany interfejsem LPA lub LUI, który zapewnia użytkownikowi centralne miejsce do zarządzania wszystkimi profilami subskrypcji wbudowanych. Platforma Android automatycznie wykrywa i łączy się z najlepszym dostępnym menedżerem profilu lokalnego oraz kieruje wszystkie operacje eUICC przez instancję menedżera profilu lokalnego.
Rysunek 1. Uproszczona architektura RSP
Operatorzy sieci komórkowych zainteresowani utworzeniem aplikacji operatora powinni zapoznać się z interfejsami API w EuiccManager
, które udostępniają operacje zarządzania profilami wysokiego poziomu, takie jak downloadSubscription()
, switchToSubscription()
i deleteSubscription()
.
Jeśli jesteś producentem OEM urządzeń i chcesz utworzyć własną aplikację systemową LPA, musisz rozszerzyć EuiccService
w ramach Androida, aby połączyć się z usługami LPA. Dodatkowo należy używać interfejsów API w EuiccCardManager
, które udostępniają funkcje ES10x oparte na GSMA RSP w wersji 2.0.
Te funkcje służą do wydawania poleceń do układu eUICC, takich jak prepareDownload()
, loadBoundProfilePackage()
, retrieveNotificationList()
i resetMemory()
.
Interfejsy API w EuiccManager
wymagają prawidłowo zaimplementowanej aplikacji LPA, a wywołujący interfejsy API EuiccCardManager
musi być LPA. Jest to egzekwowane przez platformę Androida.
Urządzenia z Androidem 10 lub nowszym mogą obsługiwać urządzenia z wieloma kartami eSIM. Więcej informacji znajdziesz w artykule Obsługa wielu kart eSIM.
Tworzenie aplikacji operatora
Interfejsy API eUICC w Androidzie 9 umożliwiają operatorom sieci komórkowych tworzenie aplikacji oznaczonych ich marką, które służą do bezpośredniego zarządzania 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, które chcą korzystać z usługi LPA. Dotyczy to aplikacji operatorów, które pobierają, usuwają i przełączają się na subskrypcje należące do operatora. Obejmuje to również aplikację systemową LUI, która zapewnia centralną lokalizację lub interfejs do zarządzania wszystkimi subskrypcjami wbudowanymi i może być oddzielną aplikacją od tej, która zapewnia EuiccService
.
Aby korzystać z publicznych interfejsów API, aplikacja przewoźnika musi najpierw uzyskać instancję EuiccManager
za pomocą Context#getSystemService
:
EuiccManager mgr = (EuiccManager) context.getSystemService(Context.EUICC_SERVICE);
Zanim wykonasz jakiekolwiek operacje na karcie eSIM, sprawdź, czy jest ona obsługiwana na urządzeniu. Funkcja EuiccManager#isEnabled()
zwykle zwraca wartość true
, jeśli zdefiniowana jest funkcja android.hardware.telephony.euicc
i występuje 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, np. downloadSubscription()
i switchToSubscription()
, używa PendingIntent
wywołań zwrotnych, ponieważ ich wykonanie może zająć sekundy, a nawet minuty.
PendingIntent
jest wysyłany z kodem wyniku w przestrzeni EuiccManager#EMBEDDED_SUBSCRIPTION_RESULT_
, który zawiera zdefiniowane przez platformę kody błędów, a także dowolny szczegółowy kod wyniku przekazywany z LPA jako EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE
, co umożliwia aplikacji operatora śledzenie na potrzeby rejestrowania i debugowania. Wywołanie zwrotne PendingIntent
musi mieć wartość BroadcastReceiver
.
Aby pobrać subskrypcję, którą można pobrać (utworzoną na podstawie 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 przejść na subskrypcję na podstawie identyfikatora subskrypcji:
// 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.
Błędy, które można rozwiązać
W niektórych przypadkach system nie może dokończyć operacji na karcie eSIM, ale użytkownik może rozwiązać ten problem. Na przykład downloadSubscription
może się nie powieść, jeśli metadane profilu wskazują, że wymagany jest kod potwierdzenia operatora. lub switchToSubscription
może się nie powieść, jeśli aplikacja operatora ma uprawnienia operatora w profilu docelowym (czyli operator jest właścicielem profilu), ale nie ma uprawnień operatora w obecnie włączonym profilu, a tym samym wymagana jest zgoda użytkownika.
W takich przypadkach wywołanie zwrotne jest wywoływane z wartością EuiccManager#EMBEDDED_SUBSCRIPTION_RESULT_RESOLVABLE_ERROR
. Funkcja zwrotna
Intent
zawiera wewnętrzne dodatki, dzięki czemu gdy rozmówca przekaże ją do
EuiccManager#startResolutionActivity
,
można poprosić o rozwiązanie problemu za pomocą interfejsu LUI. Ponowne użycie kodu potwierdzającego, np. EuiccManager#startResolutionActivity
, spowoduje wyświetlenie ekranu LUI, na którym użytkownik może wpisać kod potwierdzający. Po wpisaniu kodu pobieranie zostanie wznowione. Dzięki temu aplikacja operatora ma pełną kontrolę nad tym, kiedy wyświetlać interfejs, a LPA/LUI ma rozszerzalną metodę dodawania w przyszłości nowych sposobów obsługi problemów, które użytkownik może rozwiązać samodzielnie, bez konieczności wprowadzania zmian w aplikacjach klienckich.
Android 9 definiuje te błędy, które można rozwiązać, w EuiccService
. Interfejs LUI powinien sobie z nimi poradzić:
/**
* 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, który tworzy własną aplikację operatora wywołującą EuiccManager
w celu pobierania profili na urządzenie, Twój profil powinien zawierać w metadanych reguły uprawnień operatora
odpowiadające Twojej aplikacji operatora. Dzieje się tak, ponieważ profile subskrypcji należące do różnych operatorów mogą współistnieć na karcie 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 profil był 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 przechowywane w pliku reguł dostępu profilu (ARF) i przyznaje aplikacjom podpisanym tymi certyfikatami uprawnienia do wywoływania interfejsów API EuiccManager
. Ogólny proces wygląda tak:
- Operator podpisuje plik APK aplikacji operatora. Narzędzie apksigner dołącza do pliku APK certyfikat klucza publicznego.
Operator/SM-DP+ przygotowuje profil i jego metadane, które obejmują plik ARF zawierający:
- Podpis (SHA-1 lub SHA-256) certyfikatu klucza publicznego aplikacji operatora (wymagany)
- Nazwa pakietu aplikacji przewoźnika (zdecydowanie zalecane)
Aplikacja operatora próbuje wykonać operację eUICC za pomocą interfejsu
EuiccManager
API.Platforma Android weryfikuje, czy skrót SHA-1 lub SHA-256 certyfikatu aplikacji wywołującej jest zgodny z podpisem certyfikatu uzyskanego z pliku ARF profilu docelowego. Jeśli nazwa pakietu aplikacji operatora jest uwzględniona w pliku ARF, musi być zgodna z nazwą pakietu aplikacji dzwoniącej.
Po zweryfikowaniu podpisu i nazwy pakietu (jeśli jest uwzględniona) aplikacja wywołująca otrzymuje uprawnienia operatora do profilu docelowego.
Metadane profilu mogą być dostępne poza samym profilem (dzięki czemu LPA może pobrać metadane profilu z SM-DP+ przed pobraniem profilu lub z ISD-R, gdy profil jest wyłączony), dlatego powinny zawierać te same reguły uprawnień operatora co profil.
System operacyjny eUICC i SM-DP+ muszą obsługiwać tag własności BF76
w metadanych profilu. Zawartość tagu powinna być taka sama jak reguły uprawnień operatora zwrócone przez aplet reguł dostępu (ARA) zdefiniowany w dokumencie UICC Carrier Privileges:
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. Więcej informacji o uprawnieniach operatora znajdziesz w artykule Uprawnienia operatora UICC.
Tworzenie aplikacji asystującej w profilu lokalnym
Producenci urządzeń mogą wdrażać własnego lokalnego asystenta profilu (LPA), który musi być połączony z interfejsami API Euicc na Androidzie. W kolejnych sekcjach znajdziesz krótkie omówienie tworzenia aplikacji LPA i integrowania jej z systemem Android.
Wymagania dotyczące sprzętu i modemu
LPA i system operacyjny eSIM na chipie eUICC muszą obsługiwać co najmniej GSMA RSP (Remote SIM Provisioning) w wersji 2.0 lub 2.2. Powinieneś też używać serwerów SM-DP+ i SM-DS, które mają pasującą wersję RSP. Szczegółową architekturę RSP znajdziesz w specyfikacji GSMA SGP.21 RSP Architecture.
Aby zintegrować się z interfejsami eUICC API w Androidzie 9, modem urządzenia powinien wysyłać możliwości terminala z zakodowaną obsługą funkcji eUICC (lokalne zarządzanie profilami i pobieranie profili). 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 Google LPA musi znać stan blokady operatora, aby zezwalać na pobieranie lub przenoszenie karty eSIM tylko w przypadku dozwolonego operatora. W przeciwnym razie użytkownicy mogą pobrać i przenieść kartę SIM, a później zorientować się, że urządzenie jest zablokowane przez innego operatora.
Dostawcy lub producenci OEM muszą wdrożyć interfejs IRadioSim.getAllowedCarriers() HAL API.
Interfejs RIL / modem dostawcy powinien wypełniać stan blokady i identyfikator operatora, u którego urządzenie jest zablokowane, w ramach interfejsu API HAL IRadioSimResponse.getAllowedCarriersResponse().
Modem powinien rozpoznać kartę eSIM z włączonym domyślnym profilem rozruchowym jako prawidłową kartę SIM i utrzymać ją włączoną.
W przypadku urządzeń z Androidem 10 musi być zdefiniowana tablica identyfikatorów gniazd eUICC, których nie można usunąć. Na przykład zobacz 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 osobnych komponentów (oba mogą być zaimplementowane w tym samym pliku APK): backendu LPA oraz interfejsu LPA (LUI).
Aby wdrożyć 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 można było z nią powiązać tylko system. Usługa musi też zawierać filtr intencji z działaniem android.service.euicc.EuiccService
. Priorytet filtra intencji powinien być ustawiony na wartość różną od zera, jeśli na urządzeniu jest obecnych wiele 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 Androida określa aktywnego menedżera LPA i w razie potrzeby wchodzi z nim w interakcje, aby obsługiwać interfejsy API Androida eUICC. PackageManager
wysyła zapytanie 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 znajdzie żadnej usługi, obsługa LPA zostanie wyłączona.
Aby wdrożyć interfejs 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ć 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 większym od zera.
Podobna logika jest używana do wybierania implementacji tych działań jak w przypadku wybierania 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 implementujący te ekrany może pochodzić z innego pakietu APK niż ten, który implementuje EuiccService
.
To, czy chcesz mieć jeden plik APK, czy wiele plików APK (np. jeden, który implementuje EuiccService
, i jeden, który udostępnia działania LUI), zależy od Twojej decyzji projektowej.
EuiccCardManager
EuiccCardManager
to interfejs do komunikacji z chipem eSIM. Zapewnia funkcje ES10 (zgodnie ze specyfikacją GSMA RSP) i obsługuje polecenia żądania/odpowiedzi APDU niskiego poziomu, a także analizowanie ASN.1.
EuiccCardManager
to interfejs API systemu, który może być wywoływany tylko przez aplikacje z uprawnieniami systemowymi.
Rysunek 2. Zarówno aplikacja operatora, jak i LPA korzystają z interfejsów Euicc API.
Interfejsy API operacji na profilu w EuiccCardManager
wymagają, aby wywołujący był LPA. Jest to egzekwowane przez platformę Androida. Oznacza to, że wywołujący musi rozszerzać EuiccService
i być zadeklarowany w pliku manifestu, jak opisano w poprzednich sekcjach.
Podobnie jak w przypadku interfejsu EuiccManager
, aby korzystać z interfejsów API EuiccCardManager
, Twój dostawca platformy musi najpierw uzyskać instancję EuiccCardManager
za pomocą interfejsu Context#getSystemService
:
EuiccCardManager cardMgr = (EuiccCardManager) context.getSystemService(Context.EUICC_CARD_SERVICE);
Aby pobrać wszystkie profile na karcie 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. Gdy używasz interfejsów EuiccCardManager
API, wywołujący (LPA) musi podać obiekt Executor
, za pomocą którego wywoływane jest wywołanie zwrotne. Ten obiekt Executor
może działać w jednym wątku lub w wybranej przez Ciebie puli wątków.
Większość interfejsów API EuiccCardManager
ma ten sam wzorzec użycia. Na przykład, aby wgrać pakiet profilu powiązanego na kartę eUICC:
...
cardMgr.loadBoundProfilePackage(eid, boundProfilePackage,
AsyncTask.THREAD_POOL_EXECUTOR, callback);
Aby przełączyć się na inny profil z danym numerem ICCID:
...
cardMgr.switchToProfile(eid, iccid, true /* refresh */,
AsyncTask.THREAD_POOL_EXECUTOR, callback);
Aby uzyskać domyślny adres SM-DP+ z karty eUICC:
...
cardMgr.requestDefaultSmdpAddress(eid, AsyncTask.THREAD_POOL_EXECUTOR,
callback);
Aby pobrać listę powiadomień o określonych zdarzeniach powiadomień:
...
cardMgr.listNotifications(eid,
EuiccNotification.Event.INSTALL
| EuiccNotification.Event.DELETE /* events */,
AsyncTask.THREAD_POOL_EXECUTOR, callback);
Aktywowanie profilu eSIM za pomocą aplikacji operatora
Na urządzeniach z Androidem 9 lub nowszym możesz użyć aplikacji operatora, aby aktywować kartę eSIM i pobrać profile. Aplikacja operatora może pobierać profile, wywołując bezpośrednio funkcję downloadSubscription
lub przekazując kod aktywacyjny do LPA.
Gdy aplikacja operatora pobiera profil, wywołując downloadSubscription
, połączenie wymusza, aby aplikacja mogła zarządzać profilem za pomocą BF76
tagu metadanych, który koduje reguły uprawnień operatora dla profilu. Jeśli profil nie ma tagu BF76
lub jeśli tag BF76
nie pasuje do podpisu aplikacji operatora połączeń, pobieranie zostanie odrzucone.
W sekcji poniżej opisujemy aktywowanie karty eSIM za pomocą aplikacji operatora przy użyciu kodu aktywacyjnego.
Aktywowanie karty eSIM za pomocą kodu aktywacyjnego
Gdy do aktywowania profilu eSIM używany jest kod aktywacyjny, LPA pobiera kod aktywacyjny z aplikacji operatora i pobiera profil. Ten proces może być inicjowany przez LPA, która może kontrolować cały interfejs użytkownika. Oznacza to, że nie jest wyświetlany interfejs aplikacji operatora. Takie podejście pomija sprawdzanie tagu BF76
, a operatorzy sieci nie muszą wdrażać całego procesu aktywacji karty eSIM, w tym pobierania profilu eSIM i obsługi błędów.
Określ usługę udostępniania eUICC operatora
Aplikacja LPA i aplikacja operatora komunikują się za pomocą 2 interfejsów AIDL: ICarrierEuiccProvisioningService
i IGetActivationCodeCallback
. Aplikacja operatora musi implementować interfejs ICarrierEuiccProvisioningService
i udostępniać go w deklaracji manifestu.
Usługa LPA musi być powiązana z ICarrierEuiccProvisioningService
i wdrożyć IGetActivationCodeCallback
. Więcej informacji o wdrażaniu i udostępnianiu interfejsu AIDL znajdziesz w artykule Definiowanie interfejsu AIDL.
Aby zdefiniować interfejsy AIDL, utwórz te pliki AIDL zarówno dla aplikacji LPA, jak i 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ć się z implementacją ICarrierEuiccProvisioningService
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 LPA wywołuje funkcję getActivationCode
lub getActivationCodeForEid
, aby pobrać kod aktywacyjny z aplikacji operatora, przekazując implementację klasy stub IGetActivationCodeCallback
.ICarrierEuiccProvisioningService
Różnica między getActivationCode
a getActivationCodeForEid
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 przewoźnika
Aby LPA mogła powiązać się z aplikacją operatora, musi ona skopiować do projektu zarówno plik ICarrierEuiccProvisioningService.aidl
, jak i IGetActivationCodeCallback.aidl
, a w pliku AndroidManifest.xml
zadeklarować usługę ICarrierEuiccProvisioningService
. Usługa musi wymagać uprawnień systemowych, aby mieć pewność, że tylko LPA, czyli aplikacja z uprawnieniami systemowymi, może się z nią powiązać.android.permission.WRITE_EMBEDDED_SUBSCRIPTIONS
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 wdrożyć usługę aplikacji operatora AIDL, utwórz usługę, rozszerz klasę Stub
i wdroż metody getActivationCode
i getActivationCodeForEid
. Następnie LPA może wywołać dowolną z tych metod, aby pobrać kod aktywacji profilu. Aplikacja operatora powinna odpowiedzieć, wywołując funkcję
IGetActivationCodeCallback#onSuccess
z kodem aktywacyjnym, jeśli kod został
pobrany z serwera operatora. Jeśli operacja się nie powiedzie, aplikacja przewoźnika powinna odpowiedzieć kodem 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); } } }
Uruchamianie interfejsu aplikacji operatora w procesie aktywacji LPA
Na urządzeniach z Androidem 11 lub nowszym LPA może uruchamiać interfejs aplikacji operatora. Jest to przydatne, ponieważ aplikacja operatora może wymagać od użytkownika dodatkowych informacji przed dostarczeniem kodu aktywacyjnego do LPA. Na przykład operatorzy mogą wymagać od użytkowników zalogowania się w celu aktywowania numerów telefonów lub wykonywania innych usług przenoszenia.
Oto proces uruchamiania interfejsu aplikacji operatora w LPA:
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. (Odbiornik aplikacji operatora musi być chroniony w deklaracji manifestu za pomocą elementuandroid:permission="android.permission.WRITE_EMBEDDED_SUBSCRIPTIONS"
, aby uniknąć otrzymywania intencji z aplikacji innych niż 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);
Aplikacja operatora wykonuje swoje zadania za pomocą własnego interfejsu. Może to być na przykład logowanie użytkownika lub wysyłanie żądań HTTP do backendu operatora.
Aplikacja operatora odpowiada na żądanie LPA, wywołując funkcje
setResult(int, Intent)
ifinish()
.- Jeśli aplikacja operatora odpowie
RESULT_OK
, LPA kontynuuje proces aktywacji. Jeśli aplikacja operatora uzna, że użytkownik powinien zeskanować kod QR zamiast zezwalać na powiązanie usługi aplikacji operatora z LPA, odpowiada na LPA za pomocąsetResult(int, Intent)
zRESULT_OK
i instancjąIntent
zawierającą dodatkowy parametr logicznyandroid.telephony.euicc.extra.USE_QR_SCANNER
ustawiony natrue
. Następnie LPA sprawdza dodatkowe informacje i uruchamia skaner kodów QR zamiast wiązać implementacjęICarrierEuiccProvisioningService
aplikacji operatora. - Jeśli aplikacja operatora ulegnie awarii lub odpowie kodem
RESULT_CANCELED
(jest to domyślny kod odpowiedzi), LPA anuluje proces aktywacji karty eSIM. - Jeśli aplikacja operatora odpowie czymś innym niż
RESULT_OK
lubRESULT_CANCELED
, LPA potraktuje to jako błąd.
Ze względów bezpieczeństwa LPA nie powinna bezpośrednio akceptować kodu aktywacyjnego podanego w intencji wyniku, aby podmioty wywołujące inne niż LPA nie mogły uzyskać kodu aktywacyjnego z aplikacji operatora.
- Jeśli aplikacja operatora odpowie
Uruchamianie procesu aktywacji LPA w aplikacji operatora
Od Androida 11 aplikacje operatorów mogą używać interfejsów eUICC API do uruchamiania interfejsu użytkownika lokalnego w celu aktywacji karty eSIM. Ta metoda wyświetla interfejs przepływu aktywacji eSIM LPA, aby aktywować profil eSIM. Następnie LPA wysyła transmisję po zakończeniu aktywacji profilu eSIM.
Aplikacja LPA musi deklarować aktywność, w tym filtr intencji z działaniem
android.service.euicc.action.START_EUICC_ACTIVATION
. Priorytet filtra intencji powinien być ustawiony na wartość różną od zera, jeśli na urządzeniu jest dostępnych 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>
Aplikacja operatora wykonuje swoje zadania za pomocą własnego interfejsu. Może to być na przykład logowanie użytkownika lub wysyłanie żądań HTTP do backendu operatora.
W tym momencie aplikacja operatora musi być gotowa do dostarczenia kodu aktywacyjnego za pomocą implementacji
ICarrierEuiccProvisioningService
. Aplikacja operatora uruchamia LPA, wywołującstartActivityForResult(Intent, int)
z działaniemandroid.telephony.euicc.action.START_EUICC_ACTIVATION
. Usługa LPA sprawdza też dodatkowy atrybut logicznyandroid.telephony.euicc.extra.USE_QR_SCANNER
. Jeśli wartość totrue
, LPA uruchamia skaner kodów QR, aby umożliwić użytkownikowi zeskanowanie kodu QR profilu.Po stronie LPA LPA wiąże się z implementacją aplikacji operatora, aby pobrać kod aktywacyjny i pobrać odpowiedni profil.
ICarrierEuiccProvisioningService
Podczas pobierania LPA wyświetla wszystkie niezbędne elementy interfejsu, takie jak ekran ładowania.Po zakończeniu procesu aktywacji LPA odpowiada aplikacji operatora kodem wyniku, który jest obsługiwany przez aplikację operatora w
onActivityResult(int, int, Intent)
.- Jeśli LPA uda się pobrać nowy profil eSIM, odpowie kodem
RESULT_OK
. - Jeśli użytkownik anuluje aktywację profilu eSIM w aplikacji LPA, odpowie ona kodem
RESULT_CANCELED
. - Jeśli LPA odpowie czymś innym niż
RESULT_OK
lubRESULT_CANCELED
, aplikacja operatora potraktuje to jako błąd.
Ze względów bezpieczeństwa LPA nie akceptuje kodu aktywacyjnego bezpośrednio w dostarczonym zamiarze, aby osoby wywołujące spoza LPA nie mogły uzyskać kodu aktywacyjnego z aplikacji operatora.
- Jeśli LPA uda się pobrać nowy profil eSIM, odpowie kodem
Obsługa wielu kart eSIM
W przypadku urządzeń z Androidem 10 lub nowszym klasa
EuiccManager
obsługuje urządzenia
z kilkoma kartami eSIM. Urządzenia z jedną kartą eSIM, które są aktualizowane do Androida 10, nie wymagają żadnych modyfikacji implementacji LPA, ponieważ platforma automatycznie kojarzy instancję EuiccManager
z domyślną kartą eUICC. Domyślna karta eUICC jest określana przez platformę w przypadku urządzeń z wersją HAL radia 1.2 lub nowszą oraz przez LPA w przypadku urządzeń z wersją HAL radia starszą niż 1.2.
Wymagania
Aby obsługiwać wiele kart eSIM, urządzenie musi mieć więcej niż 1 moduł eUICC, który może być wbudowany lub mieć postać gniazda na fizyczną kartę SIM, do którego można wkładać wymienne moduły eUICC.
Aby obsługiwać wiele kart eSIM, wymagana jest wersja 1.2 lub nowsza interfejsu HAL radia. Zalecane są wersje 1.4 interfejsu HAL radia i 1.2 interfejsu HAL RadioConfig.
Implementacja
Aby obsługiwać wiele kart eSIM (w tym wymienne karty eUICC lub programowalne karty SIM), aplikacja LPA musi implementować interfejs EuiccService
, który odbiera identyfikator gniazda odpowiadający identyfikatorowi karty podanemu przez dzwoniącego.
Zasób non_removable_euicc_slots
określony w arrays.xml
to tablica liczb całkowitych, które reprezentują identyfikatory gniazd wbudowanych kart eUICC urządzenia. Musisz określić ten zasób, aby platforma mogła określić, czy włożona karta eUICC jest wyjmowalna.
Aplikacja operatora na urządzenie z wieloma kartami eSIM
Podczas tworzenia aplikacji operatora dla urządzenia z wieloma kartami eSIM użyj metody
createForCardId
w EuiccManager
, 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 modułu eUICC urządzenia, użyj metody
getCardIdForDefaultEuicc
w TelephonyManager
. Ta metoda zwraca wartość
UNSUPPORTED_CARD_ID
jeśli wersja HAL radia jest niższa niż 1.2, a wartość
UNINITIALIZED_CARD_ID
jeśli urządzenie nie odczytało karty eUICC.
Identyfikatory kart możesz też uzyskać z getUiccCardsInfo
i getUiccSlotsInfo
(interfejs API systemu) w TelephonyManager
oraz
getCardId
w SubscriptionInfo
.
Gdy obiekt EuiccManager
zostanie utworzony z określonym identyfikatorem karty, wszystkie operacje będą kierowane do karty eUICC z tym identyfikatorem. Jeśli karta eUICC stanie się niedostępna (np. zostanie wyłączona lub usunięta), EuiccManager
przestanie działać.
Do utworzenia aplikacji przewoźnika możesz użyć tych przykładowych kodów.
Przykład 1. Uzyskiwanie 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. Iteracja po kartach UICC i tworzenie instancji EuiccManager
dla wymiennej karty 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 oczekuje się, że LPA będzie dostępny we wszystkich kompilacjach Androida (nie każdy telefon obsługuje kartę eSIM). Z tego powodu nie ma kompleksowych przypadków testowych CTS. Jednak w AOSP dostępne są podstawowe przypadki testowe, które zapewniają, że ujawnione interfejsy API eUICC są prawidłowe w kompilacjach 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ść normalne wewnętrzne cykle zapewniania jakości, aby mieć pewność, że wszystkie wdrożone funkcje działają zgodnie z oczekiwaniami. Aplikacja operatora powinna co najmniej umożliwiać wyświetlanie wszystkich profili subskrypcji należących do tego samego operatora, pobieranie i instalowanie profilu, aktywowanie usługi w profilu, przełączanie się między profilami i usuwanie profili.
Jeśli tworzysz własną umowę LPA, musisz przeprowadzić znacznie bardziej rygorystyczne testy. Aby rozwiązać problemy i zapewnić interoperacyjność aplikacji LPA w architekturze RSP, współpracuj z dostawcą modemu, układu eUICC lub systemu operacyjnego eSIM, dostawcami SM-DP+ i operatorami. Duża liczba testów ręcznych jest nieunikniona. Aby uzyskać jak najlepsze pokrycie testowe, postępuj zgodnie z planem testów GSMA SGP.23 RSP.