Twilio Voice SDK: שילוב שיחות קוליות במובייל
המשתמש מקיש על כפתור השיחה — אבל השיחה לא מתבצעת. או ששיחה נכנסת מגיעה באיחור של 10 שניות. לרוב הבעיה נעוצה בשילוב שגוי של Twilio Voice: Access Token שפג תוקפו, PushKit לא מוגדר, CallKit מופעל בסדר לא נכון. בואו נפרק כיצד להימנע משגיאות אלה.
Twilio Programmable Voice SDK הוא פלטפורמה תעשייתית שמבטלת את הטרחה של שרתי TURN ושרתי מדיה. Twilio מטפל בהובלת מדיה (Opus/DTLS/SRTP) ובניתוב גלובלי דרך 90+ מרכזי נתונים. למפתח נשאר: איתות דרך Twilio, ניהול סשן השמע בפלטפורמה הניידת, ואינטגרציה עם ממשקי שיחות מערכתיים (CallKit ב-iOS, ConnectionService באנדרואיד). יש לנו 5+ פרויקטים מוצלחים של Twilio Voice תחת החגורה, המבטיחים פעילות יציבה בסביבת ייצור.
הגדרת צד שרת: Access Token
Twilio Voice SDK מאמת באמצעות Access Tokens קצרי מועד שנוצרים על ידי השרת שלך באמצעות 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()לקוח הנייד מביא את הטוקן בעת ההפעלה ומחדש אותו לפני פקיעת התוקף. ה-SDK של Twilio מודיע דרך ה-delegate 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() — בשלב זה עליך לבקש טוקן חדש ולקרוא ל-accessTokenInvalidOrExpired. אנו ממליצים על TTL של 3600 שניות — איזון בין אבטחה לתדירות רענון. התיעוד הרשמי של Twilio מאשר גישה זו.
שלבים ליצירת Access Token בשרת:
- צור API Key ב-Twilio Console.
- הגדר TwiML Application עם כתובת webhook.
- כתוב נקודת קצה ב-Node.js/Python שמחזירה JWT עם VoiceGrant.
למה PushKit חובה לשיחות נכנסות ב-iOS
PushKit הוא הדרך האמינה היחידה להעברת שיחה נכנסת בכל מצב של האפליקציה. ערוץ ה-VoIP של APNs מבטיח משלוח בעדיפות גבוהה. ללא 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 לפני updateAccessToken ב-delegate של PushKit גורמת לסיום כפוי של האפליקציה על ידי iOS. זו לא אזהרה, זו קריסה. אינטגרציה עם CallKit דרך 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 } — Twilio מספקת מנהל completion מוכן שמתקשר נכון עם CallKit.
איך לחבר את ConnectionService באנדרואיד
תלות: TVODefaultAudioDevice. ה-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. ה-SDK של Twilio מטפל ב-payload של FCM דרך AVAudioSession:
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 */
}
}מענה לשיחה: com.twilio:voice-android:6.x.x. כדי לעבוד נכון עם ConnectionService, עליך לציין את // Инициализация 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) { /* ошибка */ } }) הנכון ב-manifest — אחרת המערכת לא תוכל להפעיל את השירות.
TwiML וניתוב בצד שרת
שים לב: כאשר לקוח נייד מתקשר דרך Twilio, הבקשה מגיעה ל-webhook של TwiML Application שלך. השרת עונה עם TwiML — הוראות XML עבור Twilio:
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Dial callerId="+1234567890">
<Client>recipient_user_id</Client>
</Dial>
</Response>לשיחות למספרי טלפון רגילים, השתמש ב-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 */ } } . Twilio משמש כמתווך, השרת שלך שולט בלוגיקת הניתוב.
הקלטת שיחות ואנליטיקה
הקלטה דרך TwiML callInvite.accept(context, callListener) או באופן פרוגרמטי דרך REST API — זמינה ללא שינויים ב-SDK. Twilio מאחסן את ההקלטות בשרתיו, ומספק כתובת URL להורדה. אנליטיקת שיחות (משך, איכות, סטטוסים) — דרך Twilio Console או REST API. אנו מגדירים התראה אוטומטית על הקלטות ל-CRM שלך.
Twilio Voice לעומת WebRTC מותאם אישית
| קריטריון | Twilio Programmable Voice | WebRTC מותאם אישית + TURN |
|---|---|---|
| זמן עד לייצור | 1–3 שבועות | 3–6 חודשים |
| תשתית | אפס (מוכן) | שרת TURN, שרת מדיה, WebSocket |
| השהיה נוספת | < 50 ms (PoP הקרוב) | 0 ms (P2P) |
| הקלטת שיחות | מובנית | דורשת פיתוח |
| תמיכה ב-CallKit/ConnectionService | מובנית | דורשת הטמעה |
| עלות לדקה | החל מ-$0.014 | $0.001–0.005 (רק TURN) |
מתי לבחור ב-WebRTC מותאם אישית?
Twilio Voice מוסיף השהיה דרך ממסר — כל זרמי המדיה עוברים דרך מרכזי הנתונים של Twilio, לא P2P. לרוב המשימות זה זניח (< 50 ms השהיה נוספת ב-PoP הקרוב), אבל באזורים ללא מרכז נתונים קרוב של Twilio (מרכז אסיה, חלקים מאפריקה) ההשהיה עשויה להיות מורגשת. עלות: בנפחים גבוהים (10,000+ דקות ביום) WebRTC מותאם אישית + TURN זול יותר, אבל יקר יותר בפיתוח ותחזוקה. אם אתה צריך תקשורת P2P ללא מתווכים — צור קשר, נעזור לך לבחור את הארכיטקטורה.
תהליך האינטגרציה
| שלב | פעולות | משך |
|---|---|---|
| 1. הגדרת חשבון Twilio | TwiML App, API Keys, Push Credentials (FCM/APNs) | יום אחד |
| 2. הטמעת צד שרת | יצירת Access Token, TwiML webhook (Node.js, Python, Go) | 2–5 ימים |
| 3. אינטגרציית SDK | אנדרואיד (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) ובאנדרואיד (Kotlin, ConnectionService).
- הגדרת PushKit (iOS) ו-FCM (אנדרואיד) לשיחות נכנסות.
- בדיקות על מכשירים אמיתיים, תיקון באגים.
- תיעוד אינטגרציה ומדריך תפעול.
- הדרכת צוות (עד שעתיים אונליין).
צור קשר לייעוץ בנושא ארכיטקטורה ותמחור. הזמן אינטגרציית Twilio Voice מאיתנו – קבל שיחות יציבות תוך שבועיים.







