تنفيذ eSIM

تتيح تقنية SIM المدمجة (eSIM أو eUICC) لمستخدمي الهاتف المحمول تنزيل ملف تعريف شركة الاتصالات وتنشيط خدمة شركة الاتصالات دون الحاجة إلى بطاقة SIM فعلية. إنها مواصفات عالمية تعتمد على GSMA والتي تتيح توفير بطاقة SIM عن بعد (RSP) لأي جهاز محمول. بدءًا من Android 9، يوفر إطار عمل Android واجهات برمجة التطبيقات القياسية للوصول إلى eSIM وإدارة ملفات تعريف الاشتراك على eSIM. تعمل واجهات برمجة تطبيقات eUICC هذه على تمكين الجهات الخارجية من تطوير تطبيقات مشغل شبكة الجوال الخاصة بها ومساعدي ملفات التعريف المحلية (LPAs) على أجهزة Android التي تدعم شريحة eSIM.

LPA هو تطبيق نظام مستقل يجب تضمينه في صورة إنشاء Android. تتم إدارة ملفات التعريف على eSIM بشكل عام بواسطة LPA، حيث تعمل كجسر بين SM-DP+ (خدمة عن بعد تقوم بإعداد حزم الملفات الشخصية وتخزينها وتسليمها إلى الأجهزة) وشريحة eUICC. يمكن أن يتضمن LPA APK بشكل اختياري مكون واجهة المستخدم، يسمى LPA UI أو LUI، لتوفير مكان مركزي للمستخدم النهائي لإدارة جميع ملفات تعريف الاشتراك المضمنة. يكتشف إطار عمل Android أفضل LPA متاحًا ويتصل به تلقائيًا، ويوجه جميع عمليات eUICC من خلال مثيل LPA.

بنية مبسطة لتوفير بطاقة SIM عن بعد (RSP).

الشكل 1. بنية RSP المبسطة

يجب على مشغلي شبكات الهاتف المحمول المهتمين بإنشاء تطبيق مشغل شبكة الجوال الاطلاع على واجهات برمجة التطبيقات في EuiccManager ، والتي توفر عمليات إدارة ملفات التعريف عالية المستوى مثل downloadSubscription() و switchToSubscription() و deleteSubscription() .

إذا كنت أحد مصنعي المعدات الأصلية (OEM) للجهاز ومهتمًا بإنشاء تطبيق نظام LPA الخاص بك، فيجب عليك توسيع EuiccService لإطار عمل Android للاتصال بخدمات LPA الخاصة بك. بالإضافة إلى ذلك، يجب عليك استخدام واجهات برمجة التطبيقات في EuiccCardManager ، والتي توفر وظائف ES10x استنادًا إلى الإصدار 2.0 من GSMA RSP. تُستخدم هذه الوظائف لإصدار أوامر إلى شريحة eUICC، مثل prepareDownload() و loadBoundProfilePackage() و retrieveNotificationList() و resetMemory() .

تتطلب واجهات برمجة التطبيقات في EuiccManager تطبيق LPA تم تنفيذه بشكل صحيح للعمل، ويجب أن يكون المتصل بواجهات برمجة تطبيقات EuiccCardManager هو LPA. يتم فرض ذلك من خلال إطار عمل Android.

يمكن للأجهزة التي تعمل بنظام Android 10 أو أعلى أن تدعم الأجهزة ذات شرائح eSIM المتعددة. لمزيد من المعلومات، راجع دعم شرائح eSIM المتعددة .

صنع تطبيق الناقل

تتيح واجهات برمجة تطبيقات eUICC في نظام التشغيل Android 9 لمشغلي شبكات الهاتف المحمول إنشاء تطبيقات تحمل العلامة التجارية لشركة الاتصالات لإدارة ملفاتهم الشخصية مباشرةً. يتضمن ذلك تنزيل وحذف ملفات تعريف الاشتراك المملوكة لشركة الاتصالات، بالإضافة إلى التبديل إلى ملف تعريف مملوك لشركة الاتصالات.

EuiccManager

