فناوری سیمکارتهای جاسازیشده (eSIM یا eUICC) به کاربران تلفن همراه اجازه میدهد تا بدون داشتن سیمکارت فیزیکی، یک پروفایل اپراتور را دانلود کرده و سرویس اپراتور را فعال کنند. این یک مشخصه جهانی است که توسط GSMA ارائه میشود و امکان تأمین سیمکارت از راه دور (RSP) را برای هر دستگاه تلفن همراه فراهم میکند. با شروع از اندروید ۹، چارچوب اندروید APIهای استانداردی را برای دسترسی به eSIM و مدیریت پروفایلهای اشتراک در eSIM ارائه میدهد. این APIهای eUICC به اشخاص ثالث این امکان را میدهند که برنامههای اپراتور و دستیارهای پروفایل محلی (LPA) خود را در دستگاههای اندرویدی مجهز به eSIM توسعه دهند.
LPA یک برنامه سیستمی مستقل است که باید در تصویر ساخت اندروید گنجانده شود. مدیریت پروفایلها در eSIM عموماً توسط LPA انجام میشود، زیرا به عنوان پلی بین SM-DP+ (سرویس از راه دور که بستههای پروفایل را آماده، ذخیره و به دستگاهها تحویل میدهد) و تراشه eUICC عمل میکند. APK LPA میتواند به صورت اختیاری شامل یک جزء رابط کاربری به نام LPA UI یا LUI باشد تا یک مکان مرکزی برای کاربر نهایی جهت مدیریت تمام پروفایلهای اشتراک تعبیه شده فراهم کند. چارچوب اندروید به طور خودکار بهترین LPA موجود را کشف و به آن متصل میشود و تمام عملیات eUICC را از طریق یک نمونه LPA مسیریابی میکند.

