Реалізація перемикання eSIM-профілів через мобільний додаток
Перемикання між встановленими eSIM-профілями простіше за активацію — профіль вже є на eUICC, потрібно лише змінити активний. Але й тут платформи додають складнощів: iOS вимагає підтвердження користувача через системний діалог, Android на деяких пристроях перезавантажує радіомодуль, що займає 10–30 секунд з втратою зв'язку.
Android: EuiccManager.switchToSubscription
fun switchToProfile(subscriptionId: Int) {
// subscriptionId отримуємо з SubscriptionManager
val activeSubInfo = subscriptionManager.activeSubscriptionInfoList
val currentEsimId = activeSubInfo?.firstOrNull { it.isEmbedded }?.subscriptionId
if (currentEsimId == subscriptionId) {
showMessage("Цей профіль вже активний")
return
}
euiccManager.switchToSubscription(
subscriptionId,
PendingIntent.getBroadcast(
context,
REQUEST_CODE_SWITCH,
Intent(ACTION_ESIM_SWITCH_COMPLETE),
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
)
)
}
// BroadcastReceiver для обробки результату
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 не приймає callback напряму — лише PendingIntent. Це не баг: операція асинхронна і може вимагати взаємодії з користувачем. Результат приходить у BroadcastReceiver.
Перемикання без системного UI (privileged)
На Samsung та деяких інших виробниках доступно через android.telephony.euicc.EuiccManager.switchToSubscription(int, boolean) з прапорцем forceDeactivateSim = true. Працює лише для додатків з WRITE_EMBEDDED_SUBSCRIPTIONS.
// Samsung-специфічний прапорець для перемикання без діалогу
if (Build.MANUFACTURER.equals("samsung", ignoreCase = true)) {
euiccManager.switchToSubscription(
subscriptionId,
forceDeactivateSim = true, // Не питати користувача
callbackIntent = pendingIntent
)
}
Важливо: на деяких Qualcomm-пристроях після switchToSubscription радіомодуль перезавантажується без попередження. Попереджайте користувача заздалегідь: «Після перемикання на 15–30 секунд зникне зв'язок».
iOS: лише через Settings або carrier entitlement
На iOS програмне перемикання між eSIM-профілями недоступне для звичайних додатків. Є два варіанти:
Посилання в Settings: UIApplication.shared.open(URL(string: "App-Prefs:root=Cellular")!) — відкриває розділ «Стільниковий зв'язок» у налаштуваннях, де користувач сам перемикає. Не найкращий UX, але єдиний шлях без entitlement.
Carrier entitlement + CTSubscriptionManager: доступно лише для операторських додатків з com.apple.developer.CoreTelephony.Subscriber entitlement. Надається Apple лише ліцензованим операторам:
import CoreTelephony
let subscriptionManager = CTSubscriptionManager()
// Отримання списку профілів
let subscriptions = subscriptionManager.subscriptions
// subscriptions: [String: CTSubscriber] — key це subscriber ID
// Для перемикання — лише через системний UI або оператора
// Прямого API для switch без entitlement немає
Отримання списку встановлених профілів
Android:
fun getInstalledEsimProfiles(): List<SubscriptionInfo> {
val allSubs = subscriptionManager.availableSubscriptionInfoList ?: emptyList()
return allSubs.filter { it.isEmbedded }
.map { sub ->
// sub.displayName — ім'я оператора
// sub.simSlotIndex: -1 якщо профіль inactive, >= 0 якщо active
// sub.iccId — унікальний ідентифікатор профілю
sub
}
}
simSlotIndex == -1 для inactive профілів — важливо для відображення статусу у списку.
iOS (без entitlement):
import CoreTelephony
func getActiveCarriers() -> [CTCarrier] {
let networkInfo = CTTelephonyNetworkInfo()
return networkInfo.serviceSubscriberCellularProviders?.values
.compactMap { $0 }
.filter { $0.carrierName != nil }
?? []
}
Лише активні профілі. Список усіх встановлених (включаючи неактивні) — недоступний без carrier entitlement.
UX перемикання
Час перемикання: Android — 10–30 секунд (radio reboot на Qualcomm, швидше на MTK). iOS через Settings — не контрольовано. Показувати прогрес-індикатор з попередженням про тимчасову втрату зв'язку.
Після успішного перемикання перевіряти новий активний профіль через SubscriptionManager.getActiveSubscriptionInfo(newSubscriptionId) — переконатися що перемикання завершено перед оновленням UI.
Терміни
Android: перемикання між профілями з BroadcastReceiver та обробкою помилок — 1–2 тижні. iOS: deeplink в Settings + відображення поточних профілів — 3–5 днів. Carrier-grade рішення для обох платформ з повним контролем через entitlement: 1–2 місяці.