EuiccManager هو نقطة الدخول الرئيسية للتطبيقات للتفاعل مع LPA. يتضمن ذلك تطبيقات شركة الاتصالات التي تقوم بتنزيل الاشتراكات المملوكة لشركة الاتصالات وحذفها والتبديل إليها. يتضمن هذا أيضًا تطبيق نظام LUI، الذي يوفر موقعًا مركزيًا/واجهة مستخدم لإدارة جميع الاشتراكات المضمنة، ويمكن أن يكون تطبيقًا منفصلاً عن التطبيق الذي يوفر EuiccService .

لاستخدام واجهات برمجة التطبيقات العامة، يجب أن يحصل تطبيق الناقل أولاً على مثيل 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();

تستخدم العديد من واجهات برمجة التطبيقات، مثل downloadSubscription() و switchToSubscription() ، عمليات رد الاتصال PendingIntent لأنها قد تستغرق ثوانٍ أو حتى دقائق حتى تكتمل. يتم إرسال PendingIntent مع رمز النتيجة في مساحة EuiccManager#EMBEDDED_SUBSCRIPTION_RESULT_ ، والتي توفر رموز خطأ محددة بواسطة إطار العمل، بالإضافة إلى رمز نتيجة تفصيلي عشوائي منتشر من LPA كـ EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE ، مما يسمح لتطبيق الناقل بالتتبع لأغراض التسجيل/تصحيح الأخطاء. يجب أن يكون رد الاتصال PendingIntent هو BroadcastReceiver .

لتنزيل اشتراك معين قابل للتنزيل (تم إنشاؤه من رمز التفعيل أو رمز الاستجابة السريعة):

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

للحصول على قائمة كاملة بواجهات برمجة تطبيقات EuiccManager وأمثلة التعليمات البرمجية، راجع واجهات برمجة تطبيقات eUICC .

أخطاء قابلة للحل

هناك بعض الحالات التي يتعذر فيها على النظام إكمال عملية eSIM ولكن يمكن للمستخدم حل الخطأ. على سبيل المثال، قد يفشل downloadSubscription إذا كانت البيانات التعريفية للملف الشخصي تشير إلى أن رمز تأكيد شركة الاتصالات مطلوب. أو قد يفشل switchToSubscription إذا كان تطبيق شركة الاتصالات يتمتع بامتيازات شركة الاتصالات على ملف تعريف الوجهة (أي أن شركة الاتصالات تمتلك الملف الشخصي) ولكن ليس لديها امتيازات شركة الاتصالات على ملف التعريف الممكّن حاليًا، وبالتالي فإن موافقة المستخدم مطلوبة.

في هذه الحالات، يتم استدعاء رد اتصال المتصل باستخدام EuiccManager#EMBEDDED_SUBSCRIPTION_RESULT_RESOLVABLE_ERROR . تحتوي Intent رد الاتصال على إضافات داخلية بحيث أنه عندما يقوم المتصل بتمريرها إلى EuiccManager#startResolutionActivity ، يمكن طلب الحل من خلال LUI. باستخدام رمز التأكيد مرة أخرى على سبيل المثال، يقوم EuiccManager#startResolutionActivity بتشغيل شاشة LUI التي تسمح للمستخدم بإدخال رمز التأكيد؛ بعد إدخال الرمز، يتم استئناف عملية التنزيل. يوفر هذا الأسلوب لتطبيق الناقل تحكمًا كاملاً في وقت ظهور واجهة المستخدم، ولكنه يمنح LPA/LUI طريقة قابلة للتوسيع لإضافة معالجة جديدة للمشكلات التي يمكن للمستخدم استردادها في المستقبل دون الحاجة إلى تغيير تطبيقات العميل.

يحدد Android 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 الخاص بالجهاز، ويجب السماح لكل تطبيق شركة اتصالات فقط بالوصول إلى الملفات الشخصية المملوكة لشركة الاتصالات هذه. على سبيل المثال، يجب ألا يتمكن مشغل شبكة الجوال "أ" من تنزيل أو تمكين أو تعطيل ملف تعريف مملوك لمشغل شبكة الجوال "ب".

