לעתים קרובות אנו רואים אפליקציות VoIP נאבקות עם המערכת: מסך שיחה מותאם אישית, בעיות מיקוד שמע, חוסר אינטגרציה עם Bluetooth. משתמשים מצפים ששיחות אפליקציה יתנהגו כמו שיחות רגילות — יופיעו על מסך הנעילה, ישהקו מוזיקה, ויופיעו ביומן השיחות. זה בדיוק מה ש-ConnectionService — רכיב של Android Telecom Framework — מספק. הוא מאפשר לאפליקציה שלך להפוך לספק טלפון מלא. היישום דורש הקפדה מדויקת על מחזור החיים של Connection ועבודה עם PhoneAccount. במאמר זה, אנו חולקים ניסיון מלמעלה מ-50 פרויקטים ומסבירים כיצד להימנע ממלכודות נפוצות.
80% מהמשתמשים מצפים להתנהגות שיחה מקורית — מסך מערכת, השהיית מוזיקה אוטומטית, רישום היסטוריה. ללא ConnectionService, עליך ליישם את כל זה ידנית, וכל יצרן מכשירים (Samsung, Xiaomi, OPPO) מוסיף מוזרויות משלו. בדקנו אינטגרציה על יותר מ-30 מכשירים אמיתיים וזיהינו 5 בעיות טיפוסיות שהגישה שלנו פותרת.
כיצד פועל ConnectionService
ConnectionService הוא מחלקה מופשטת מחבילת android.telecom. האפליקציה שלך יורשת ממנה ורושמת את היישום במניפסט כ-<service> עם הרשאת android.permission.BIND_TELECOM_CONNECTION_SERVICE. מערכת Telecom קוראת ל-callbacks של השירות עבור שיחות נכנסות ויוצאות.
האובייקט המרכזי הוא Connection. עבור כל שיחה, נוצר מופע Connection נפרד עם קבוצת מצבים:
NEW → DIALING → RINGING → ACTIVE → HOLDING → DISCONNECTED כל מעבר דורש קריאה מפורשת למתודה המתאימה: NEW → DIALING → RINGING → ACTIVE → HOLDING → DISCONNECTED , setDialing(), setRinging(), setActive(), setOnHold(). אם מעבר לא מופעל, המערכת מחשיבה את השיחה כתקועה. זו אחת הטעויות הנפוצות ביותר ביישומים ראשוניים: מחסנית ה-VoIP מקבלת תגובת שרת, אך ה-Connection נשאר ב-DIALING לנצח.
setDisconnected(DisconnectCause) — מזהה הספק במערכת. הוא נרשם דרך PhoneAccount. הוא דורש אייקון, תווית, סכמות URI נתמכות (TelecomManager.registerPhoneAccount(), tel, או מותאמות אישית), ודגלי יכולות (sip, CAPABILITY_CALL_PROVIDER וכו').
המשתמש חייב להפעיל במפורש את PhoneAccount בהגדרות המערכת — האפליקציה לא יכולה לעשות זאת אוטומטית. ההשקה הראשונה דורשת ניווט אל CAPABILITY_VIDEO_CALLING. זהו היבט UX שדורש עיצוב נפרד.
| מצב Connection | מתודת מעבר | תיאור |
|---|---|---|
| NEW | - | מצב התחלתי |
| DIALING | setDialing() | שיחה יוצאת |
| RINGING | setRinging() | שיחה נכנסת |
| ACTIVE | setActive() | שיחה פעילה |
| HOLDING | setOnHold() | המתנה |
| DISCONNECTED | setDisconnected() | הסתיימה |
מדוע מיקוד שמע הוא קריטי
שים לב: כאשר Connection עובר ל-ACTIVE, המערכת מצפה שהאפליקציה תיקח מיקוד שמע ותגדיר ניתוב שמע. זה נעשה דרך Settings → Apps → [Приложение] → Phone accounts עם AudioManager.requestAudioFocus() (API 26+) או AudioFocusRequest. ללא זה, אפליקציות אחרות (נגן מוזיקה, ניווט) לא יקבלו אות השהיה.
מעבר בין רמקול, אוזניות ו-Bluetooth — דרך AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE. המערכת מעבירה ConnectionService.onCallAudioStateChanged() עם הניתוב הנוכחי ו-bitmask של ניתובים זמינים. האפליקציה חייבת לסנכרן את מצבה עם המערכת. טעות נפוצה היא שהאפליקציה משנה את הניתוב ישירות דרך CallAudioState, תוך התעלמות מ-AudioManager, והמערכת מציגה מצבי כפתורים שגויים בממשק המערכת.
היכן רוב היישומים נשברים
שיחה נכנסת על מסך הנעילה
שיחה נכנסת שיזמה האפליקציה דרך CallAudioState חייבת להיות מלווה ב-TelecomManager.addNewIncomingCall() — או מסך שיחות מערכת או IncomingCallUi מותאם אישית עם דגלים Activity. מ-API 27, השתמש ב-FLAG_SHOW_WHEN_LOCKED | FLAG_TURN_SCREEN_ON | FLAG_KEEP_SCREEN_ON ו-setShowWhenLocked(true) על ה-Activity.
עבור התראות שיחה נכנסת מ-API 31, נדרש setTurnScreenOn(true) — בלעדיו, המערכת עלולה לא להציג full-screen intent בחלק מהמכשירים. ב-Samsung One UI, ההתנהגות שונה מ-AOSP: ה-full-screen intent לפעמים מתעלמים ממנו לטובת מגש ההתראות של המערכת.
המתנה ושיחת ועידה
Notification.CallStyle.forIncomingCall() על Connection פירושו שניתן להשהות את השיחה. אבל אם הקצה האחורי של VoIP אינו תומך בהשהיה דרך SIP CAPABILITY_HOLD עם re-INVITE — יש להסיר את היכולת, אחרת המערכת תשלח a=sendonly, והאפליקציה לא תוכל לבצע אותה. שיחת ועידה דרך אובייקט Conference היא מורכבות נפרדת: ניהול משתתפים, מיזוג, החלפה.
Android Auto ו-WearOS
ConnectionService משתלב אוטומטית עם Android Auto — ממשק מערכת הרכב יציג כרטיס שיחה. אבל אם האפליקציה עוקפת ניתוב שמע ישירות, זה מתנגש עם פרופילי HFP Bluetooth. בדיקות באמולטור Android Auto הן חובה.
כיצד ליישם ConnectionService ב-5 שלבים
- צור מחלקה המרחיבה את ConnectionService. יישם מתודות
onHold(),onCreate(),onBind(),onCreateOutgoingConnection(). -
רשום את השירות ב-
onCreateIncomingConnection()עם הרשאתAndroidManifest.xmlו-intent-filter עבורBIND_TELECOM_CONNECTION_SERVICE. - צור ורשום PhoneAccount דרך TelecomManager. ציין אייקון, תווית, סכמות URI ודגלים.
- יישם את מחזור החיים של Connection: טיפול בכל המצבים, DTMF, השהיה.
- טפל במיקוד שמע וניתוב: בקש מיקוד שמע ב-ACTIVE, הגב ל-CallAudioState.
הרשאות ומגבלות
| הרשאה | מטרה |
|---|---|
android.telecom.ConnectionService |
קבלת מצב טלפון |
READ_PHONE_STATE |
ניהול שיחות ללא רישום ספק |
MANAGE_OWN_CALLS |
לכידת מיקרופון |
RECORD_AUDIO |
חובה לשירות במניפסט |
BIND_TELECOM_CONNECTION_SERVICE |
Full-screen intent (Android 10+) |
במכשירים עם ממשקים מותאמים אישית (MIUI, One UI, ColorOS), התנהגות USE_FULL_SCREEN_INTENT שונה מ-AOSP. בדיקות רק באמולטור אינן מספיקות — יש צורך במכשירי Xiaomi, Samsung, OPPO אמיתיים.
מקרה בוחן: אפליקציית ייעוץ רפואי
לאחרונה שילבנו את ConnectionService עבור אפליקציית ייעוץ רפואי. הבעיה: שיחות נכנסות לא הוצגו על מסך הנעילה, מה שגרם לרופאים לפספס שיחות חשובות. הסיבה הייתה שימוש שגוי ב-TelecomManager והיעדר IncomingCallUi. הוספנו Activity עם דגלים והחלפנו את ההתראה הרגילה ב-setShowWhenLocked. כתוצאה מכך, זמן התגובה לשיחות ירד ב-40%, והשיחות שהוחמצו צומצמו בחצי. חשוב לציין, הגדרנו מיקוד שמע ללכידה בלעדית — כעת המוזיקה מושהית אוטומטית. ConnectionService מאיץ את האינטגרציה פי 3 בהשוואה לממשק מותאם אישית.
תהליך ולוח זמנים
יישום ConnectionService כולל מספר שלבים: עיצוב ארכיטקטורה (כיצד מחסנית ה-VoIP מאותתת שיחות ל-ConnectionService), יישום מחזור החיים של Connection, אינטגרציית ממשק משתמש, בדיקות ניתוב שמע במספר מכשירים.
האינטגרציה תלויה במחסנית ה-VoIP הקיימת: אם משתמשים במחסנית SIP מוכנה (LinphoneSDK, PJSIP דרך wrapper של Android, WebRTC דרך libwebrtc של Google), יש לתרגם את האירועים שלה למעברי Connection. אם המחסנית מפותחת מאפס, לוחות הזמנים גדלים משמעותית.
הערכה: 2-3 שבועות לאינטגרציה בסיסית של שיחות נכנסות/יוצאות עם ממשק מערכת, 4-6 שבועות לפונקציונליות מלאה עם השהיה, ועידה, DTMF, Android Auto. העלות מחושבת בנפרד לאחר ניתוח מחסנית ה-VoIP הקיימת והדרישות.
מה כלול
- יישום ConnectionService התומך בשיחות נכנסות ויוצאות
- רישום PhoneAccount עם הגדרת סכמת URI
- טיפול במיקוד שמע וניתוב (רמקול, Bluetooth, אוזניות)
- אינטגרציה עם יומן השיחות של המערכת
- בדיקות על 5+ מכשירים אמיתיים (Samsung, Xiaomi, OPPO, Pixel)
- תיעוד תפעולי ותמיכה של שבועיים לאחר המסירה
צור קשר להערכת פרויקט חינמית. הזמן אינטגרציה סוהר — קבל פתרון מוכן לשימוש עם אחריות לתפקוד.
לפרטים נוספים, ראה תיעוד רשמי: מסמכי מפתחי Android — Android Telecom Framework.







