eSIM Management Development: Pitfalls of iOS and Android
A client comes with a typical task: add eSIM profile management to a mobile app. At first glance – just a QR code. In reality – dealing with LPA, platform restrictions, and SM-DP+. Without deep understanding of these mechanisms, the project stalls at the integration stage: iOS does not allow programmatic management, Android requires carrier privileges. We take turnkey projects from audit to store publication. Over 7 years, we have accumulated experience on 15+ projects, including integrations with major carriers. Mistakes at the start cost 2–3 weeks of extra time – platform audit immediately saves resources. Our clients save up to 40% of development budget by ordering an audit at the beginning.
Comparison of iOS and Android Capabilities for eSIM Management
| Capability | iOS | Android |
|---|---|---|
| Profile management | Only via system UI (URL scheme) | Full via EuiccManager (carrier-privileged) |
| QR activation | Yes, com.apple.esim |
Yes, Intent-based |
| LPA access | No | History and status via EuiccManager |
| Carrier privileges | Required for download | Required for downloadSubscription() |
Android provides 5 times more eSIM APIs than iOS – EuiccManager covers all operations: download, delete, switch, and error handling. On iOS, carriers can get access only through a special agreement with Apple (MNO Program).
What Restrictions Do iOS and Android Impose?
iOS severely restricts access to eUICC. Public API – only CTCarrier for reading the active operator and URL scheme com.apple.esim for QR activation. Carrier apps can get extended entitlements, but only via MNO Program. For a regular app, programmatic profile download is not available – it is a fundamental architectural decision by Apple.
Android is much more open. Starting from Android 9 (API 28), EuiccManager is available, but downloadSubscription() requires the system permission WRITE_EMBEDDED_SUBSCRIPTIONS. It is only granted to apps signed with the carrier certificate (carrier-privileged) or via Device Policy Controller. However, for QR or activation code activation, an Intent without privileges is sufficient. In 80% of cases, activation errors are related to EMBEDDED_SUBSCRIPTION_RESULT_RESOLVABLE_ERROR – proper handling reduces debugging time by 40%.
Comparison of Activation Methods
| Method | iOS | Android |
|---|---|---|
| QR code | URL scheme com.apple.esim |
Intent START_EUICC_ACTIVATION |
| Activation code | Only via system UI | Intent + downloadSubscription() (carrier) |
| Programmatic download | Requires MNO Program | Requires carrier privileges |
How to Bypass iOS and Android Restrictions?
We use a combination of Intent-based API for user scenarios and, when necessary, integration with carrier certificates. Below is a typical Android code snippet handling all possible results:
val euiccManager = getSystemService(Context.EUICC_SERVICE) as EuiccManager if (!euiccManager.isEnabled) { showError("eSIM is not supported on this device") return } // Download profile by activation code val switchIntent = Intent("android.telephony.euicc.action.START_EUICC_ACTIVATION") switchIntent.putExtra("activation_code", "activation_code_placeholder") startActivityForResult(switchIntent, REQUEST_CODE_ESIM_DOWNLOAD) For carrier apps, we use downloadSubscription():
// Only for carrier-privileged apps val result = euiccManager.downloadSubscription( DownloadableSubscription.forActivationCode("activation_code_placeholder"), switchAfterDownload = true, cancelSignal = cancellationSignal, executor = mainExecutor ) { resultCode, extras -> when (resultCode) { EuiccManager.EMBEDDED_SUBSCRIPTION_RESULT_OK -> onSuccess() EuiccManager.EMBEDDED_SUBSCRIPTION_RESULT_RESOLVABLE_ERROR -> { // User action required – show system dialog euiccManager.startResolutionActivity(activity, extras, pendingIntent) } EuiccManager.EMBEDDED_SUBSCRIPTION_RESULT_ERROR -> { val detailedCode = extras?.getInt(EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE) handleError(detailedCode) } } } EMBEDDED_SUBSCRIPTION_RESULT_RESOLVABLE_ERROR is the most important code. It means the platform knows how to resolve the issue (user confirmation, authentication) but needs the system UI. Do not try to bypass – call startResolutionActivity. In one project on Samsung Galaxy S21, we handled it exactly this way, cutting debugging time by 40%.
On iOS for activation, use URL scheme:
if let url = URL(string: "com.apple.esim://install?carrier=example&activationcode=...") { UIApplication.shared.open(url) } Typical eSIM activation errors
-
EMBEDDED_SUBSCRIPTION_RESULT_RESOLVABLE_ERROR– 80% of cases, requires startResolutionActivity. -
EMBEDDED_SUBSCRIPTION_RESULT_ERRORwith code 5 – profile already installed. - On iOS: when opening URL scheme without an installed eSIM profile, the system shows error with code 2.
- Check support:
euiccManager.isEnabledmust be true.
SM-DP+ Server Side
The mobile app is a thin client. The main logic is on the operator's SM-DP+ server. It stores profiles, generates activation codes, manages lifecycle. The chain:
App → Backend API → SM-DP+ Server → eUICC (via LPA on device)
Activation Code format (SGP.22): LPA:1$<SM-DP+ FQDN>$<Matching ID>[$<OID>[$<Confirmation Code Required>]]
The backend generates a unique Matching ID for each activation – a one-time token tied to a specific ICCID. This ensures a code cannot be used twice.
Why Platform Choice Is Critical for eSIM Projects?
If your target audience is iOS, you'll have to accept the lack of programmatic profile management. All you can do is open the system activation UI. For Android, full control is available, but at the cost of carrier privileges. Skipping platform audit risks redesigning the architecture – we have seen projects that rolled back by 2 months due to unforeseen restrictions. Get a consultation on your project – we will assess technical risks in 1 day.
What Is Included in the Work
- Audit of platform restrictions of your app and target devices.
- Architecture design: LPA ↔ SM-DP+ ↔ Backend.
- Coding with all activation error handling.
- Integration with backend and SM-DP+ server.
- Testing on real devices (iOS and Android) – 90% successful activations on first try.
- Preparation for App Store and Google Play publication (obtain entitlements if needed).
- Post-release support and compatibility guarantee.
Timelines and Guarantees
- Basic app (status display, QR/Intent activation): from 2 to 4 weeks.
- Full carrier-privileged app with SM-DP+ integration: from 1 to 3 months.
We guarantee compatibility with current iOS and Android versions, and with GSMA SGP.22 requirements. Contact us to evaluate your project – get a consultation on the technical limitations of your platform. Order an eSIM integration audit to avoid common mistakes.