لضمان إمكانية الوصول إلى الملف الشخصي فقط لمالكه، يستخدم Android آلية لمنح امتيازات خاصة لتطبيق مالك الملف الشخصي (أي تطبيق الناقل). يقوم نظام Android الأساسي بتحميل الشهادات المخزنة في ملف قاعدة الوصول للملف الشخصي (ARF) ويمنح الإذن للتطبيقات الموقعة بواسطة هذه الشهادات لإجراء مكالمات إلى واجهات برمجة تطبيقات EuiccManager . يتم وصف العملية رفيعة المستوى أدناه:

  1. يقوم المشغل بتوقيع APK لتطبيق الناقل؛ تقوم أداة apksigner بإرفاق شهادة المفتاح العام بملف APK.
  2. يقوم المشغل/SM-DP+ بإعداد ملف التعريف وبياناته التعريفية، والتي تتضمن ARF الذي يحتوي على:

    1. التوقيع (SHA-1 أو SHA-256) لشهادة المفتاح العام لتطبيق الناقل (مطلوب)
    2. اسم حزمة تطبيق شركة الاتصالات (موصى به بشدة)
  3. يحاول تطبيق Carrier تنفيذ عملية eUICC عبر EuiccManager API.

  4. يتحقق نظام Android الأساسي من تطابق تجزئة SHA-1 أو SHA-256 لشهادة تطبيق المتصل مع توقيع الشهادة التي تم الحصول عليها من ARF الخاص بالملف الشخصي المستهدف. إذا تم تضمين اسم حزمة تطبيق شركة الاتصالات في ARF، فيجب أن يتطابق أيضًا مع اسم حزمة تطبيق المتصل.

  5. بعد التحقق من التوقيع واسم الحزمة (إذا تم تضمينهما)، يتم منح امتياز شركة الاتصالات لتطبيق المتصل عبر الملف الشخصي المستهدف.

نظرًا لأن البيانات التعريفية للملف الشخصي يمكن أن تكون متاحة خارج الملف الشخصي نفسه (بحيث يتمكن 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)، والذي يجب ربطه بواجهات برمجة تطبيقات Android Euicc. تقدم الأقسام التالية نظرة عامة موجزة عن إنشاء تطبيق LPA ودمجه مع نظام Android.

متطلبات الأجهزة/المودم

يجب أن يدعم LPA ونظام التشغيل eSIM الموجود على شريحة eUICC الإصدار 2.0 أو الإصدار 2.2 من GSMA RSP (توفير بطاقة SIM عن بُعد) على الأقل. يجب عليك أيضًا التخطيط لاستخدام خوادم SM-DP+ وSM-DS التي تحتوي على إصدار RSP مطابق. للحصول على تفاصيل حول بنية RSP، راجع مواصفات بنية RSP الخاصة بـ GSMA SGP.21 .

بالإضافة إلى ذلك، للتكامل مع واجهات برمجة تطبيقات eUICC في Android 9، يجب أن يرسل مودم الجهاز إمكانات طرفية مع دعم إمكانات eUICC المشفرة (إدارة ملف التعريف المحلي وتنزيل ملف التعريف). ويحتاج أيضًا إلى تنفيذ الطرق التالية:

  • IRadio HAL v1.1: setSimPower
  • IRadio HAL v1.2: getIccCardStatus

  • IRadioConfig HAL v1.0: getSimSlotsStatus

  • IRadioConfig AIDL v1.0: getAllowedCarriers

    يحتاج Google LPA إلى معرفة حالة قفل مشغل شبكة الجوال حتى يتمكن من السماح بتنزيل eSIM أو نقله فقط لمشغل شبكة الجوال المسموح به. وإلا فقد ينتهي الأمر بالمستخدمين إلى تنزيل بطاقة SIM ونقلها ثم يدركون لاحقًا أن الجهاز مقفل على شركة اتصالات مختلفة.

    • يجب على البائعين أو مصنعي المعدات الأصلية تطبيق IRadioSim.getAllowedCarriers()HAL API.

    • يجب أن يقوم البائع RIL / المودم بملء حالة القفل ومعرف الناقل الخاص بالناقل حيث تم قفل الجهاز كجزء من 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، وLPA UI أو LUI.

