eSIM profile switching via mobile app

NOVASOLUTIONS.TECHNOLOGY is engaged in the development, support and maintenance of iOS, Android, PWA mobile applications. We have extensive experience and expertise in publishing mobile applications in popular markets like Google Play, App Store, Amazon, AppGallery and others.
Development and support of all types of mobile applications:
Information and entertainment mobile applications
News apps, games, reference guides, online catalogs, weather apps, fitness and health apps, travel apps, educational apps, social networks and messengers, quizzes, blogs and podcasts, forums, aggregators
E-commerce mobile applications
Online stores, B2B apps, marketplaces, online exchanges, cashback services, exchanges, dropshipping platforms, loyalty programs, food and goods delivery, payment systems.
Business process management mobile applications
CRM systems, ERP systems, project management, sales team tools, financial management, production management, logistics and delivery management, HR management, data monitoring systems
Electronic services mobile applications
Classified ads platforms, online schools, online cinemas, electronic service platforms, cashback platforms, video hosting, thematic portals, online booking and scheduling platforms, online trading platforms

These are just some of the types of mobile applications we work with, and each of them may have its own specific features and functionality, tailored to the specific needs and goals of the client.

Showing 1 of 1 servicesAll 1735 services
eSIM profile switching via mobile app
Complex
from 1 week to 3 months
FAQ
Our competencies:
Development stages
Latest works
  • image_mobile-applications_feedme_467_0.webp
    Development of a mobile application for FEEDME
    756
  • image_mobile-applications_xoomer_471_0.webp
    Development of a mobile application for XOOMER
    624
  • image_mobile-applications_rhl_428_0.webp
    Development of a mobile application for RHL
    1052
  • image_mobile-applications_zippy_411_0.webp
    Development of a mobile application for ZIPPY
    947
  • image_mobile-applications_affhome_429_0.webp
    Development of a mobile application for Affhome
    862
  • image_mobile-applications_flavors_409_0.webp
    Development of a mobile application for the FLAVORS company
    445

Implementing eSIM Profile Switching in Mobile App

Switching between installed eSIM profiles is simpler than activation — profile already exists on eUICC, just need to make it active. But even here platforms add complexities: iOS requires user confirmation via system dialog, Android on some devices reboots radio module, taking 10–30 seconds with connection loss.

Android: EuiccManager.switchToSubscription

fun switchToProfile(subscriptionId: Int) {
    // Get subscriptionId from SubscriptionManager
    val activeSubInfo = subscriptionManager.activeSubscriptionInfoList
    val currentEsimId = activeSubInfo?.firstOrNull { it.isEmbedded }?.subscriptionId

    if (currentEsimId == subscriptionId) {
        showMessage("This profile is already active")
        return
    }

    euiccManager.switchToSubscription(
        subscriptionId,
        PendingIntent.getBroadcast(
            context,
            REQUEST_CODE_SWITCH,
            Intent(ACTION_ESIM_SWITCH_COMPLETE),
            PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
        )
    )
}

// BroadcastReceiver for result handling
private val switchReceiver = object : BroadcastReceiver() {
    override fun onReceive(context: Context, intent: Intent) {
        val resultCode = intent.getIntExtra(EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE, 0)
        if (resultCode == EuiccManager.EMBEDDED_SUBSCRIPTION_RESULT_OK) {
            onSwitchSuccess()
        } else {
            onSwitchError(resultCode)
        }
    }
}

switchToSubscription doesn't take callback directly — only PendingIntent. Not a bug: operation is asynchronous and may require user interaction. Result comes to BroadcastReceiver.

Switching Without System UI (Privileged)

On Samsung and some others available via android.telephony.euicc.EuiccManager.switchToSubscription(int, boolean) with forceDeactivateSim = true flag. Works only for apps with WRITE_EMBEDDED_SUBSCRIPTIONS.

// Samsung-specific flag for switching without dialog
if (Build.MANUFACTURER.equals("samsung", ignoreCase = true)) {
    euiccManager.switchToSubscription(
        subscriptionId,
        forceDeactivateSim = true, // Don't ask user
        callbackIntent = pendingIntent
    )
}

Important: on some Qualcomm devices, radio reboots after switchToSubscription without warning. Warn user beforehand: "After switching, connection will drop for 15–30 seconds."

iOS: Only Through Settings or Carrier Entitlement

On iOS, programmatic switching between eSIM profiles is unavailable for regular apps. Two options:

Link to Settings: UIApplication.shared.open(URL(string: "App-Prefs:root=Cellular")!) — opens "Cellular" section in settings, user switches manually. Not best UX, but only way without entitlement.

Carrier entitlement + CTSubscriptionManager: available only for operator apps with com.apple.developer.CoreTelephony.Subscriber entitlement. Apple provides only to licensed operators:

import CoreTelephony

let subscriptionManager = CTSubscriptionManager()

// Get list of profiles
let subscriptions = subscriptionManager.subscriptions
// subscriptions: [String: CTSubscriber] — key is subscriber ID

// For switching — only via system UI or operator
// No direct API for switch without entitlement

Getting List of Installed Profiles

Android:

fun getInstalledEsimProfiles(): List<SubscriptionInfo> {
    val allSubs = subscriptionManager.availableSubscriptionInfoList ?: emptyList()
    return allSubs.filter { it.isEmbedded }
        .map { sub ->
            // sub.displayName — operator name
            // sub.simSlotIndex: -1 if inactive, >= 0 if active
            // sub.iccId — unique profile identifier
            sub
        }
}

simSlotIndex == -1 for inactive profiles — important for status display in list.

iOS (without entitlement):

import CoreTelephony

func getActiveCarriers() -> [CTCarrier] {
    let networkInfo = CTTelephonyNetworkInfo()
    return networkInfo.serviceSubscriberCellularProviders?.values
        .compactMap { $0 }
        .filter { $0.carrierName != nil }
        ?? []
}

Only active profiles. List of all installed (including inactive) — unavailable without carrier entitlement.

Switching UX

Switch time: Android — 10–30 seconds (radio reboot on Qualcomm, faster on MTK). iOS via Settings — uncontrollable. Show progress indicator with warning about temporary connection loss.

After successful switch, verify new active profile via SubscriptionManager.getActiveSubscriptionInfo(newSubscriptionId) — ensure completion before UI update.

Timeline

Android: switching between profiles with BroadcastReceiver and error handling — 1–2 weeks. iOS: deeplink to Settings + show current profiles — 3–5 days. Carrier-grade solution for both platforms with full control via entitlement: 1–2 months.