واجهات برمجة تطبيقات eUICC

في Android 9، تتوفّر واجهات برمجة التطبيقات لإدارة الملفات الشخصية (العامة وSystemApi@) من خلال الفئة EuiccManager. تتوفّر واجهات برمجة التطبيقات الخاصة بالتواصل مع eUICC ‏(SystemApi@ فقط) من خلال الفئة EuiccCardManager.

لمحة عن eUICC

يمكن لمشغّلي شبكات الجوّال إنشاء تطبيقات مشغّلي شبكات الجوّال باستخدام EuiccManager لإدارة الملفات الشخصية، كما هو موضّح في الشكل 1. لا يشترط أن تكون تطبيقات مشغّلي شبكات الجوّال تطبيقات نظام، ولكن يجب أن تحصل على امتيازات مشغّلي شبكات الجوّال التي تمنحها ملفات eUICC. يجب أن يكون تطبيق LPA (واجهة المستخدم المحلية (LUI) وخادم LPA الخلفي) تطبيق نظام (أي مضمّن في صورة النظام) لاستدعاء @SystemApi.

هاتف Android مزوّد بتطبيق مشغّل شبكة الجوّال وLPA من الشركة المصنّعة للجهاز الأصلي

الشكل 1: هواتف Android التي تتضمّن تطبيق مشغّل شبكة الجوّال وLPA من الشركة المصنّعة للجهاز

بالإضافة إلى منطق الاتصال بـ EuiccCardManager والتواصل مع eUICC، يجب أن تنفّذ تطبيقات LPA ما يلي:

  • يتواصل عميل SM-DP+ مع خادم SM-DP+ للمصادقة وتنزيل الملفات الشخصية
  • [اختياري] SM-DS للحصول على المزيد من الملفات الشخصية المحتملة القابلة للتنزيل
  • التعامل مع الإشعارات لإرسالها إلى الخادم من أجل تعديل حالة الملف الشخصي
  • [اختياري] إدارة الشرائح، بما في ذلك التبديل بين منطق شريحة eSIM وشريحة SIM. هذا الخيار غير إلزامي إذا كان الهاتف يحتوي على شريحة eSIM فقط.
  • eSIM OTA

على الرغم من إمكانية توفّر أكثر من تطبيق LPA على هاتف Android، يمكن اختيار تطبيق LPA واحد فقط ليكون تطبيق LPA الفعلي الذي يتم استخدامه استنادًا إلى الأولوية المحدّدة في ملف AndroidManifest.xml لكل تطبيق.

استخدام EuiccManager

تتوفّر واجهات برمجة التطبيقات LPA بشكل علني من خلال EuiccManager (ضمن الحزمة android.telephony.euicc). يمكن لتطبيق مشغّل شبكة الجوّال الحصول على مثيل EuiccManager، واستدعاء الطرق في EuiccManager للحصول على معلومات eUICC وإدارة الاشتراكات (المشار إليها باسم "الملفات الشخصية" في مستندات GSMA RSP) كعناصر SubscriptionInfo.

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

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

للحصول على معلومات حول واجهات برمجة التطبيقات الخاصة بالملفات الشخصية المتعددة المفعَّلة، يُرجى الاطّلاع على ملفات شخصية متعددة مفعَّلة.

واجهات برمجة التطبيقات

يمكن العثور على واجهات برمجة التطبيقات التالية في المستندات المرجعية EuiccManager وEuiccManager.java.

الحصول على مثيل (عام)

يحصل على مثيل EuiccManager من خلال Context#getSystemService. للحصول على التفاصيل، يُرجى الاطّلاع على getSystemService.

EuiccManager mgr = (EuiccManager) context.getSystemService(Context.EUICC_SERVICE);

التحقّق من التفعيل (عام)

تتحقّق هذه السمة ممّا إذا كان الاشتراك المضمّن مفعّلاً. يجب التحقّق من ذلك قبل الوصول إلى واجهات برمجة التطبيقات الخاصة بـ LPA. للحصول على التفاصيل، يُرجى الاطّلاع على isEnabled.

boolean isEnabled = mgr.isEnabled();
if (!isEnabled) {
    return;
}

الحصول على معرّف شريحة SIM المضمّنة (عام)

تعرض هذه السمة رقم تعريف eUICC. قد تكون هذه القيمة فارغة إذا لم تكن شريحة eUICC جاهزة. يجب أن يكون لدى المتصل امتياز مشغّل شبكة الجوّال أو إذن READ_PRIVILEGED_PHONE_STATE. للحصول على التفاصيل، يُرجى الاطّلاع على getEid.

String eid = mgr.getEid();
if (eid == null) {
  // Handle null case.
}

Get EuiccInfo (عام)

تعرض هذه الطريقة معلومات عن شريحة eUICC. يحتوي هذا الحقل على إصدار نظام التشغيل. للحصول على التفاصيل، يُرجى الاطّلاع على getEuiccInfo.

EuiccInfo info = mgr.getEuiccInfo();
String osVer = info.getOsVersion();

تنزيل الاشتراك (عام)

تنزيل الاشتراك المحدّد (يُشار إليه باسم "الملف الشخصي" في مستندات GSMA RSP) يمكن إنشاء الاشتراك من خلال رمز تفعيل. على سبيل المثال، يمكن تحليل رمز التفعيل من رمز استجابة سريعة. تنزيل اشتراك هو عملية غير متزامنة.

يجب أن يكون لدى المتصل إذن WRITE_EMBEDDED_SUBSCRIPTIONS أو امتيازات مشغّل شبكة الجوّال للاشتراك المستهدف. للحصول على التفاصيل، يُرجى الاطّلاع على downloadSubscription.