لتنفيذ الواجهة الخلفية لـ LPA، يجب عليك توسيع 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>

داخليًا، يحدد إطار عمل Android LPA النشط ويتفاعل معه حسب الحاجة لدعم واجهات برمجة تطبيقات eUICC لنظام Android. يتم الاستعلام عن 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 واحد أو ملفات APK متعددة (على سبيل المثال، ملف يقوم بتنفيذ EuiccService والآخر يوفر أنشطة LUI) هو اختيار تصميم.

EuiccCardManager

EuiccCardManager هي الواجهة للتواصل مع شريحة eSIM. وهو يوفر وظائف ES10 (كما هو موضح في مواصفات GSMA RSP) ويتعامل مع أوامر طلب/استجابة APDU ذات المستوى المنخفض بالإضافة إلى تحليل ASN.1. EuiccCardManager عبارة عن واجهة برمجة تطبيقات للنظام ولا يمكن استدعاؤها إلا من خلال التطبيقات التي تتمتع بمميزات النظام.

تطبيقات الناقل، LPA، وEuicc APIs

الشكل 2. يستخدم كل من تطبيق الناقل وLPA واجهات برمجة تطبيقات Euicc

تتطلب واجهات برمجة التطبيقات الخاصة بعملية الملف الشخصي من خلال EuiccCardManager أن يكون المتصل LPA. يتم فرض ذلك من خلال إطار عمل Android. هذا يعني أنه يجب على المتصل تمديد EuiccService والإعلان عنه في ملف البيان الخاص بك، كما هو موضح في الأقسام السابقة.

على غرار EuiccManager ، لاستخدام واجهات برمجة تطبيقات 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 مختلفة ومخصصة. عند استخدام واجهات برمجة تطبيقات EuiccCardManager ، يجب على المتصل (LPA) توفير كائن Executor يتم من خلاله استدعاء رد الاتصال. قد يتم تشغيل كائن Executor هذا على مؤشر ترابط واحد أو على تجمع مؤشرات ترابط من اختيارك.

تتمتع معظم واجهات برمجة تطبيقات 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 من خلال تطبيق الناقل

على الأجهزة التي تعمل بنظام التشغيل Android 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:

  1. يُطلق 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);
    
  2. يقوم تطبيق الناقل بعمله باستخدام واجهة المستخدم الخاصة به. على سبيل المثال، تسجيل دخول المستخدم أو إرسال طلبات HTTP إلى الواجهة الخلفية لمشغل شبكة الجوال.

  3. يستجيب تطبيق الناقل لـ LPA عن طريق استدعاء setResult(int, Intent) و finish() .

    1. إذا استجاب تطبيق الناقل بـ RESULT_OK ، فسيواصل LPA تدفق التنشيط. إذا قرر تطبيق الناقل أنه يجب على المستخدم مسح رمز QR ضوئيًا بدلاً من السماح لـ LPA بربط خدمة تطبيق الناقل، فإن تطبيق الناقل يستجيب لـ LPA باستخدام setResult(int, Intent) مع RESULT_OK ومثيل Intent الذي يحتوي على android.telephony.euicc.extra.USE_QR_SCANNER مضبوط على true . يقوم LPA بعد ذلك بالتحقق من العناصر الإضافية وتشغيل الماسح الضوئي QR بدلاً من ربط تطبيق ICarrierEuiccProvisioningService لتطبيق الناقل.
    2. إذا تعطل تطبيق شركة الاتصالات أو استجاب بـ RESULT_CANCELED (هذا هو رمز الاستجابة الافتراضي)، فإن LPA يلغي تدفق تنشيط eSIM.
    3. إذا استجاب تطبيق مشغل شبكة الجوال بشيء آخر غير RESULT_OK أو RESULT_CANCELED ، فإن LPA يتعامل معه على أنه خطأ.

    لأسباب أمنية، لا ينبغي لـ LPA قبول رمز التنشيط المقدم مباشرة في هدف النتيجة لضمان عدم تمكن المتصلين من غير LPA من الحصول على رمز التنشيط من تطبيق شركة الاتصالات.

