טכנולוגיית SIM משובצת (eSIM, או eUICC) מאפשרת למשתמשים ניידים להוריד פרופיל ספק ולהפעיל שירות של ספק ללא כרטיס SIM פיזי. זהו מפרט עולמי המונע על ידי ה-GSMA המאפשר אספקת SIM מרחוק (RSP) של כל מכשיר נייד. החל מ-Android 9, מסגרת Android מספקת ממשקי API סטנדרטיים לגישה ל-eSIM ולניהול פרופילי מנויים ב-eSIM. ממשקי API אלה של eUICC מאפשרים לצדדים שלישיים לפתח אפליקציות ספק משלהם ועוזרי פרופיל מקומיים (LPA) במכשירי אנדרואיד התומכים ב-eSIM.
ה-LPA הוא אפליקציית מערכת עצמאית שאמורה להיכלל בתמונת ה-build של אנדרואיד. ניהול הפרופילים ב-eSIM נעשה בדרך כלל על ידי ה-LPA, שכן הוא משמש כגשר בין ה-SM-DP+ (שירות מרוחק שמכין, מאחסן ומעביר חבילות פרופיל למכשירים) לבין שבב eUICC. ה-APK של LPA יכול לכלול אופציונלי רכיב UI, הנקרא LPA UI או LUI, כדי לספק מקום מרכזי למשתמש הקצה לניהול כל פרופילי המנויים המוטבעים. מסגרת האנדרואיד מגלה ומתחברת אוטומטית ל-LPA הזמין הטוב ביותר, ומנתבת את כל פעולות ה-eUICC דרך מופע LPA.
איור 1. ארכיטקטורת RSP פשוטה
מפעילי רשתות סלולריות המעוניינים ליצור אפליקציית ספק צריכים להסתכל על ממשקי ה-API ב- EuiccManager
, המספקים פעולות ניהול פרופיל ברמה גבוהה כגון downloadSubscription()
, switchToSubscription()
ו- deleteSubscription()
.
אם אתה יצרן OEM של מכשיר המעוניין ליצור אפליקציית מערכת LPA משלך, עליך להרחיב EuiccService
למסגרת Android כדי להתחבר לשירותי LPA שלך. בנוסף, עליך להשתמש בממשקי ה-API ב- EuiccCardManager
, המספקים פונקציות ES10x המבוססות על GSMA RSP v2.0. פונקציות אלו משמשות להנפקת פקודות לשבב eUICC, כגון prepareDownload()
, loadBoundProfilePackage()
, retrieveNotificationList()
ו- resetMemory()
.
ממשקי ה-API ב- EuiccManager
דורשים אפליקציית LPA המיושמת כהלכה כדי לתפקד והקורא של ממשקי ה-API EuiccCardManager
חייב להיות LPA. זה נאכף על ידי מסגרת אנדרואיד.
מכשירים עם אנדרואיד 10 ומעלה יכולים לתמוך במכשירים עם מספר eSIMs. למידע נוסף, ראה תמיכה במספר eSIMs .
יצירת אפליקציית ספק
ממשקי ה-API של eUICC באנדרואיד 9 מאפשרים למפעילי רשתות סלולריות ליצור אפליקציות ממותגות על מנת לנהל את הפרופילים שלהם ישירות. זה כולל הורדה ומחיקה של פרופילי מנוי שבבעלות הספק, כמו גם מעבר לפרופיל שבבעלות ספק.
EuiccManager
EuiccManager
הוא נקודת הכניסה העיקרית לאפליקציות לאינטראקציה עם ה-LPA. זה כולל אפליקציות של ספק שמורידות, מוחקות ועוברות למינויים שבבעלות הספק. זה כולל גם את אפליקציית מערכת LUI, המספקת מיקום/ממשק משתמש מרכזי לניהול כל המנויים המשובצים, ויכולה להיות אפליקציה נפרדת מזו שמספקת את EuiccService
.
כדי להשתמש בממשקי ה-API הציבוריים, אפליקציית ספק חייבת להשיג תחילה את המופע של EuiccManager
דרך Context#getSystemService
:
EuiccManager mgr = (EuiccManager) context.getSystemService(Context.EUICC_SERVICE);
עליך לבדוק אם eSIM נתמך במכשיר לפני ביצוע פעולות eSIM כלשהן. EuiccManager#isEnabled()
בדרך כלל מחזירה true
אם תכונת android.hardware.telephony.euicc
מוגדרת וקיימת חבילת LPA.
if (mgr == null || !mgr.isEnabled()) {
return;
}
כדי לקבל מידע על חומרת eUICC וגרסת מערכת ההפעלה eSIM:
EuiccInfo info = mgr.getEuiccInfo();
String osVer = info.getOsVersion();
ממשקי API רבים, כגון downloadSubscription()
ו- switchToSubscription()
, משתמשים בהתקשרות חוזרת PendingIntent
מכיוון שהשלמה עשויה להימשך שניות או אפילו דקות. PendingIntent
נשלח עם קוד תוצאה במרחב EuiccManager#EMBEDDED_SUBSCRIPTION_RESULT_
, המספק קודי שגיאה המוגדרים במסגרת, כמו גם קוד תוצאה מפורט שרירותי המופץ מה-LPA כ- EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE
, המאפשר לעקוב אחר יישום רישום/המטרה של הספק. ההתקשרות חזרה PendingIntent
חייבת להיות BroadcastReceiver
.
כדי להוריד מנוי נתון שניתן להורדה (נוצר מקוד הפעלה או מקוד QR):
// Register receiver.
static final String ACTION_DOWNLOAD_SUBSCRIPTION = "download_subscription";
static final String LPA_DECLARED_PERMISSION
= "com.your.company.lpa.permission.BROADCAST";
BroadcastReceiver receiver =
new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (!action.equals(intent.getAction())) {
return;
}
resultCode = getResultCode();
detailedCode = intent.getIntExtra(
EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE,
0 /* defaultValue*/);
// If the result code is a resolvable error, call startResolutionActivity
if (resultCode == EuiccManager.EMBEDDED_SUBSCRIPTION_RESULT_RESOLVABLE_ERROR) {
PendingIntent callbackIntent = PendingIntent.getBroadcast(
getContext(), 0 /* requestCode */, intent,
PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE);
mgr.startResolutionActivity(
activity,
0 /* requestCode */,
intent,
callbackIntent);
}
resultIntent = intent;
}
};
context.registerReceiver(receiver,
new IntentFilter(ACTION_DOWNLOAD_SUBSCRIPTION),
LPA_DECLARED_PERMISSION /* broadcastPermission*/,
null /* handler */);
// Download subscription asynchronously.
DownloadableSubscription sub = DownloadableSubscription
.forActivationCode(code /* encodedActivationCode*/);
Intent intent = new Intent(action).setPackage(context.getPackageName());
PendingIntent callbackIntent = PendingIntent.getBroadcast(
getContext(), 0 /* requestCode */, intent,
PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE);
mgr.downloadSubscription(sub, true /* switchAfterDownload */,
callbackIntent);
הגדר והשתמש בהרשאה ב- AndroidManifest.xml
:
<permission android:protectionLevel="signature" android:name="com.your.company.lpa.permission.BROADCAST" />
<uses-permission android:name="com.your.company.lpa.permission.BROADCAST"/>
כדי לעבור למנוי בהינתן מזהה המנוי:
// 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);
לרשימה מלאה של ממשקי API EuiccManager
ודוגמאות קוד, ראה ממשקי API של eUICC .
שגיאות ניתנות לפתרון
ישנם מקרים שבהם המערכת אינה מסוגלת להשלים את פעולת ה-eSIM אך המשתמש יכול לפתור את השגיאה. לדוגמה, downloadSubscription
עלולה להיכשל אם המטא נתונים של הפרופיל מציינים שנדרש קוד אישור ספק . לחלופין, switchToSubscription
עשוי להיכשל אם לאפליקציית הספק יש הרשאות ספק על פרופיל היעד (כלומר, הספק הוא הבעלים של הפרופיל) אך אין לה הרשאות ספק על הפרופיל המופעל כעת, ולכן נדרשת הסכמת המשתמש.
במקרים אלה, ההתקשרות חזרה של המתקשר נקראת באמצעות EuiccManager#EMBEDDED_SUBSCRIPTION_RESULT_RESOLVABLE_ERROR
. Intent
להתקשרות חוזרת מכילה תוספות פנימיות כך שכאשר המתקשר מעביר אותה ל- EuiccManager#startResolutionActivity
, ניתן לבקש פתרון דרך ה-LUI. באמצעות קוד האישור למשל שוב, EuiccManager#startResolutionActivity
מפעיל מסך LUI המאפשר למשתמש להזין קוד אישור; לאחר הזנת הקוד, פעולת ההורדה מחודשת. גישה זו מספקת לאפליקציית הספק שליטה מלאה על מועד הצגת ממשק המשתמש, אך מעניקה ל-LPA/LUI שיטה הניתנת להרחבה להוספת טיפול חדש בבעיות הניתנות לשחזור על ידי משתמשים בעתיד ללא צורך בשינוי אפליקציות לקוח.
אנדרואיד 9 מגדיר את השגיאות הניתנות לפתרון ב- EuiccService
, שה-LUI צריך לטפל בהן:
/**
* Alert the user that this action will result in an active SIM being
* deactivated. To implement the LUI triggered by the system, you need to define
* this in AndroidManifest.xml.
*/
public static final String ACTION_RESOLVE_DEACTIVATE_SIM =
"android.service.euicc.action.RESOLVE_DEACTIVATE_SIM";
/**
* Alert the user about a download/switch being done for an app that doesn't
* currently have carrier privileges.
*/
public static final String ACTION_RESOLVE_NO_PRIVILEGES =
"android.service.euicc.action.RESOLVE_NO_PRIVILEGES";
/** Ask the user to resolve all the resolvable errors. */
public static final String ACTION_RESOLVE_RESOLVABLE_ERRORS =
"android.service.euicc.action.RESOLVE_RESOLVABLE_ERRORS";
הרשאות ספק
אם אתה ספק שמפתח אפליקציית ספק משלך שקוראת ל- EuiccManager
כדי להוריד פרופילים למכשיר, הפרופיל שלך צריך לכלול כללי הרשאות ספק התואמים לאפליקציית הספק שלך במטא נתונים. הסיבה לכך היא שפרופילי מנוי השייכים לספקים שונים יכולים להתקיים במקביל ב-eUICC של מכשיר, ויש לאפשר לכל אפליקציית ספק לגשת רק לפרופילים שבבעלות אותו ספק. לדוגמה, ספק א' לא אמור להיות מסוגל להוריד, להפעיל או להשבית פרופיל שבבעלות ספק ב'.
כדי להבטיח שפרופיל נגיש רק לבעליו, אנדרואיד משתמשת במנגנון להענקת הרשאות מיוחדות לאפליקציה של בעל הפרופיל (כלומר, אפליקציית הספק). פלטפורמת אנדרואיד טוענת אישורים המאוחסנים בקובץ כללי הגישה של הפרופיל (ARF) ומעניקה הרשאה לאפליקציות החתומות על ידי אישורים אלו לבצע קריאות לממשקי ה-API EuiccManager
. התהליך ברמה גבוהה מתואר להלן:
- המפעיל חותם על ה-APK של אפליקציית הספק; הכלי apksigner מצרף את אישור המפתח הציבורי ל-APK.
Operator/SM-DP+ מכין פרופיל והמטא נתונים שלו, הכוללים ARF שמכיל:
- חתימה (SHA-1 או SHA-256) של אישור המפתח הציבורי של אפליקציית הספק (חובה)
- שם החבילה של אפליקציית הספק (מומלץ בחום)
אפליקציית הספק מנסה לבצע פעולת eUICC באמצעות
EuiccManager
API.פלטפורמת אנדרואיד מאמתת ש-SHA-1 או SHA-256 hash של האישור של האפליקציה המתקשרת תואמת את החתימה של האישור המתקבל מה-ARF של פרופיל היעד. אם שם החבילה של אפליקציית הספק כלול ב-ARF, עליו להתאים גם לשם החבילה של האפליקציה המתקשרת.
לאחר אימות החתימה ושם החבילה (אם כלול), הרשאת הספק מוענקת לאפליקציית המתקשר על פני פרופיל היעד.
מכיוון שמטא נתונים של פרופיל יכולים להיות זמינים מחוץ לפרופיל עצמו (כדי ש-LPA יוכל לאחזר את המטא נתונים של הפרופיל מ-SM-DP+ לפני הורדת הפרופיל, או מ-ISD-R כאשר הפרופיל מושבת), הם צריכים להכיל את אותם כללי הרשאות ספק כמו בפרופיל.
מערכת ההפעלה eUICC ו-SM-DP+ חייבים לתמוך בתג קנייני BF76
במטא נתונים של הפרופיל. תוכן התג צריך להיות אותם כללי הרשאות ספק כפי שהוחזרו על ידי יישומון כלל הגישה (ARA) המוגדר ב- 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
}
}
לפרטים נוספים על חתימת אפליקציה, ראה חתימה על האפליקציה שלך . לפרטים על הרשאות ספק, ראה הרשאות ספק של UICC .
יצירת אפליקציית עוזר פרופיל מקומי
יצרני מכשירים יכולים ליישם את עוזר הפרופיל המקומי שלהם (LPA), אשר חייב להיות מחובר לממשקי ה-API של Android Euicc. הסעיפים הבאים מספקים סקירה קצרה של יצירת אפליקציית LPA ושילובה עם מערכת אנדרואיד.
דרישות חומרה/מודם
ה-LPA ומערכת ההפעלה eSIM בשבב eUICC חייבים לתמוך לפחות ב-GSMA RSP (Remote SIM Provisioning) v2.0 או v2.2. כדאי גם לתכנן להשתמש בשרתי SM-DP+ ו-SM-DS בעלי גרסת RSP תואמת. לארכיטקטורת RSP מפורטת, ראה מפרט ארכיטקטורת RSP GSMA SGP.21 .
בנוסף, כדי להשתלב עם ממשקי API של eUICC באנדרואיד 9, מודם המכשיר צריך לשלוח יכולות מסוף עם תמיכה ביכולות eUICC מקודדות (ניהול פרופיל מקומי והורדת פרופיל). זה גם צריך ליישם את השיטות הבאות:
- IRadio HAL v1.1:
setSimPower
IRadio HAL v1.2:
getIccCardStatus
IRadioConfig HAL v1.0:
getSimSlotsStatus
IRadioConfig AIDL v1.0:
getAllowedCarriers
ה-LPA של Google צריך לדעת את סטטוס נעילת הספק כדי שיוכל לאפשר הורדה או העברה של eSIM רק עבור הספק המותר. אחרת המשתמשים עלולים בסופו של דבר להוריד ולהעביר SIM ומאוחר יותר להבין שהמכשיר נעול ספק לספק אחר.
ספקים או יצרני OEM חייבים ליישם את IRadioSim.getAllowedCarriers()HAL API.
הספק RIL / Modem יאכלס את סטטוס הנעילה ואת ה-carrierId של הספק אליו נעול המכשיר כחלק מ-IRadioSimResponse.getAllowedCarriersResponse()HAL API.
המודם צריך לזהות את ה-eSIM עם פרופיל האתחול המופעל כברירת מחדל כ-SIM חוקי ולהשאיר את ה-SIM מופעל.
עבור מכשירים עם Android 10, יש להגדיר מערך מזהה חריץ eUICC שאינו ניתן להסרה. לדוגמה, ראה arrays.xml
.
<resources>
<!-- Device-specific array of SIM slot indexes which are are embedded eUICCs.
e.g. If a device has two physical slots with indexes 0, 1, and slot 1 is an
eUICC, then the value of this array should be:
<integer-array name="non_removable_euicc_slots">
<item>1</item>
</integer-array>
If a device has three physical slots and slot 1 and 2 are eUICCs, then the value of
this array should be:
<integer-array name="non_removable_euicc_slots">
<item>1</item>
<item>2</item>
</integer-array>
This is used to differentiate between removable eUICCs and built in eUICCs, and should
be set by OEMs for devices which use eUICCs. -->
<integer-array name="non_removable_euicc_slots">
<item>1</item>
</integer-array>
</resources>
לרשימה מלאה של דרישות מודם, ראה דרישות מודם לתמיכה ב-eSIM .
EuiccService
LPA מורכב משני רכיבים נפרדים (ניתן ליישם את שניהם באותו APK): ה-LPA הקצה האחורי וממשק המשתמש או ה-LUI של LPA.
כדי ליישם את ה-LPA backend, עליך להרחיב EuiccService
ולהכריז על שירות זה בקובץ המניפסט שלך. השירות חייב לדרוש את הרשאת המערכת android.permission.BIND_EUICC_SERVICE
כדי להבטיח שרק המערכת יכולה להתחבר אליו. השירות חייב לכלול גם מסנן כוונות עם הפעולה android.service.euicc.EuiccService
. יש להגדיר את העדיפות של מסנן הכוונות לערך שאינו אפס במקרה שקיימים יישומים מרובים במכשיר. לדוגמה:
<service
android:name=".EuiccServiceImpl"
android:permission="android.permission.BIND_EUICC_SERVICE">
<intent-filter android:priority="100">
<action android:name="android.service.euicc.EuiccService" />
</intent-filter>
</service>
פנימית, המסגרת של אנדרואיד קובעת את ה-LPA הפעיל ומקיימת אינטראקציה איתה לפי הצורך כדי לתמוך בממשקי ה-API של Android eUICC. השאילתה PackageManager
מתבצעת עבור כל האפליקציות עם הרשאת android.permission.WRITE_EMBEDDED_SUBSCRIPTIONS
, המציינת שירות עבור הפעולה android.service.euicc.EuiccService
. נבחר השירות בעל העדיפות הגבוהה ביותר. אם לא נמצא שירות, תמיכת LPA מושבתת.
כדי ליישם את ה- LUI, עליך לספק פעילות עבור הפעולות הבאות:
-
android.service.euicc.action.MANAGE_EMBEDDED_SUBSCRIPTIONS
-
android.service.euicc.action.PROVISION_EMBEDDED_SUBSCRIPTION
כמו בשירות, כל פעילות חייבת לדרוש את הרשאת המערכת android.permission.BIND_EUICC_SERVICE
. לכל אחד צריך להיות מסנן כוונות עם הפעולה המתאימה, קטגוריית android.service.euicc.category.EUICC_UI
ועדיפות שאינה אפס. לוגיקה דומה משמשת לבחירת ההטמעות לפעילויות אלו כמו בבחירת היישום של EuiccService
. לדוגמה:
<activity android:name=".MyLuiActivity"
android:exported="true"
android:permission="android.permission.BIND_EUICC_SERVICE">
<intent-filter android:priority="100">
<action android:name="android.service.euicc.action.MANAGE_EMBEDDED_SUBSCRIPTIONS" />
<action android:name="android.service.euicc.action.PROVISION_EMBEDDED_SUBSCRIPTION" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.service.euicc.category.EUICC_UI" />
</intent-filter>
</activity>
זה מרמז שממשק המשתמש המיישם את המסכים הללו יכול להגיע מ-APK שונה מזה שמיישם EuiccService
. אם יש APK יחיד או APKs מרובים (לדוגמה, אחד שמטמיע EuiccService
ואחד שמספק פעילויות LUI) היא בחירה עיצובית.
EuiccCardManager
EuiccCardManager
הוא הממשק לתקשורת עם שבב ה-eSIM. הוא מספק פונקציות ES10 (כמתואר במפרט GSMA RSP) ומטפל בפקודות הבקשה/תגובה של APDU ברמה נמוכה וכן בניתוח ASN.1. EuiccCardManager
הוא ממשק API של מערכת וניתן לקרוא אותו רק על ידי אפליקציות מורשות מערכת.
איור 2. גם אפליקציית הספק וגם LPA משתמשים בממשקי API של Euicc
ממשקי API של תפעול הפרופיל באמצעות EuiccCardManager
דורשים שהמתקשר יהיה LPA. זה נאכף על ידי מסגרת אנדרואיד. המשמעות היא שהמתקשר חייב להרחיב EuiccService
ולהכריז עליו בקובץ המניפסט שלך, כמתואר בסעיפים הקודמים.
בדומה ל- EuiccManager
, כדי להשתמש בממשקי ה-API EuiccCardManager
, על ה-LPA שלך להשיג תחילה את המופע של EuiccCardManager
דרך Context#getSystemService
:
EuiccCardManager cardMgr = (EuiccCardManager) context.getSystemService(Context.EUICC_CARD_SERVICE);
לאחר מכן, כדי לקבל את כל הפרופילים ב-eUICC:
ResultCallback<EuiccProfileInfo[]> callback =
new ResultCallback<EuiccProfileInfo[]>() {
@Override
public void onComplete(int resultCode,
EuiccProfileInfo[] result) {
if (resultCode == EuiccCardManagerReflector.RESULT_OK) {
// handle result
} else {
// handle error
}
}
};
cardMgr.requestAllProfiles(eid, AsyncTask.THREAD_POOL_EXECUTOR, callback);
באופן פנימי, EuiccCardManager
נקשר ל- EuiccCardController
(שפועל בתהליך הטלפון) דרך ממשק AIDL, וכל שיטה של EuiccCardManager
מקבלת התקשרות חוזרת מתהליך הטלפון באמצעות ממשק AIDL אחר, ייעודי. בעת שימוש בממשקי ה-API EuiccCardManager
, המתקשר (LPA) חייב לספק אובייקט Executor
שדרכו מופעל השיחה חזרה. אובייקט Executor
זה עשוי לפעול על שרשור בודד או על מאגר אשכולות לפי בחירתך.
לרוב ממשקי ה-API EuiccCardManager
יש את אותו דפוס שימוש. לדוגמה, כדי לטעון חבילת פרופיל מאוגד על ה-eUICC:
...
cardMgr.loadBoundProfilePackage(eid, boundProfilePackage,
AsyncTask.THREAD_POOL_EXECUTOR, callback);
כדי לעבור לפרופיל אחר עם ICCID נתון:
...
cardMgr.switchToProfile(eid, iccid, true /* refresh */,
AsyncTask.THREAD_POOL_EXECUTOR, callback);
כדי לקבל את כתובת ברירת המחדל של SM-DP+ מהשבב eUICC:
...
cardMgr.requestDefaultSmdpAddress(eid, AsyncTask.THREAD_POOL_EXECUTOR,
callback);
כדי לאחזר רשימה של התראות על אירועי ההתראה שניתנו:
...
cardMgr.listNotifications(eid,
EuiccNotification.Event.INSTALL
| EuiccNotification.Event.DELETE /* events */,
AsyncTask.THREAD_POOL_EXECUTOR, callback);
הפעלת פרופיל eSIM באמצעות אפליקציית ספק
במכשירים שבהם פועל אנדרואיד 9 ומעלה, אתה יכול להשתמש באפליקציית ספק כדי להפעיל את ה-eSIM ולהוריד פרופילים. אפליקציית הספק יכולה להוריד פרופילים על ידי התקשרות ישירה ל- downloadSubscription
או על ידי מתן קוד הפעלה ל-LPA.
כאשר אפליקציית ספק מורידה פרופיל על ידי קריאה downloadSubscription
, השיחה אוכפת שהאפליקציה יכולה לנהל את הפרופיל באמצעות תג מטא-נתונים BF76
המקודד כללי הרשאות ספק עבור הפרופיל. אם לפרופיל אין תג BF76
או אם תג BF76
שלו אינו תואם את החתימה של אפליקציית הספק המתקשר, ההורדה נדחית.
הסעיף שלהלן מתאר הפעלת eSIM דרך אפליקציית ספק באמצעות קוד הפעלה.
הפעלת eSIM באמצעות קוד הפעלה
בעת שימוש בקוד הפעלה להפעלת פרופיל eSIM, ה-LPA שואב קוד הפעלה מאפליקציית הספק ומוריד את הפרופיל. זרימה זו יכולה להיות יזומה על ידי ה-LPA וה-LPA יכול לשלוט בכל זרימת המשתמש, כלומר לא מוצג ממשק משתמש של אפליקציית הספק. גישה זו עוקפת את בדיקת התגים BF76
, ומפעילי רשת אינם צריכים ליישם את כל זרימת ממשק המשתמש של eSIM, כולל הורדת פרופיל eSIM וטיפול בשגיאות.
הגדרת שירות האספקה של הספק eUICC
האפליקציה LPA והספק מתקשרים באמצעות שני ממשקי AIDL : ICarrierEuiccProvisioningService
ו- IGetActivationCodeCallback
. אפליקציית הספק חייבת ליישם ממשק ICarrierEuiccProvisioningService
ולחשוף אותו בהצהרת המניפסט שלה. ה-LPA חייב להיקשר ל- ICarrierEuiccProvisioningService
וליישם IGetActivationCodeCallback
. למידע נוסף על איך ליישם ולחשוף ממשק AIDL, ראה הגדרה וממשק AIDL .
כדי להגדיר את ממשקי ה-AIDL, צור את קובצי ה-AIDL הבאים עבור אפליקציות ה-LPA והן עבור אפליקציות הספק.
ICarrierEuiccProvisioningService.aidl
package android.service.euicc; import android.service.euicc.IGetActivationCodeCallback; oneway interface ICarrierEuiccProvisioningService { // The method to get the activation code from the carrier app. The caller needs to pass in // the implementation of IGetActivationCodeCallback as the parameter. void getActivationCode(in IGetActivationCodeCallback callback); // The method to get the activation code from the carrier app. The caller needs to pass in // the activation code string as the first parameter and the implementation of // IGetActivationCodeCallback as the second parameter. This method provides the carrier // app the device EID which allows a carrier to pre-bind a profile to the device's EID before // the download process begins. void getActivationCodeForEid(in String eid, in IGetActivationCodeCallback callback); }
IGetActivationCodeCallback.aidl
package android.service.euicc; oneway interface IGetActivationCodeCallback { // The call back method needs to be called when the carrier app gets the activation // code successfully. The caller needs to pass in the activation code string as the // parameter. void onSuccess(String activationCode); // The call back method needs to be called when the carrier app failed to get the // activation code. void onFailure(); }
דוגמה ליישום LPA
כדי להיקשר למימוש ICarrierEuiccProvisioningService
של אפליקציית הספק, ה-LPA חייב להעתיק הן ICarrierEuiccProvisioningService.aidl
והן IGetActivationCodeCallback.aidl
לפרויקט שלך ולהטמיע את ServiceConnection
.
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
mCarrierProvisioningService = ICarrierEuiccProvisioningService.Stub.asInterface(iBinder);
}
לאחר הכריכה ליישום ICarrierEuiccProvisioningService
של אפליקציית הספק, ה-LPA קורא ל- getActivationCode
או getActivationCodeForEid
כדי לקבל את קוד ההפעלה מאפליקציית הספק על-ידי העברת היישום של מחלקת הסטאב של IGetActivationCodeCallback
.
ההבדל בין getActivationCode
ל- getActivationCodeForEid
הוא ש- getActivationCodeForEid
מאפשר לספק לקשור מראש פרופיל ל-EID של המכשיר לפני תחילת תהליך ההורדה.
void getActivationCodeFromCarrierApp() {
IGetActivationCodeCallback.Stub callback =
new IGetActivationCodeCallback.Stub() {
@Override
public void onSuccess(String activationCode) throws RemoteException {
// Handle the case LPA success to get activation code from a carrier app.
}
@Override
public void onFailure() throws RemoteException {
// Handle the case LPA failed to get activation code from a carrier app.
}
};
try {
mCarrierProvisioningService.getActivationCode(callback);
} catch (RemoteException e) {
// Handle Remote Exception
}
}
דוגמה ליישום עבור אפליקציית הספק
כדי שה-LPA ייקשר לאפליקציית הספק, אפליקציית הספק חייבת להעתיק הן ICarrierEuiccProvisioningService.aidl
והן IGetActivationCodeCallback.aidl
לפרויקט שלך ולהכריז על שירות ICarrierEuiccProvisioningService
בקובץ AndroidManifest.xml
. השירות חייב לדרוש את הרשאת המערכת android.permission.WRITE_EMBEDDED_SUBSCRIPTIONS
כדי להבטיח שרק ה-LPA, אפליקציה מוסמכת למערכת, יכולה להיקשר אליו. השירות חייב לכלול גם מסנן כוונות עם הפעולה android.service.euicc.action.BIND_CARRIER_PROVISIONING_SERVICE
.
AndroidManifest.xml
<application> ... <service android:name=".CarrierEuiccProvisioningService" android:exported="true" android:permission="android.permission.WRITE_EMBEDDED_SUBSCRIPTIONS"> <intent-filter> <action android:name="android.service.euicc.action.BIND_CARRIER_PROVISIONING_SERVICE"/> </intent-filter> </service> ... </application>
כדי ליישם את שירות אפליקציית הספק AIDL, צור שירות, הרחב את מחלקה Stub
והטמיע את השיטות getActivationCode
ו- getActivationCodeForEid
. לאחר מכן, ה-LPA יכול לקרוא לכל אחת מהשיטות כדי להביא את קוד הפעלת הפרופיל. אפליקציית הספק צריכה להגיב על ידי קריאה ל- IGetActivationCodeCallback#onSuccess
עם קוד ההפעלה אם הקוד הובא מהשרת של הספק בהצלחה. אם לא מצליח, אפליקציית הספק אמורה להגיב עם IGetActivationCodeCallback#onFailure
.
CarrierEuiccProvisioningService.java
import android.service.euicc.ICarrierEuiccProvisioningService; import android.service.euicc.ICarrierEuiccProvisioningService.Stub; import android.service.euicc.IGetActivationCodeCallback; public class CarrierEuiccProvisioningService extends Service { private final ICarrierEuiccProvisioningService.Stub binder = new Stub() { @Override public void getActivationCode(IGetActivationCodeCallback callback) throws RemoteException { String activationCode = // do whatever work necessary to get an activation code (HTTP requests to carrier server, fetch from storage, etc.) callback.onSuccess(activationCode); } @Override public void getActivationCodeForEid(String eid, IGetActivationCodeCallback callback) throws RemoteException { String activationCode = // do whatever work necessary (HTTP requests, fetch from storage, etc.) callback.onSuccess(activationCode); } } }
הפעלת ממשק המשתמש של אפליקציית הספק בזרימת ההפעלה של LPA
במכשירים שבהם פועל Android 11 ומעלה, ה-LPA יכול להפעיל את ממשק המשתמש של אפליקציית הספק. זה שימושי מכיוון שאפליקציית ספק עשויה לדרוש מידע נוסף מהמשתמש לפני אספקת קוד הפעלה ל-LPA. לדוגמה, ספקים עשויים לדרוש ממשתמשים להיכנס כדי להפעיל את מספרי הטלפון שלהם או לבצע שירותי העברה אחרים.
זה התהליך להפעלת ממשק המשתמש של אפליקציית הספק ב-LPA:
ה-LPA משיק את זרימת ההפעלה של אפליקציית הספק על ידי שליחת הכוונה
android.service.euicc.action.START_CARRIER_ACTIVATION
לחבילת אפליקציית הספק המכילה את הפעולה. (מקלט האפליקציה של הספק חייב להיות מוגן בהצהרת המניפסט עםandroid:permission="android.permission.WRITE_EMBEDDED_SUBSCRIPTIONS"
כדי למנוע קבלת כוונות מאפליקציות שאינן LPA.)String packageName = // The carrier app's package name Intent carrierAppIntent = new Intent(“android.service.euicc.action.START_CARRIER_ACTIVATION”) .setPackage(packageName); ResolveInfo activity = context.getPackageManager().resolveActivity(carrierAppIntent, 0); carrierAppIntent .setClassName(activity.activityInfo.packageName, activity.activityInfo.name); startActivityForResult(carrierAppIntent, requestCode);
אפליקציית הספק עושה את עבודתה באמצעות ממשק משתמש משלה. לדוגמה, כניסה למשתמש או שליחת בקשות HTTP לחלק האחורי של הספק.
אפליקציית הספק מגיבה ל-LPA על ידי קריאה
setResult(int, Intent)
ו-finish()
.- אם אפליקציית הספק מגיבה ב-
RESULT_OK
, ה-LPA ממשיך בזרימת ההפעלה. אם אפליקציית הספק קובעת שהמשתמש צריך לסרוק קוד QR במקום לאפשר ל-LPA לאגד את השירות של אפליקציית הספק, אפליקציית הספק מגיבה ל-LPA באמצעותsetResult(int, Intent)
עםRESULT_OK
ומופעIntent
המכיל אתandroid.telephony.euicc.extra.USE_QR_SCANNER
מוגדר כ-true
. לאחר מכן, ה-LPA בודק את התוספת ומשגר את סורק ה-QR במקום לחייב את היישוםICarrierEuiccProvisioningService
של אפליקציית הספק. - אם אפליקציית הספק קורסת או מגיבה ב-
RESULT_CANCELED
(זהו קוד התגובה המוגדר כברירת מחדל), ה-LPA מבטל את זרימת הפעלת ה-eSIM. - אם אפליקציית הספק מגיבה במשהו אחר מלבד
RESULT_OK
אוRESULT_CANCELED
, ה-LPA מתייחס לזה כשגיאה.
מסיבות אבטחה, ה-LPA לא אמור לקבל ישירות קוד הפעלה שסופק בכוונת התוצאה כדי להבטיח שמתקשרים שאינם מתקשרים ל-LPA לא יוכלו לקבל קוד הפעלה מאפליקציית הספק.
- אם אפליקציית הספק מגיבה ב-
הפעלת זרימת ההפעלה של LPA באפליקציית ספק
החל מ-Android 11, אפליקציות ספק יכולות להשתמש בממשקי API של eUICC כדי להפעיל LUI להפעלת eSIM. שיטה זו מציגה את ממשק המשתמש של זרימת eSIM של ה-LPA כדי להפעיל את פרופיל ה-eSIM. לאחר מכן, ה-LPA שולח שידור כאשר הפעלת פרופיל ה-eSIM מסתיימת.
ה-LPA חייב להכריז על פעילות הכוללת מסנן כוונות עם הפעולה
android.service.euicc.action.START_EUICC_ACTIVATION
. יש להגדיר את העדיפות של מסנן הכוונות לערך שאינו אפס במקרה שקיימים יישומים מרובים במכשיר. לדוגמה:<application> ... <activity android:name=".CarrierAppInitActivity" android:exported="true"> <intent-filter android:priority="100"> <action android:name="android.service.euicc.action.START_EUICC_ACTIVATION" /> </intent-filter> </activity> ... </application>
אפליקציית הספק עושה את עבודתה באמצעות ממשק משתמש משלה. לדוגמה, כניסה למשתמש או שליחת בקשות HTTP לחלק האחורי של הספק.
בשלב זה, אפליקציית הספק חייבת להיות מוכנה לספק קוד הפעלה באמצעות היישום שלה
ICarrierEuiccProvisioningService
. אפליקציית הספק מפעילה את ה-LPA על ידי קריאה ל-startActivityForResult(Intent, int)
עם הפעולהandroid.telephony.euicc.action.START_EUICC_ACTIVATION
. ה-LPA בודק גם את ה-android.telephony.euicc.extra.USE_QR_SCANNER
הבוליאני. אם הערךtrue
, ה-LPA מפעיל את סורק ה-QR כדי לאפשר למשתמש לסרוק את קוד ה-QR של הפרופיל.בצד ה-LPA, ה-LPA נקשר למימוש
ICarrierEuiccProvisioningService
של אפליקציית הספק כדי להביא את קוד ההפעלה ולהוריד את הפרופיל המתאים. ה-LPA מציג את כל רכיבי ממשק המשתמש הנחוצים במהלך ההורדה, כגון מסך טעינה.כאשר זרימת ההפעלה של LPA הושלמה, ה-LPA מגיב לאפליקציית הספק עם קוד תוצאה, שבו אפליקציית הספק מטפלת ב-
onActivityResult(int, int, Intent)
.- אם ה-LPA מצליח להוריד את פרופיל ה-eSIM החדש, הוא מגיב ב-
RESULT_OK
. - אם המשתמש מבטל את הפעלת פרופיל ה-eSIM ב-LPA, הוא יגיב ב-
RESULT_CANCELED
. - אם ה-LPA מגיב במשהו אחר מלבד
RESULT_OK
אוRESULT_CANCELED
, אפליקציית הספק מתייחסת לכך כשגיאה.
מסיבות אבטחה, ה-LPA אינו מקבל קוד הפעלה ישירות בכוונה שסופקה כדי להבטיח שמתקשרים שאינם מתקשרים ל-LPA לא יוכלו לקבל את קוד ההפעלה מאפליקציית הספק.
- אם ה-LPA מצליח להוריד את פרופיל ה-eSIM החדש, הוא מגיב ב-
תמיכה במספר eSIMs
עבור מכשירים עם אנדרואיד 10 ומעלה, מחלקת EuiccManager
תומכת במכשירים עם מספר eSIMs. מכשירים עם eSIM בודד שמשדרגים לאנדרואיד 10 אינם דורשים כל שינוי ביישום ה-LPA מכיוון שהפלטפורמה משייכת אוטומטית את מופע EuiccManager
עם ברירת המחדל של eUICC. ברירת המחדל של eUICC נקבעת על ידי הפלטפורמה עבור מכשירים עם רדיו HAL גרסה 1.2 ומעלה ועל ידי LPA עבור מכשירים עם גרסאות רדיו HAL נמוכות מ-1.2.
דרישות
כדי לתמוך במספר eSIM, המכשיר חייב להיות בעל יותר מ-eUICC אחד, שיכול להיות eUICC מובנה או חריץ SIM פיזי שבו ניתן להכניס eUICC נשלפים.
נדרשת Radio HAL גרסה 1.2 ומעלה כדי לתמוך במספר eSIMs. מומלצים Radio HAL גרסה 1.4 ו- RadioConfig HAL גרסה 1.2.
יישום
כדי לתמוך במספר eSIMs (כולל eUICCs נשלפים או SIMs ניתנים לתכנות), ה-LPA חייב ליישם EuiccService
, אשר מקבל את מזהה החריץ המתאים לזיהוי הכרטיס שסופק המתקשר.
המשאב non_removable_euicc_slots
שצוין ב- arrays.xml
הוא מערך של מספרים שלמים המייצגים את מזהי החריצים של eUICCs המובנים במכשיר. עליך לציין משאב זה כדי לאפשר לפלטפורמה לקבוע אם eUICC שהוכנס ניתן להסרה או לא.
אפליקציית ספק למכשיר עם מספר eSIMs
בעת יצירת אפליקציית ספק עבור מכשיר עם מספר eSIMs, השתמש בשיטת createForCardId
ב- EuiccManager
כדי ליצור אובייקט EuiccManager
המוצמד למזהה כרטיס נתון. מזהה הכרטיס הוא ערך מספר שלם המזהה באופן ייחודי UICC או eUICC במכשיר.
כדי לקבל את מזהה הכרטיס עבור ברירת המחדל של eUICC של המכשיר, השתמש בשיטת getCardIdForDefaultEuicc
ב- TelephonyManager
. שיטה זו מחזירה UNSUPPORTED_CARD_ID
אם גרסת הרדיו HAL נמוכה מ-1.2 ומחזירה UNINITIALIZED_CARD_ID
אם המכשיר לא קרא את ה-eUICC.
אתה יכול גם לקבל מזהי כרטיסים מ- getUiccCardsInfo
ו- getUiccSlotsInfo
(API של מערכת) ב- TelephonyManager
, ו- getCardId
ב- SubscriptionInfo
.
כאשר אובייקט EuiccManager
הודגם עם מזהה כרטיס ספציפי, כל הפעולות מופנות ל-eUICC עם מזהה כרטיס זה. אם ה-eUICC הופך לבלתי ניתן להשגה (לדוגמה, כאשר הוא כבוי או מוסר) EuiccManager
לא עובד יותר.
אתה יכול להשתמש בדוגמאות הקוד הבאות כדי ליצור אפליקציית ספק.
דוגמה 1: קבל מנוי פעיל והפעל את EuiccManager
// Get the active subscription and instantiate an EuiccManager for the eUICC which holds
// that subscription
SubscriptionManager subMan = (SubscriptionManager)
mContext.getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE);
int cardId = subMan.getActiveSubscriptionInfo().getCardId();
EuiccManager euiccMan = (EuiccManager) mContext.getSystemService(Context.EUICC_SERVICE)
.createForCardId(cardId);
דוגמה 2: חזור דרך UICCs והפעל EuiccManager
עבור eUICC נשלף
// On a device with a built-in eUICC and a removable eUICC, iterate through the UICC cards
// to instantiate an EuiccManager associated with a removable eUICC
TelephonyManager telMan = (TelephonyManager)
mContext.getSystemService(Context.TELEPHONY_SERVICE);
List<UiccCardInfo> infos = telMan.getUiccCardsInfo();
int removableCardId = -1; // valid cardIds are 0 or greater
for (UiccCardInfo info : infos) {
if (info.isRemovable()) {
removableCardId = info.getCardId();
break;
}
}
if (removableCardId != -1) {
EuiccManager euiccMan = (EuiccManager) mContext.getSystemService(Context.EUICC_SERVICE)
.createForCardId(removableCardId);
}
מַתַן תוֹקֵף
AOSP לא מגיע עם מימוש LPA ולא צפוי שתהיה לך LPA זמין בכל ה-builds של אנדרואיד (לא כל טלפון תומך ב-eSIM). מסיבה זו, אין מקרי בדיקת CTS מקצה לקצה. עם זאת, מקרי בדיקה בסיסיים זמינים ב-AOSP כדי להבטיח שממשקי ה-API של eUICC החשופים תקפים ב-builds של Android.
עליך לוודא שה-builds עוברים את מקרי הבדיקה הבאים של CTS (עבור ממשקי API ציבוריים): /platform/cts/tests/tests/telephony/current/src/android/telephony/euicc/cts .
ספקים המיישמים אפליקציית ספק צריכים לעבור את מחזורי אבטחת האיכות הפנימיים הרגילים שלהם כדי להבטיח שכל התכונות המיושמות פועלות כמצופה. לכל הפחות, אפליקציית הספק אמורה להיות מסוגלת לרשום את כל פרופילי המנויים שבבעלות אותו מפעיל, להוריד ולהתקין פרופיל, להפעיל שירות בפרופיל, לעבור בין פרופילים ולמחוק פרופילים.
אם אתה מכין LPA משלך, אתה צריך לעבור בדיקות הרבה יותר קפדניות. עליך לעבוד עם ספק המודם שלך, ספק שבב eUICC או eSIM OS, ספקי SM-DP+ וספקים כדי לפתור בעיות ולהבטיח יכולת פעולה הדדית של ה-LPA שלך בתוך ארכיטקטורת RSP. כמות טובה של בדיקות ידניות היא בלתי נמנעת. לקבלת כיסוי הבדיקה הטוב ביותר, עליך לעקוב אחר תוכנית הבדיקה של GSMA SGP.23 RSP .