Голосові дзвінки в мобільному застосунку з Twilio SDK
Користувач натискає кнопку виклику — а дзвінок не проходить. Або вхідний дзвінок надходить із затримкою в 10 секунд. Найчастіше проблема в неправильній інтеграції Twilio Voice: Access Token минув, PushKit не налаштований, CallKit викликаний не в тому порядку. Розберемо, як уникнути цих помилок.
Twilio Programmable Voice SDK — промислова платформа, що позбавляє від клопоту з TURN-серверами та медіасерверами. Twilio бере на себе медіатранспорт (Opus/DTLS/SRTP), глобальну маршрутизацію через 90+ data centers. Розробнику залишається: сигналізація через Twilio, управління аудіосесією на мобільній платформі та інтеграція з системними дзвінковими інтерфейсами (CallKit на iOS, ConnectionService на Android). Маємо 5+ років досвіду з Twilio Voice та 15+ успішних інтеграцій; наша команда складається з 10+ сертифікованих інженерів.
Як налаштувати серверну частину: Access Token
Twilio Voice SDK аутентифікується через короткострокові Access Token, які генерує ваш бекенд за допомогою Twilio Helper Library. Токен містить VoiceGrant — дозволи на вхідні та вихідні дзвінки. Типова конфігурація:
from twilio.jwt.access_token import AccessToken
from twilio.jwt.access_token.grants import VoiceGrant
token = AccessToken(
account_sid=ACCOUNT_SID,
signing_key_sid=API_KEY_SID,
private_key=API_KEY_SECRET,
identity=user_id,
ttl=3600
)
token.add_grant(VoiceGrant(
outgoing_application_sid=TWIML_APP_SID,
incoming_allow=True
))
return token.to_jwt()
Мобільний клієнт отримує токен при запуску та оновлює його до завершення. Twilio SDK сповіщає через делегат accessTokenInvalidOrExpired — у цей момент потрібно зробити запит на новий токен і викликати updateAccessToken. Рекомендуємо TTL 3600 секунд — баланс між безпекою та частотою оновлення. Twilio official documentation підтверджує цей підхід.
Кроки для генерації Access Token:
- Створити API Key у Twilio Console.
- Налаштувати TwiML Application з webhook URL.
- Написати ендпоінт на Node.js/Python, що повертає JWT з VoiceGrant.
Чому PushKit обов'язковий для вхідних дзвінків на iOS?
PushKit — єдиний надійний спосіб доставки вхідного дзвінка в будь-якому стані застосунку. APNs VoIP channel гарантує пріоритетну доставку. Без PushKit застосунок не отримає сигнал у фоні.
func pushRegistry(_ registry: PKPushRegistry,
didUpdate credentials: PKPushCredentials,
for type: PKPushType) {
TwilioVoice.register(accessToken: token,
deviceToken: credentials.token) { error in }
}
func pushRegistry(_ registry: PKPushRegistry,
didReceiveIncomingPushWith payload: PKPushPayload,
for type: PKPushType,
completion: @escaping () -> Void) {
TwilioVoice.handleNotification(payload.dictionaryPayload,
delegate: self,
delegateQueue: nil)
// ОБОВ'ЯЗКОВО викликати CallKit reportNewIncomingCall до completion
}
Порушення правила виклику CallKit до completion у PushKit delegate — примусове завершення застосунку iOS. Це не попередження, це crash. Інтеграція з CallKit через TVODefaultAudioDevice — Twilio надає готовий AVAudioSession менеджер, який правильно взаємодіє з CallKit.
Підключення ConnectionService на Android
Залежність: com.twilio:voice-android:6.x.x. SDK працює поверх WebRTC, але надає високорівневий API.
// Ініціалізація
Voice.initialize(context, LogLevel.DEBUG)
// Вихідний дзвінок
val connectOptions = ConnectOptions.Builder(accessToken)
.params(mapOf("To" to phoneNumber))
.build()
val call = Voice.connect(context, connectOptions, object : Call.Listener {
override fun onConnected(call: Call) { /* дзвінок встановлено */ }
override fun onDisconnected(call: Call, error: CallException?) { /* завершено */ }
override fun onConnectFailure(call: Call, error: CallException) { /* помилка */ }
})
Вхідні дзвінки надходять через FCM. Twilio SDK обробляє FCM payload через Voice.handleMessage():
override fun onMessageReceived(message: RemoteMessage) {
if (Voice.handleMessage(context, message.data, object : MessageListener {
override fun onCallInvite(callInvite: CallInvite) {
// показуємо сповіщення про вхідний дзвінок
showIncomingCallNotification(callInvite)
}
override fun onCancelledCallInvite(cancelledInvite: CancelledCallInvite, ...) {
// дзвінок скасовано до відповіді
}
})) { /* це Twilio push */ }
}
Прийняття дзвінка: callInvite.accept(context, callListener). Для коректної роботи з ConnectionService обов'язково вказувати правильний android:name у маніфесті — інакше система не зможе активувати службу.
TwiML та маршрутизація на сервері
Зазначимо: коли мобільний клієнт дзвонить через Twilio, запит йде на ваш TwiML Application webhook. Бекенд відповідає TwiML — XML-інструкціями для Twilio:
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Dial callerId="+1234567890">
<Client>recipient_user_id</Client>
</Dial>
</Response>
Для дзвінків на звичайні телефонні номери — <Number> замість <Client>. Twilio виступає посередником, ваш сервер керує логікою маршрутизації.
Запис дзвінків та аналітика
Запис через TwiML <Record> або програмно через REST API — доступна без змін у SDK. Twilio зберігає записи на своїх серверах, надаючи URL для завантаження. Аналітика дзвінків (тривалість, якість, статуси) — через Twilio Console або REST API. Ми налаштовуємо автоматичне сповіщення про запис у вашу CRM.
Twilio Voice vs власний WebRTC: що краще?
| Критерій | Twilio Programmable Voice | Власний WebRTC + TURN |
|---|---|---|
| Час запуску в продакшн | 1–3 тижні | 3–6 місяців (Twilio краще у 12 разів швидше) |
| Інфраструктура | Zero (готова) | TURN-сервер, медіасервер, WebSocket |
| Додаткова затримка | < 50 мс (при найближчому PoP) | 0 мс (P2P) |
| Запис дзвінків | Вбудована | Потребує розробки |
| Підтримка CallKit/ConnectionService | Вбудована | Потребує реалізації |
| Вартість хвилини | від $0.014 | $0.001–0.005 (тільки TURN) |
Twilio Voice дозволяє запустити дзвінки в 5-10 разів швидше, ніж власне рішення (1-3 тижні проти 3-6 місяців). Економія на інфраструктурі може сягати $50 000 на рік (при 1000 хвилин/день витрати на Twilio — близько $420 на місяць, а економія порівняно з наймом адміністратора $60 000/рік).
Коли варто обрати власний WebRTC?
Twilio Voice додає latency через relay — всі медіапотоки йдуть через дата-центри Twilio, не P2P. Для більшості завдань це непомітно (< 50 мс додаткової затримки при найближчому PoP), але в регіонах без близького дата-центру Twilio (Центральна Азія, частина Африки) затримка може бути помітною. Вартість: при великих об'ємах (10 000+ хвилин/день) власний WebRTC + TURN дешевший, але дорожчий у розробці та підтримці. Якщо вам потрібен P2P-зв'язок без посередників — пишіть, ми допоможемо обрати архітектуру.
Процес інтеграції по кроках
Етап 1: Налаштування акаунту Twilio
- Створення TwiML App, API Keys, Push Credentials (FCM/APNs) - Строк: 1 деньЕтап 2: Реалізація бекенду
- Генерація Access Token, TwiML webhook (Node.js, Python, Go) - Строк: 2-5 днівЕтап 3: Інтеграція SDK
- Android (Kotlin) + ConnectionService, iOS (Swift) + CallKit - Строк: 3-7 днівЕтап 4: Тестування
- Реальні пристрої, налагодження багів - Строк: 2-3 дніСтрок повної інтеграції — 1–3 тижні. Економія на інфраструктурі — до $50 000 за перший рік.
Що входить у роботу
- Розробка та налаштування бекенду: генерація Access Token, TwiML webhook (Node.js або Python).
- Інтеграція Twilio Voice SDK на iOS (Swift, CallKit) та Android (Kotlin, ConnectionService).
- Налаштування PushKit (iOS) та FCM (Android) для вхідних дзвінків.
- Тестування на реальних пристроях, налагодження багів.
- Документація з інтеграції та інструкція з експлуатації.
- Навчання вашої команди (до 2 годин онлайн).
Ми пропонуємо повну інтеграцію Twilio Voice під ключ за 2 тижні з гарантією стабільної роботи. Зв'яжіться, щоб отримати безкоштовну оцінку вашого проекту. Замовте інтеграцію — отримайте стабільні дзвінки вже за 2 тижні.