// Register receiver.
String action = "download_subscription";
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),
        "example.broadcast.permission" /* broadcastPermission*/, null /* handler */);

// Download subscription asynchronously.
DownloadableSubscription sub =
        DownloadableSubscription.forActivationCode(code /* encodedActivationCode*/);
Intent intent = new Intent(action);
PendingIntent callbackIntent = PendingIntent.getBroadcast(
        getContext(), 0 /* requestCode */, intent, PendingIntent.FLAG_UPDATE_CURRENT);
mgr.downloadSubscription(sub, true /* switchAfterDownload */, callbackIntent);

تبديل الاشتراك (علني)

يتم التبديل إلى الاشتراك المحدّد (تفعيله). يجب أن يكون لدى المتصل إما WRITE_EMBEDDED_SUBSCRIPTIONS أو امتيازات مشغّل شبكة الجوّال للاشتراك الحالي المفعّل والاشتراك المستهدَف. للحصول على التفاصيل، يُرجى الاطّلاع على switchToSubscription.

// Register receiver.
String action = "switch_to_subscription";
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),
        "example.broadcast.permission" /* broadcastPermission*/, null /* handler */);

// Switch to a subscription asynchronously.
Intent intent = new Intent(action);
PendingIntent callbackIntent = PendingIntent.getBroadcast(
        getContext(), 0 /* requestCode */, intent, PendingIntent.FLAG_UPDATE_CURRENT);
mgr.switchToSubscription(1 /* subscriptionId */, callbackIntent);

تبديل الاشتراك باستخدام المنفذ (عام)

(متاحة بدءًا من الإصدار 13 من نظام التشغيل Android) يتم التبديل إلى (تفعيل) الاشتراك المحدّد باستخدام فهرس المنفذ المحدّد. يجب أن يكون لدى المتصل إما WRITE_EMBEDDED_SUBSCRIPTIONS أو امتيازات مشغّل شبكة الجوّال للاشتراك المفعّل حاليًا والاشتراك المستهدَف. للحصول على التفاصيل، يُرجى الاطّلاع على switchToSubscription.

// Register receiver.
String action = "switch_to_subscription";
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),
        "example.broadcast.permission" /* broadcastPermission*/, null /* handler */);

// Switch to a subscription asynchronously.
Intent intent = new Intent(action);
PendingIntent callbackIntent = PendingIntent.getBroadcast(
        getContext(), 0 /* requestCode */, intent, PendingIntent.FLAG_UPDATE_CURRENT);
mgr.switchToSubscription(1 /* subscriptionId */, 0 /*portIndex*/, callbackIntent);

هل يمكن نقل شريحة SIM (عام)؟

public boolean isSimPortAvailable(int portIndex)

(متاحة من Android 13) تعرض هذه السمة ما إذا كان فهرس المنفذ الذي تم تمريره متاحًا. يكون المنفذ متاحًا إذا لم يكن لديه اشتراك مفعّل أو إذا كان تطبيق الاتصال لديه امتياز مشغّل شبكة الجوّال على الاشتراك المثبَّت على المنفذ المحدّد. للحصول على التفاصيل، يُرجى الاطّلاع على isSimPortAvailable.

حذف الاشتراك (متاح للجميع)

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

// Register receiver.
String action = "delete_subscription";
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),
        "example.broadcast.permission" /* broadcastPermission*/,
        null /* handler */);

// Delete a subscription asynchronously.
Intent intent = new Intent(action);
PendingIntent callbackIntent = PendingIntent.getBroadcast(
        getContext(), 0 /* requestCode */, intent, PendingIntent.FLAG_UPDATE_CURRENT);
mgr.deleteSubscription(1 /* subscriptionId */, callbackIntent);

محو جميع الاشتراكات (واجهة برمجة التطبيقات للنظام)

يمحو هذا الإجراء جميع الاشتراكات على الجهاز. اعتبارًا من Android 11، عليك تقديم قيمة تعداد EuiccCardManager#ResetOption لتحديد ما إذا كنت تريد محو جميع أنواع الاشتراكات الاختبارية أو التشغيلية أو كليهما. يجب أن يكون لدى المتصل إذن WRITE_EMBEDDED_SUBSCRIPTIONS.

// Register receiver.
String action = "delete_subscription";
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),
        "example.broadcast.permission" /* broadcastPermission*/,
        null /* handler */);

// Erase all operational subscriptions asynchronously.
Intent intent = new Intent(action);
PendingIntent callbackIntent = PendingIntent.getBroadcast(
        getContext(), 0 /* requestCode */, intent, PendingIntent.FLAG_UPDATE_CURRENT);
mgr.eraseSubscriptions(
        EuiccCardManager.RESET_OPTION_DELETE_OPERATIONAL_PROFILES, callbackIntent);

بدء نشاط حلّ المشكلة (عام)

يبدأ نشاطًا لحلّ خطأ يمكن للمستخدم حله. إذا عرضت عملية ما الرمز EuiccManager#EMBEDDED_SUBSCRIPTION_RESULT_RESOLVABLE_ERROR، يمكن استدعاء هذه الطريقة لطلب حلّ المشكلة من المستخدم. لا يمكن استدعاء هذه الطريقة إلا مرة واحدة لكل خطأ معيّن.

...
mgr.startResolutionActivity(getActivity(), 0 /* requestCode */, resultIntent, callbackIntent);

الثوابت

للاطّلاع على قائمة بثوابت public في EuiccManager، راجِع الثوابت.