react-native-esim-activate
v0.1.0
Published
React Native module to check eSIM support and install eSIM profiles on iOS and Android
Maintainers
Readme
react-native-esim-activate
React Native Turbo Module to check eSIM support and install eSIM profiles on iOS and Android.
npm install react-native-esim-activate
# or
yarn add react-native-esim-activateRequires React Native 0.76+ (New Architecture). Autolinking handles iOS and Android.
eSIM install cannot be tested in simulators or emulators. Use a physical iPhone or Android phone with an eUICC.
Usage
Activation codes are LPA strings:
LPA:1$<smdp-address>$<matchingId>Example: LPA:1$smdp.example.com$ABCD-1234
import {
isEsimSupported,
installEsim,
useEsimSupport,
parseActivationCode,
} from 'react-native-esim-activate';
const supported = await isEsimSupported();
await installEsim('LPA:1$smdp.example.com$ABCD-1234');
await installEsim('LPA:1$smdp.example.com$ABCD-1234', {
iosMode: 'carrier',
});function EsimStatus() {
const { isSupported, isChecked } = useEsimSupport();
if (!isChecked) {
return null;
}
return isSupported ? 'eSIM available' : 'eSIM not supported';
}installEsim resolves true when the platform accepted the request. On iOS Universal Link, that means Apple's setup URL opened — not that the profile finished downloading.
API
isEsimSupported(): Promise<boolean>
| Platform | Implementation |
| --- | --- |
| iOS 12+ | CTCellularPlanProvisioning.supportsCellularPlan() |
| Android 9+ (API 28) | EuiccManager.isEnabled |
| Older / other | false |
installEsim(activationCode, options?): Promise<true>
| Option | Type | Default | Description |
| --- | --- | --- | --- |
| iosMode | 'auto' \| 'carrier' \| 'universalLink' | 'auto' | iOS install strategy. Ignored on Android. |
| iosMode | Behavior |
| --- | --- |
| carrier | CTCellularPlanProvisioning.addPlan — in-app install. Requires Apple's carrier entitlement. |
| universalLink | Opens https://esimsetup.apple.com/esim_qrcode_provisioning?carddata=... (iOS 17.4+). No entitlement. |
| auto | Tries addPlan, then falls back to the Universal Link on fail / unknown. |
Carrier apps should pass iosMode: 'carrier'. In auto, cancelling the carrier sheet also returns .fail, so the Universal Link may open afterwards.
Android always uses EuiccManager.downloadSubscription and the system LPA consent UI (RESOLVABLE_ERROR → startResolutionActivity).
parseActivationCode(code): ParsedActivationCode | null
Splits an LPA string into { scheme, address, matchingId }. Returns null if it does not have three non-empty $-separated parts.
useEsimSupport()
Returns { isSupported: boolean, isChecked: boolean }. Checks once on mount.
Error codes
Rejected promises use these error.code values:
| Code | Meaning |
| --- | --- |
| deviceNotSupported | No eSIM / eUICC, or OS too old |
| invalidActivationCode | Not an LPA string with 3 parts |
| fail | Install failed, or Universal Link could not be opened |
| unknown | Unrecognized native result |
iOS setup
The library does not grant Apple privileges. You choose a path:
Universal Link (any app, iOS 17.4+)
No entitlement. Call installEsim(code) or installEsim(code, { iosMode: 'universalLink' }).
Apple presents the system eSIM sheet. This is the right default for most npm consumers.
Carrier API (in-app install, iOS 12+)
addPlan needs a restricted entitlement that Apple grants mainly to carriers / MNOs, not typical App Store apps.
- Ask Apple for
com.apple.CommCenter.fine-grained→public-cellular-plan(carrier association / WWDR). - Add it to the app entitlements (not the library):
<key>com.apple.CommCenter.fine-grained</key>
<array>
<string>public-cellular-plan</string>
</array>- Add your carrier identifiers to the app
Info.plist. Do not copy another operator's values.
<key>CarrierDescriptors</key>
<array>
<dict>
<key>MCC</key>
<string>YOUR_MCC</string>
<key>MNC</key>
<string>YOUR_MNC</string>
<key>GID1</key>
<string>YOUR_GID1</string>
<key>GID2</key>
<string>YOUR_GID2</string>
</dict>
</array>
<key>IccidPrefix</key>
<string>YOUR_ICCID_PREFIX</string>- Call
installEsim(code, { iosMode: 'carrier' }).
Without the entitlement, addPlan typically fails. iosMode: 'auto' then opens the Universal Link on iOS 17.4+.
Android setup
Autolinking merges an optional feature:
<uses-feature
android:name="android.hardware.telephony.euicc"
android:required="false" />Install uses EuiccManager (API 28+). On consumer devices the system LPA dialog is shown via a resolvable error; the user must confirm.
Do not add WRITE_EMBEDDED_SUBSCRIPTIONS unless you ship a privileged / carrier / system app. That permission is not a normal Play Store permission. This library does not declare it. Silent install without the LPA UI is only for apps that already have that privileged access.
Test on a physical device with an eUICC. Emulators report unsupported.
Example app
The example/ app can check support and trigger install. From the repo root:
yarn
yarn example ios
yarn example androidRun those commands on a physical device. Simulators will not exercise addPlan or EuiccManager.
Contributing
License
MIT
Made with create-react-native-library