شکل ۱. معماری سادهشدهی RSP
اپراتورهای شبکه تلفن همراه که علاقهمند به ایجاد یک برنامه اپراتور تلفن همراه هستند، باید به APIهای موجود در EuiccManager نگاهی بیندازند، که عملیات مدیریت پروفایل سطح بالایی مانند downloadSubscription() ، switchToSubscription() و deleteSubscription() را ارائه میدهد.
اگر شما یک تولیدکننده اصلی دستگاه هستید که علاقهمند به ایجاد برنامه سیستم LPA خود هستید، باید EuiccService برای چارچوب اندروید گسترش دهید تا به سرویسهای LPA شما متصل شود. علاوه بر این، باید از APIهای موجود در EuiccCardManager استفاده کنید که توابع ES10x را بر اساس GSMA RSP v2.0 ارائه میدهند. این توابع برای صدور دستورات به تراشه eUICC مانند prepareDownload() ، loadBoundProfilePackage() ، retrieveNotificationList() و resetMemory() استفاده میشوند.
APIهای موجود در EuiccManager برای عملکرد خود به یک برنامه LPA که به درستی پیادهسازی شده باشد نیاز دارند و فراخوانیکننده APIهای EuiccCardManager باید یک LPA باشد. این امر توسط چارچوب اندروید اعمال میشود.
دستگاههایی که اندروید ۱۰ یا بالاتر دارند میتوانند از دستگاههایی با چندین eSIM پشتیبانی کنند. برای اطلاعات بیشتر، به بخش «پشتیبانی از چندین eSIM» مراجعه کنید.
یک برنامه اپراتور تلفن همراه بسازید
رابطهای برنامهنویسی کاربردی eUICC در اندروید ۹ به اپراتورهای شبکه تلفن همراه این امکان را میدهد که برنامههایی با برند اپراتور ایجاد کنند تا مستقیماً پروفایلهای خود را مدیریت کنند. این شامل دانلود و حذف پروفایلهای اشتراک متعلق به اپراتور و همچنین تغییر به پروفایل متعلق به یک اپراتور میشود.
مدیر اجرایی
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 و نمونههای کد، به eUICC APIs مراجعه کنید.
خطاهای قابل حل
مواردی وجود دارد که سیستم قادر به تکمیل عملیات eSIM نیست، اما کاربر میتواند این خطا را برطرف کند. برای مثال، اگر فرادادههای پروفایل نشان دهند که کد تأیید اپراتور مورد نیاز است، ممکن است downloadSubscription با شکست مواجه شود. یا اگر switchToSubscription اپراتور دارای امتیازات اپراتور بر روی پروفایل مقصد باشد (یعنی اپراتور مالک پروفایل باشد) اما امتیازات اپراتور بر روی پروفایل فعال فعلی را نداشته باشد، ممکن است switchToSubscription با شکست مواجه شود.
برای این موارد، فراخوانی برگشتی تماسگیرنده با EuiccManager#EMBEDDED_SUBSCRIPTION_RESULT_RESOLVABLE_ERROR فراخوانی میشود. Intent فراخوانی برگشتی شامل موارد اضافی داخلی است به طوری که وقتی تماسگیرنده آن را به EuiccManager#startResolutionActivity ارسال میکند، میتوان از طریق LUI درخواست رفع مشکل را داد. به عنوان مثال، با استفاده از کد تأیید، EuiccManager#startResolutionActivity یک صفحه LUI را فعال میکند که به کاربر اجازه میدهد کد تأیید را وارد کند. پس از وارد کردن کد، عملیات دانلود از سر گرفته میشود. این رویکرد به برنامه حامل کنترل کامل بر زمان نمایش رابط کاربری را میدهد، اما به LPA/LUI یک روش توسعهپذیر برای اضافه کردن روشهای جدید مدیریت مشکلات قابل بازیابی توسط کاربر در آینده بدون نیاز به تغییر برنامههای کلاینت میدهد.
اندروید ۹ این خطاهای قابل حل را در EuiccService تعریف میکند که LUI باید آنها را مدیریت کند:
/**
* Alert the user that this action will result in an active SIM being
* deactivated. To implement the LUI triggered by the system, you need to define
* this in AndroidManifest.xml.
*/
public static final String ACTION_RESOLVE_DEACTIVATE_SIM =
"android.service.euicc.action.RESOLVE_DEACTIVATE_SIM";
/**
* Alert the user about a download/switch being done for an app that doesn't
* currently have carrier privileges.
*/
public static final String ACTION_RESOLVE_NO_PRIVILEGES =
"android.service.euicc.action.RESOLVE_NO_PRIVILEGES";
/** Ask the user to resolve all the resolvable errors. */
public static final String ACTION_RESOLVE_RESOLVABLE_ERRORS =
"android.service.euicc.action.RESOLVE_RESOLVABLE_ERRORS";
امتیازات اپراتور
اگر شما یک اپراتور هستید که در حال توسعه برنامه اپراتور خود هستید که EuiccManager را برای دانلود پروفایلها روی دستگاه فراخوانی میکند، پروفایل شما باید شامل قوانین امتیاز اپراتور مربوط به برنامه اپراتور شما در فراداده باشد. دلیل این امر این است که پروفایلهای اشتراک متعلق به اپراتورهای مختلف میتوانند در eUICC یک دستگاه همزمان وجود داشته باشند و هر برنامه اپراتور فقط باید اجازه دسترسی به پروفایلهای متعلق به آن اپراتور را داشته باشد. به عنوان مثال، اپراتور A نباید بتواند پروفایل متعلق به اپراتور B را دانلود، فعال یا غیرفعال کند.
برای اطمینان از اینکه یک پروفایل فقط برای مالک آن قابل دسترسی است، اندروید از مکانیزمی برای اعطای امتیازات ویژه به برنامه مالک پروفایل (یعنی برنامه اپراتور) استفاده میکند. پلتفرم اندروید گواهیهای ذخیره شده در فایل قانون دسترسی پروفایل (ARF) را بارگذاری میکند و به برنامههایی که توسط این گواهیها امضا شدهاند، اجازه میدهد تا با APIهای EuiccManager تماس برقرار کنند. فرآیند سطح بالا در زیر شرح داده شده است:
- اپراتور، APK برنامهی اپراتور را امضا میکند؛ ابزار apksigner گواهی کلید عمومی را به APK پیوست میکند.
اپراتور/SM-DP+ یک پروفایل و فرادادههای آن را تهیه میکند که شامل یک ARF است که شامل موارد زیر است:
- امضای (SHA-1 یا SHA-256) گواهی کلید عمومی برنامهی اپراتور (الزامی)
- نام بسته برنامه اپراتور (اکیدا توصیه میشود)
برنامهی اپراتور سعی میکند یک عملیات eUICC را با رابط برنامهنویسی کاربردی
EuiccManagerانجام دهد.پلتفرم اندروید، هش SHA-1 یا SHA-256 گواهی برنامه تماسگیرنده را با امضای گواهی بهدستآمده از ARF پروفایل هدف مطابقت میدهد. اگر نام بسته برنامه اپراتور در ARF گنجانده شده باشد، باید با نام بسته برنامه تماسگیرنده نیز مطابقت داشته باشد.
پس از تأیید امضا و نام بسته (در صورت وجود)، امتیاز اپراتور به برنامه تماسگیرنده از طریق پروفایل هدف اعطا میشود.
از آنجا که فرادادههای پروفایل میتوانند خارج از خود پروفایل نیز در دسترس باشند (به طوری که LPA بتواند فرادادههای پروفایل را قبل از دانلود پروفایل از SM-DP+ یا هنگام غیرفعال شدن پروفایل از ISD-R بازیابی کند)، باید شامل همان قوانین امتیاز حامل موجود در پروفایل باشد.
سیستم عامل eUICC و SM-DP+ باید از برچسب اختصاصی BF76 در فراداده پروفایل پشتیبانی کنند. محتوای برچسب باید همان قوانین امتیاز حامل باشد که توسط اپلت قانون دسترسی (ARA) تعریف شده در امتیازات حامل UICC برگردانده میشود:
RefArDo ::= [PRIVATE 2] SEQUENCE { -- Tag E2
refDo [PRIVATE 1] SEQUENCE { -- Tag E1
deviceAppIdRefDo [PRIVATE 1] OCTET STRING (SIZE(20|32)), -- Tag C1
pkgRefDo [PRIVATE 10] OCTET STRING (SIZE(0..127)) OPTIONAL -- Tag CA
},
arDo [PRIVATE 3] SEQUENCE { -- Tag E3
permArDo [PRIVATE 27] OCTET STRING (SIZE(8)) -- Tag DB
}
}
برای جزئیات بیشتر در مورد امضای برنامه، به امضای برنامه خود مراجعه کنید. برای جزئیات بیشتر در مورد امتیازات اپراتور، به امتیازات اپراتور UICC مراجعه کنید.
یک برنامه دستیار پروفایل محلی بسازید
تولیدکنندگان دستگاه میتوانند دستیار پروفایل محلی (LPA) خود را پیادهسازی کنند که باید به APIهای Android Euicc متصل شود. بخشهای زیر مروری مختصر بر ساخت یک برنامه LPA و ادغام آن با سیستم اندروید ارائه میدهند.
نیازمندیهای سختافزار/مودم
LPA و سیستم عامل eSIM روی تراشه eUICC باید حداقل از GSMA RSP (Remote SIM Provisioning) نسخه 2.0 یا نسخه 2.2 پشتیبانی کنند. همچنین باید در نظر داشته باشید که از سرورهای SM-DP+ و SM-DS که نسخه RSP منطبق با آن را دارند، استفاده کنید. برای جزئیات معماری RSP، به مشخصات معماری GSMA SGP.21 RSP مراجعه کنید.
علاوه بر این، برای ادغام با APIهای eUICC در اندروید ۹، مودم دستگاه باید قابلیتهای ترمینال را با پشتیبانی از قابلیتهای eUICC کدگذاری شده (مدیریت پروفایل محلی و دانلود پروفایل) ارسال کند. همچنین باید روشهای زیر را پیادهسازی کند:
- رادیو IRadio HAL نسخه ۱.۱:
setSimPower رادیو IRadio HAL نسخه ۱.۲:
getIccCardStatusIRadioConfig HAL نسخه ۱.۰:
getSimSlotsStatusIRadioConfig AIDL v1.0:
getAllowedCarriersگوگل LPA باید وضعیت قفل اپراتور را بداند تا بتواند دانلود یا انتقال eSIM را فقط برای اپراتور مجاز مجاز کند. در غیر این صورت، کاربران ممکن است در نهایت یک سیمکارت را دانلود و منتقل کنند و بعداً متوجه شوند که دستگاهشان به اپراتور دیگری قفل شده است.
فروشندگان یا تولیدکنندگان اصلی تجهیزات (OEM) باید رابط برنامهنویسی کاربردی IRadioSim.getAllowedCarriers()HAL را پیادهسازی کنند.
فروشنده RIL / مودم باید وضعیت قفل و carrierId اپراتوری که دستگاه روی آن قفل شده است را به عنوان بخشی از API IRadioSimResponse.getAllowedCarriersResponse()HAL وارد کند.
مودم باید eSIM را با پروفایل بوت پیشفرض فعال، به عنوان یک سیمکارت معتبر تشخیص دهد و سیمکارت را روشن نگه دارد.
برای دستگاههایی که اندروید ۱۰ را اجرا میکنند، باید یک آرایه شناسه اسلات 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 مراجعه کنید.
خدمات Euicc
یک LPA از دو جزء جداگانه تشکیل شده است (ممکن است هر دو در یک APK پیادهسازی شوند): بکاند LPA و رابط کاربری یا LUI مربوط به LPA.
برای پیادهسازی بکاند LPA، باید EuiccService را ارثبری کنید و این سرویس را در فایل مانیفست خود اعلام کنید. این سرویس باید به مجوز سیستمی android.permission.BIND_EUICC_SERVICE نیاز داشته باشد تا اطمینان حاصل شود که فقط سیستم میتواند به آن متصل شود. این سرویس همچنین باید شامل یک فیلتر intent با اکشن android.service.euicc.EuiccService باشد. در صورتی که چندین پیادهسازی در دستگاه وجود داشته باشد، اولویت فیلتر intent باید روی مقداری غیر از صفر تنظیم شود. به عنوان مثال:
<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های 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 نیاز داشته باشد. هر کدام باید یک فیلتر intent با اکشن مناسب، دسته 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 متفاوت از APKای که EuiccService را پیادهسازی میکند، آمده باشد. اینکه یک APK واحد یا چندین APK داشته باشیم (مثلاً یکی که EuiccService را پیادهسازی میکند و دیگری که فعالیتهای LUI را ارائه میدهد) یک انتخاب طراحی است.
مدیر کارت هوشمند Euicc
EuiccCardManager رابطی برای برقراری ارتباط با تراشه eSIM است. این رابط، توابع ES10 (مطابق با مشخصات GSMA RSP) را ارائه میدهد و دستورات درخواست/پاسخ APDU سطح پایین و همچنین تجزیه ASN.1 را مدیریت میکند. EuiccCardManager یک API سیستمی است و فقط توسط برنامههای دارای مجوز سیستم قابل فراخوانی است.

