Реалізація активації eSIM-профіля через мобільний додаток
Активація eSIM — найбільш болісний користувацький досвід у телекомі, якщо реалізована неправильно. Користувач вводить activation code, бачить спиннер 30 секунд, отримує «Помилка активації». Що пішло не так — додаток не знає. SM-DP+ сервер повернув SGP.22 error code, LPA його обробив, платформа завернула в непрозорий resultCode. Завдання — докопатися до реальної причини та показати людини зрозумілу повідомлення.
Activation Code: формати та джерела
SGP.22 визначає два способи передачи activation code користувачу:
QR-код — стандартний формат: LPA:1$smdp-plus.operator.com$ABC123XYZ. Сканування — нативними можливостями платформи або вбудованим сканером у додатку. На iOS можна відкрити системний процес активації безпосередньо.
Manual Entry — той же рядковий код, вводиться вручну. Повинна бути валідація формату перед відправкою: наявність LPA:1$, коректний FQDN SM-DP+, Matching ID без заборонених символів.
// Валідація формату activation code
fun validateActivationCode(code: String): Boolean {
val pattern = Regex("""^LPA:1\$[a-zA-Z0-9\-.]+\$[a-zA-Z0-9\-]+(\$[a-zA-Z0-9.]+(\$[01])?)?$""")
return pattern.matches(code.trim())
}
Android: поетапна активація з обробкою помилок
EuiccManager.downloadSubscription() — основний метод для carrier-privileged додатків:
private fun activateEsimProfile(activationCode: String) {
val subscription = DownloadableSubscription.forActivationCode(activationCode)
// Флаг switchAfterDownload: true — профіль активується одразу після загрузки
// false — завантажується в disabled стані, активується окремим викликом
euiccManager.downloadSubscription(
subscription,
switchAfterDownload = true,
cancellationSignal = CancellationSignal(),
executor = mainExecutor
) { resultCode, extras ->
when (resultCode) {
EuiccManager.EMBEDDED_SUBSCRIPTION_RESULT_OK -> {
val subscriptionId = extras?.getInt(EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_ID) ?: -1
onActivationSuccess(subscriptionId)
}
EuiccManager.EMBEDDED_SUBSCRIPTION_RESULT_RESOLVABLE_ERROR -> {
// Потребує користувацької дії
val intent = extras?.getParcelable<PendingIntent>(
EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_RESOLUTION_INTENT
)
intent?.send() // Відкриває системний діалог згоди
}
EuiccManager.EMBEDDED_SUBSCRIPTION_RESULT_ERROR -> {
val detailedCode = extras?.getInt(
EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE, -1
) ?: -1
val operationCode = detailedCode and 0xFF
val errorCode = (detailedCode shr 8) and 0xFF
showActivationError(operationCode, errorCode)
}
}
}
}
Детализація помилок через EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE:
| Operation Code | Error Code | Причина | Що сказати користувачу |
|---|---|---|---|
| 1 (DOWNLOAD) | 2 | Неверний activation code | «Перевірте код активації» |
| 1 (DOWNLOAD) | 3 | Код уже використаний | «Цей код уже активований» |
| 2 (INSTALL) | 8 | Нема місця на eUICC | «Видаліть невикористовуваний профіль» |
| 3 (SWITCH) | 1 | Помилка мережі SM-DP+ | «Перевірте підключення до інтернету» |
iOS: системний UI та QR
На iOS без carrier entitlement — тільки системний діалог активації. Відкривається через URL:
func activateViaNativeUI(activationCode: String) {
// Формуємо URL для системної активації
let urlString = "com.apple.esim://\(activationCode)"
if let url = URL(string: urlString), UIApplication.shared.canOpenURL(url) {
UIApplication.shared.open(url) { success in
if success {
// Системний UI відкрився, чекаємо результату через Universal Link callback
startPollingForNewProfile()
}
}
}
}
Після активації через системний UI — нема прямого callback у додаток. Потрібно полити CTSubscriptionManager або слухати сповіщення CTSubscriberTokenRefreshed.
Для carrier додатків з entitlement — CTSubscriptionManagerDelegate:
import CoreTelephony
class ESIMActivationManager: NSObject, CTSubscriptionManagerDelegate {
let subscriptionManager = CTSubscriptionManager()
func activateProfile(activationCode: String) {
subscriptionManager.delegate = self
subscriptionManager.setAccountIdentifier(activationCode)
}
func subscriptionManagerCompleted(_ manager: CTSubscriptionManager) {
DispatchQueue.main.async {
self.handleActivationComplete()
}
}
}
Стани та UX завантаження
Активація eSIM займає від 15 секунд до 3 хвилин — SM-DP+ сервер генерує профіль, LPA завантажує й встановлює (звичайно 300–500 KB зашифрованих даних). За цей час користувач не повинен бачити статичний спиннер.
Правильний UX: кроки з поточним станом:
- Перевірка activation code → Валідація формату
- Підключення до оператора → Запрос до SM-DP+
- Загрузка профіля → Progress bar (якщо LPA надає прогрес)
- Встановлення → Запис у eUICC
- Активація → Переключення на новий профіль
На Android downloadSubscription не надає прогресу по кроках. Фейковий прогрес з оцінкою за часом виглядає краще, ніж статичний спиннер. Реальний прогрес — тільки якщо використовувати власний LPA через TelephonyManager.setPreferredOpportunisticDataSubscription.
Строки
Активація eSIM через Intent/системний UI з обробкою кодів помилок: 1–2 тижні. Повна інтеграція з EuiccManager для carrier-додатку (Android) + CoreTelephony для iOS: 1–3 місяці включаючи узгодження з оператором та доступи.