إطلاق تدفق تنشيط LPA في تطبيق الناقل

بدءًا من Android 11، يمكن لتطبيقات مشغل شبكة الجوال استخدام واجهات برمجة تطبيقات eUICC لبدء واجهة مستخدم عالمية (LUI) لتنشيط eSIM. تعرض هذه الطريقة واجهة مستخدم تدفق تنشيط eSIM الخاصة بـ LPA لتنشيط ملف تعريف eSIM. تقوم LPA بعد ذلك بإرسال بث عند انتهاء تنشيط ملف تعريف eSIM.

  1. يجب أن تعلن 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>
    
  2. يقوم تطبيق الناقل بعمله باستخدام واجهة المستخدم الخاصة به. على سبيل المثال، تسجيل دخول المستخدم أو إرسال طلبات HTTP إلى الواجهة الخلفية لمشغل شبكة الجوال.

  3. في هذه المرحلة، يجب أن يكون تطبيق شركة الاتصالات جاهزًا لتوفير رمز التنشيط من خلال تطبيق ICarrierEuiccProvisioningService الخاص به. يقوم تطبيق الناقل بتشغيل LPA عن طريق استدعاء startActivityForResult(Intent, int) باستخدام الإجراء android.telephony.euicc.action.START_EUICC_ACTIVATION . يتحقق LPA أيضًا من الأمر المنطقي الإضافي android.telephony.euicc.extra.USE_QR_SCANNER . إذا كانت القيمة true ، يقوم LPA بتشغيل الماسح الضوئي QR للسماح للمستخدم بمسح رمز الاستجابة السريعة لملف التعريف.

  4. على جانب LPA، يرتبط LPA بتطبيق ICarrierEuiccProvisioningService الخاص بتطبيق الناقل لجلب رمز التنشيط وتنزيل ملف التعريف المقابل. يعرض LPA جميع عناصر واجهة المستخدم الضرورية أثناء التنزيل، مثل شاشة التحميل.

  5. عند اكتمال تدفق تنشيط LPA، يستجيب LPA لتطبيق شركة الاتصالات برمز النتيجة، الذي يعالجه تطبيق شركة الاتصالات في onActivityResult(int, int, Intent) .

    1. إذا نجح LPA في تنزيل ملف تعريف eSIM الجديد، فإنه يستجيب بـ RESULT_OK .
    2. إذا قام المستخدم بإلغاء تنشيط ملف تعريف eSIM في LPA، فإنه يستجيب بـ RESULT_CANCELED .
    3. إذا استجاب LPA بشيء آخر غير RESULT_OK أو RESULT_CANCELED ، فإن تطبيق مشغل شبكة الجوال يتعامل مع هذا على أنه خطأ.

    لأسباب أمنية، لا يقبل LPA رمز التنشيط مباشرةً في الغرض المقدم لضمان عدم تمكن المتصلين من غير LPA من الحصول على رمز التنشيط من تطبيق شركة الاتصالات.

دعم شرائح eSIM متعددة

بالنسبة للأجهزة التي تعمل بنظام التشغيل Android 10 أو أعلى، تدعم فئة EuiccManager الأجهزة ذات شرائح eSIM المتعددة. لا تتطلب الأجهزة التي تحتوي على شريحة eSIM واحدة والتي يتم ترقيتها إلى Android 10 أي تعديل على تطبيق LPA حيث يقوم النظام الأساسي تلقائيًا بربط مثيل EuiccManager مع eUICC الافتراضي. يتم تحديد eUICC الافتراضي بواسطة النظام الأساسي للأجهزة التي تحتوي على إصدار HAL للراديو 1.2 أو أعلى وعن طريق LPA للأجهزة التي تحتوي على إصدارات HAL للراديو أقل من 1.2.