شکل ۲. هم برنامه اپراتور و هم 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 از طریق یک رابط AIDL به EuiccCardController (که در فرآیند تلفن اجرا میشود) متصل میشود و هر متد 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 از طریق اپلیکیشن اپراتور
در دستگاههایی که اندروید ۹ یا بالاتر دارند، میتوانید از یک برنامه اپراتور برای فعال کردن 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.aidlpackage 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.aidlpackage 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 با ارسال پیادهسازی کلاس stub مربوط به IGetActivationCodeCallback ، متدهای getActivationCode یا getActivationCodeForEid را فراخوانی میکند تا کد فعالسازی را از برنامهی حامل دریافت کند.
تفاوت بین 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، یک برنامهی دارای امتیاز سیستمی، میتواند به آن متصل شود. این سرویس همچنین باید شامل یک فیلتر intent با اکشن 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.javaimport 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 شروع کنید
در دستگاههایی که اندروید ۱۱ و بالاتر دارند، 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 به بکاند اپراتور.
برنامهی حامل با فراخوانی
setResult(int, Intent)وfinish()به LPA پاسخ میدهد.- اگر برنامهی اپراتور با
RESULT_OKپاسخ دهد، LPA جریان فعالسازی را ادامه میدهد. اگر برنامهی اپراتور تشخیص دهد که کاربر باید یک کد QR را اسکن کند به جای اینکه اجازه دهد LPA سرویس برنامهی اپراتور را متصل کند، برنامهی اپراتور با استفاده ازsetResult(int, Intent)باRESULT_OKو یک نمونهیIntentحاوی مقدار بولی extraandroid.telephony.euicc.extra.USE_QR_SCANNERکه رویtrueتنظیم شده است، به LPA پاسخ میدهد. سپس LPA مقدار extra را بررسی کرده و به جای اتصال پیادهسازیICarrierEuiccProvisioningServiceبرنامهی اپراتور، اسکنر QR را اجرا میکند. - اگر برنامه اپراتور از کار بیفتد یا با
RESULT_CANCELED(این کد پاسخ پیشفرض است) پاسخ دهد، LPA جریان فعالسازی eSIM را لغو میکند. - اگر برنامهی اپراتور با چیزی غیر از
RESULT_OKیاRESULT_CANCELEDپاسخ دهد، LPA آن را به عنوان یک خطا در نظر میگیرد.
به دلایل امنیتی، LPA نباید مستقیماً کد فعالسازی ارائه شده در هدف نتیجه را بپذیرد تا اطمینان حاصل شود که تماسگیرندگان غیر LPA نمیتوانند کد فعالسازی را از برنامه اپراتور دریافت کنند.
- اگر برنامهی اپراتور با
جریان فعالسازی LPA را در یک برنامه اپراتور راهاندازی کنید
از اندروید ۱۱ به بعد، برنامههای اپراتورها میتوانند از APIهای eUICC برای شروع یک رابط کاربری (LUI) برای فعالسازی eSIM استفاده کنند. این روش، رابط کاربری جریان فعالسازی eSIM مربوط به LPA را برای فعالسازی پروفایل eSIM نمایش میدهد. سپس LPA پس از اتمام فعالسازی پروفایل eSIM، یک اعلان ارسال میکند.
LPA باید یک فعالیت شامل یک فیلتر intent را با اکشن
android.service.euicc.action.START_EUICC_ACTIVATIONاعلام کند. در صورتی که چندین پیادهسازی روی دستگاه وجود داشته باشد، اولویت فیلتر intent باید روی مقداری غیر از صفر تنظیم شود. به عنوان مثال:<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خود باشد. برنامهی اپراتور با فراخوانیstartActivityForResult(Intent, int)به همراه اکشنandroid.telephony.euicc.action.START_EUICC_ACTIVATION، LPA را راهاندازی میکند. LPA همچنین مقدار بولی extraandroid.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 کد فعالسازی را مستقیماً در intent ارائه شده نمیپذیرد تا اطمینان حاصل شود که تماسگیرندگان غیر LPA نمیتوانند کد فعالسازی را از برنامه اپراتور دریافت کنند.
- اگر LPA در دانلود پروفایل جدید eSIM موفق شود، با
پشتیبانی از چندین سیمکارت الکترونیکی (eSIM)
برای دستگاههایی که اندروید ۱۰ یا بالاتر را اجرا میکنند، کلاس EuiccManager از دستگاههایی با چندین eSIM پشتیبانی میکند. دستگاههایی که دارای یک eSIM هستند و به اندروید ۱۰ ارتقا مییابند، نیازی به هیچ تغییری در پیادهسازی LPA ندارند، زیرا پلتفرم به طور خودکار نمونه EuiccManager را با eUICC پیشفرض مرتبط میکند. eUICC پیشفرض برای دستگاههایی با رادیو HAL نسخه ۱.۲ یا بالاتر توسط پلتفرم و برای دستگاههایی با رادیو HAL نسخههای پایینتر از ۱.۲ توسط LPA تعیین میشود.
الزامات
برای پشتیبانی از چندین eSIM، دستگاه باید بیش از یک eUICC داشته باشد که میتواند یا یک eUICC داخلی باشد یا یک اسلات سیمکارت فیزیکی که eUICCهای قابل جابجایی در آن قرار میگیرند.
برای پشتیبانی از چندین eSIM، به Radio HAL نسخه ۱.۲ یا بالاتر نیاز است. Radio HAL نسخه ۱.۴ و RadioConfig HAL نسخه ۱.۲ توصیه میشوند.
پیادهسازی
برای پشتیبانی از چندین eSIM (شامل eUICCهای قابل جابجایی یا سیمکارتهای قابل برنامهریزی)، LPA باید EuiccService پیادهسازی کند که شناسه اسلات مربوط به شناسه کارت ارائه شده توسط تماسگیرنده را دریافت میکند.
منبع non_removable_euicc_slots که در arrays.xml مشخص شده است، آرایهای از اعداد صحیح است که نشاندهنده شناسههای اسلات eUICC های داخلی دستگاه است. شما باید این منبع را مشخص کنید تا پلتفرم بتواند تشخیص دهد که آیا یک eUICC درج شده قابل جابجایی است یا خیر.
برنامه اپراتور برای دستگاهی با چندین سیمکارت الکترونیکی
هنگام ساخت یک برنامه اپراتور برای دستگاهی با چندین eSIM، از متد createForCardId در EuiccManager برای ایجاد یک شیء EuiccManager که به یک شناسه کارت مشخص پین شده است، استفاده کنید. شناسه کارت یک مقدار صحیح است که به طور منحصر به فرد UICC یا eUICC را در دستگاه مشخص میکند.
برای دریافت شناسه کارت برای eUICC پیشفرض دستگاه، از متد getCardIdForDefaultEuicc در TelephonyManager استفاده کنید. این متد اگر نسخه رادیو HAL پایینتر از ۱.۲ باشد، UNSUPPORTED_CARD_ID را برمیگرداند و اگر دستگاه eUICC را نخوانده باشد UNINITIALIZED_CARD_ID را برمیگرداند.
همچنین میتوانید شناسههای کارت را از getUiccCardsInfo و getUiccSlotsInfo (رابط برنامهنویسی سیستم) در TelephonyManager و getCardId در SubscriptionInfo دریافت کنید.
وقتی یک شیء EuiccManager با یک شناسه کارت خاص نمونهسازی میشود، تمام عملیات به eUICC با آن شناسه کارت هدایت میشوند. اگر eUICC غیرقابل دسترس شود (مثلاً وقتی خاموش یا حذف شود)، EuiccManager دیگر کار نمیکند.
برای ایجاد یک برنامهی حمل و نقل میتوانید از نمونه کدهای زیر استفاده کنید.
مثال ۱: دریافت اشتراک فعال و نمونهسازی 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);
مثال ۲: پیمایش روی UICCها و نمونهسازی EuiccManager برای یک eUICC قابل جابجایی
// On a device with a built-in eUICC and a removable eUICC, iterate through the UICC cards
// to instantiate an EuiccManager associated with a removable eUICC
TelephonyManager telMan = (TelephonyManager)
mContext.getSystemService(Context.TELEPHONY_SERVICE);
List<UiccCardInfo> infos = telMan.getUiccCardsInfo();
int removableCardId = -1; // valid cardIds are 0 or greater
for (UiccCardInfo info : infos) {
if (info.isRemovable()) {
removableCardId = info.getCardId();
break;
}
}
if (removableCardId != -1) {
EuiccManager euiccMan = (EuiccManager) mContext.getSystemService(Context.EUICC_SERVICE)
.createForCardId(removableCardId);
}
اعتبارسنجی
AOSP پیادهسازی LPA را ارائه نمیدهد و انتظار نمیرود که LPA در تمام نسخههای اندروید موجود باشد (همه گوشیها از eSIM پشتیبانی نمیکنند). به همین دلیل، هیچ مورد آزمایشی CTS سرتاسری وجود ندارد. با این حال، موارد آزمایشی اولیه در AOSP موجود است تا اطمینان حاصل شود که APIهای eUICC در نسخههای اندروید معتبر هستند.
شما باید مطمئن شوید که نسخههای ساختهشده، موارد آزمایش CTS زیر (برای APIهای عمومی) را با موفقیت پشت سر میگذارند: /platform/cts/tests/tests/telephony/current/src/android/telephony/euicc/cts .
اپراتورهایی که یک اپلیکیشن اپراتور را پیادهسازی میکنند، باید چرخههای تضمین کیفیت داخلی معمول خود را طی کنند تا اطمینان حاصل شود که تمام ویژگیهای پیادهسازی شده طبق انتظار کار میکنند. حداقل، اپلیکیشن اپراتور باید بتواند تمام پروفایلهای اشتراک متعلق به همان اپراتور را فهرست کند، یک پروفایل را دانلود و نصب کند، یک سرویس را روی پروفایل فعال کند، بین پروفایلها جابهجا شود و پروفایلها را حذف کند.
اگر LPA خودتان را میسازید، باید آزمایشهای بسیار دقیقتری را پشت سر بگذارید. باید با فروشنده مودم، فروشنده تراشه eUICC یا سیستم عامل eSIM، فروشندگان SM-DP+ و اپراتورها همکاری کنید تا مشکلات را حل کنید و از قابلیت همکاری LPA خود در معماری RSP اطمینان حاصل کنید. انجام مقدار زیادی آزمایش دستی اجتنابناپذیر است. برای بهترین پوشش آزمایش، باید از طرح آزمایش GSMA SGP.23 RSP پیروی کنید.