متطلبات

لدعم شرائح eSIM المتعددة، يجب أن يحتوي الجهاز على أكثر من eUICC واحد، والذي يمكن أن يكون إما eUICC مدمجًا أو فتحة SIM فعلية حيث يمكن إدراج eUICC القابلة للإزالة.

مطلوب إصدار Radio HAL 1.2 أو أعلى لدعم شرائح eSIM المتعددة. يوصى بإصدار Radio HAL 1.4 وRadioConfig HAL الإصدار 1.2.

تطبيق

لدعم شرائح eSIM المتعددة (بما في ذلك شرائح eUICC القابلة للإزالة أو شرائح SIM القابلة للبرمجة)، يجب على LPA تنفيذ EuiccService ، الذي يتلقى معرف الفتحة المتوافق مع معرف البطاقة المقدمة من المتصل.

المورد non_removable_euicc_slots المحدد في arrays.xml هو مصفوفة من الأعداد الصحيحة التي تمثل معرفات الفتحة الخاصة بـ eUICCs المضمنة بالجهاز. يجب عليك تحديد هذا المورد للسماح للنظام الأساسي بتحديد ما إذا كان eUICC المدرج قابلاً للإزالة أم لا.

تطبيق الناقل للجهاز مع شرائح eSIM متعددة

عند إنشاء تطبيق شركة اتصالات لجهاز به عدة شرائح eSIM، استخدم طريقة createForCardId في EuiccManager لإنشاء كائن EuiccManager المثبت على معرف بطاقة معين. معرف البطاقة عبارة عن قيمة عددية تحدد بشكل فريد UICC أو eUICC على الجهاز.

للحصول على معرف البطاقة لـ eUICC الافتراضي للجهاز، استخدم الأسلوب getCardIdForDefaultEuicc في TelephonyManager . تقوم هذه الطريقة بإرجاع UNSUPPORTED_CARD_ID إذا كان إصدار HAL للراديو أقل من 1.2 وإرجاع UNINITIALIZED_CARD_ID إذا لم يقرأ الجهاز eUICC.

يمكنك أيضًا الحصول على معرفات البطاقة من getUiccCardsInfo و getUiccSlotsInfo (واجهة برمجة تطبيقات النظام) في 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 متاحًا على جميع إصدارات Android (ليس كل هاتف يدعم eSIM). ولهذا السبب، لا توجد حالات اختبار CTS شاملة. ومع ذلك، تتوفر حالات الاختبار الأساسية في AOSP للتأكد من صلاحية واجهات برمجة تطبيقات eUICC المكشوفة في إصدارات Android.

يجب عليك التأكد من اجتياز الإصدارات لحالات اختبار CTS التالية (لواجهات برمجة التطبيقات العامة): /platform/cts/tests/tests/telephony/current/src/android/telephony/euicc/cts .

يجب أن تخضع شركات النقل التي تنفذ تطبيق شركة الاتصالات لدورات ضمان الجودة الداخلية العادية الخاصة بها لضمان عمل جميع الميزات المطبقة كما هو متوقع. كحد أدنى، يجب أن يكون تطبيق شركة الاتصالات قادرًا على سرد جميع ملفات تعريف الاشتراك المملوكة لنفس المشغل، وتنزيل ملف تعريف وتثبيته، وتنشيط خدمة في ملف التعريف، والتبديل بين الملفات الشخصية، وحذف الملفات الشخصية.

إذا كنت تقوم بتصنيع LPA الخاص بك، فيجب أن تخضع لاختبارات أكثر صرامة. يجب عليك العمل مع بائع المودم الخاص بك، وشريحة eUICC أو بائع نظام التشغيل eSIM، وموردي SM-DP+، وشركات الاتصالات لحل المشكلات وضمان إمكانية التشغيل البيني لـ LPA الخاص بك ضمن بنية RSP. قدر كبير من الاختبار اليدوي أمر لا مفر منه. للحصول على أفضل تغطية للاختبار، يجب عليك اتباع خطة اختبار GSMA SGP.23 RSP .