זיהוי כרטיסי eSIM וכרטיסי SIM
מתבצע זיהוי של הכרטיסים
מכשירי Android עם כרטיסי SIM וכרטיסי eSIM משתמשים במזהים הבאים בטלפוניה ממשקי API, כולל [`טלפוניה`](/reference/android/telephony/telephony) וגם [`SubscriptionManager`](/reference/android/telephony/SubscriptionManager): * מזהה מינוי: מזהה ייחודי של מינוי לנייד. * מזהה או אינדקס חריץ לוגי: אינדקס ייחודי המתייחס לחריץ SIM לוגי. מזהי יחידות קיבולת (Slot) לוגיים מתחילים ב-0 ועולים בהתאם למספר משבצות פעילות נתמכות במכשיר. לדוגמה, מכשיר עם SIM כפול בדרך כלל מכיל את חריץ 0 ואת משבצת 1. אם במכשיר יש כמה משבצות פיזיות, אבל רק יש תמיכה ביחידת קיבולת פעילה אחת, יהיה בה רק מזהה החריץ הלוגי 0. * מזהה או אינדקס חריץ פיזי: אינדקס ייחודי המתייחס לחריץ SIM פיזי. מזהי המיקומים הפיזיים מתחילים ב-0 ועולים בהתאם למספר משבצות במכשיר. הערך הזה שונה ממספר המשבצות הלוגיות במכשיר יש, שתואם למספר המשבצות הפעילות שמכשיר יכול להכיל באמצעות. לדוגמה, מכשיר שעובר בין Dual SIM ל-Single-SIM במצב של כרטיס SIM יחיד תמיד יהיו שתי משבצות פיזיות, רק משבצת לוגית אחת. * מזהה הכרטיס: מזהה ייחודי המשמש לזיהוי של כרטיס UiccCard. ![תרשים שממחיש את השימוש במזהים במקרה עם שתי משבצות לוגיות ושלוש משבצות פיזיות](/images/guide/topics/connectivity/tel-ids.png) בתרשים שלמעלה: * במכשיר יש שתי משבצות לוגיות. * במיקום 0 הפיזי יש כרטיס UICC פיזי עם פרופיל פעיל. * במשבצת הפיזית 2 נמצא eUICC עם פרופיל פעיל. * המיקום הפיזי 1 לא בשימוש כרגע. ![תרשים שממחיש את השימוש במזהים במקרה עם שלוש משבצות לוגיות ושתי משבצות פיזיות](/images/guide/topics/connectivity/tel-ids-2.png) בתרשים שלמעלה: * במכשיר יש שלוש משבצות לוגיות. * במיקום 0 הפיזי יש כרטיס UICC פיזי עם פרופיל פעיל. * במיקום 1 הפיזי נמצא eUICC שיש בו שני פרופילים שהורדו, שניהם פעילים באמצעות MEP (פרופילים מרובים שמופעלים).
סקירה כללית של הפרוטוקול להפעלת סשן
מערכת Android מספקת API שתומך בפרוטוקול SIP של סשן. כך אפשר להוסיף לאפליקציות שלך תכונות של טלפוניה באינטרנט שמבוססות על SIP. Android כולל מקבץ מלא של פרוטוקול SIP וניהול שיחות משולב שירותים שמאפשרים לאפליקציות להגדיר בקלות שיחות קוליות יוצאות ונכנסות, ללא צורך בניהול סשנים, תקשורת ברמת התעבורה או אודיו להקליט או להפעיל ישירות.
לפניכם דוגמאות לסוגי האפליקציות שעשויות להשתמש ב-SIP API:
- שיחת ועידה בווידאו
- העברת הודעות מיידית
דרישות ומגבלות
אלו הדרישות לפיתוח אפליקציית SIP:
- מכשיר נייד עם Android מגרסה 2.3 ומעלה צריך להיות.
- SIP פועל באמצעות חיבור נתונים אלחוטי, כך שצריך להיות במכשיר חיבור נתונים חיבור (באמצעות שירות נתונים סלולריים או Wi-Fi). המשמעות היא לא ניתן לבצע בדיקה ב-AVD — אפשר לבדוק רק במכשיר פיזי. פרטים נוספים זמינים במאמר בדיקה של אפליקציות SIP.
- לכל משתתף בפעילות התקשורת של האפליקציה צריך להיות חשבון SIP. יש הרבה ספקי SIP שונים שמציעים חשבונות SIP.
הערה: הספרייה android.net.sip
לא תומכת בהפעלת וידאו
שיחות. אם רוצים להטמיע שיחות VOIP באמצעות מחסנית SIP, כמו
android.net.sip
, אפשר לבחון אחד מ הוספת הקוד הפתוח המודרני
חלופות כבסיס לכל הטמעה של שיחות VOIP. לחלופין,
אפשר ליישם
ConnectionService
API שמאפשר לשלב היטב את הקריאות האלה בחייגן של המכשיר
אפליקציה.
מחלקות וממשקים של SIP API
לפניכם סיכום של הכיתות וממשק אחד
(SipRegistrationListener
) שכלולים ב-SIP של Android
API:
כיתה/ממשק | תיאור |
---|---|
SipAudioCall |
טיפול בשיחת אודיו באינטרנט באמצעות SIP. |
SipAudioCall.Listener |
האזנה לאירועים שקשורים לשיחת SIP, כמו שיחה מכוונת התקבל ('בצלצול') או שמתקיימת שיחה ('בהתקשרות'). |
SipErrorCode |
הגדרת קודי שגיאה שהוחזרו במהלך פעולות SIP. |
SipManager |
מספק ממשקי API למשימות SIP, כמו יצירת חיבורי SIP, ומספק גישה לשירותי SIP קשורים. |
SipProfile |
הגדרת פרופיל SIP, כולל חשבון SIP, דומיין ופרטי שרת. |
SipProfile.Builder |
כיתה לעזרה ביצירת SipProfile. |
SipSession |
מייצג סשן SIP שמשויך לתיבת דו-שיח של SIP או לעסקה עצמאית לא בתוך תיבת דו-שיח. |
SipSession.Listener |
האזנה לאירועים שקשורים לסשן SIP, כמו רישום של סשן ('בהרשמה') או שיוצאת שיחה ('בהתקשרות'). |
SipSession.State |
הגדרת מצבי SIP של סשן, כמו 'הרשמה', 'שיחה יוצאת' ו'בשיחה'. |
SipRegistrationListener |
ממשק שמשמש כ-listener לאירועי רישום ל-SIP. |
יצירת מניפסט
אם אתם מפתחים אפליקציה שמשתמשת ב-SIP API, חשוב לזכור יש תמיכה רק ב-Android 2.3 (רמת API 9) ובגרסאות מתקדמות יותר של הפלטפורמה. כמו כן, במכשירים שבהם פועלת גרסת Android 2.3 (רמת API 9) ומעלה, לא כל המכשירים יציעו תמיכה ב-SIP.
כדי להשתמש ב-SIP, צריך להוסיף את ההרשאות הבאות למניפסט של האפליקציה:
android.permission.USE_SIP
android.permission.INTERNET
כדי לוודא שניתן להתקין את האפליקציה שלך רק במכשירים שיכול לתמוך ב-SIP, צריך להוסיף את הפרטים הבאים מניפסט:
<uses-sdk android:minSdkVersion="9" />
קוד זה מצביע על כך שהאפליקציה שלך דורשת Android 2.3 ומעלה. עבור
מידע נוסף:
רמות API
ואת המסמכים עבור
<uses-sdk>
לרכיב מסוים.
כדי לקבוע איך האפליקציה תסונן ממכשירים שלא תומכים SIP (לדוגמה, ב-Google Play), צריך להוסיף את הפרטים הבאים מניפסט:
<uses-feature android:name="android.software.sip.voip" />
בהודעה כתוב שהאפליקציה משתמשת ב-SIP API. ההצהרה צריכה להיות
לכלול מאפיין android:required
שמציין אם
אני רוצה לסנן את האפליקציה ממכשירים שלא מציעים תמיכה ב-SIP.
יכול להיות שיהיה צורך גם בהצהרות נוספות מ-<uses-feature>
,
בהתאם ליישום שלכם. מידע נוסף זמין במשאבי העזרה
עבור
<uses-feature>
לרכיב מסוים.
אם האפליקציה שלך מיועדת לקבל שיחות, עליך להגדיר גם מקבל (BroadcastReceiver
תת-מחלקה) במניפסט של האפליקציה:
<receiver android:name=".IncomingCallReceiver" android:label="Call Receiver" />
הנה קטעים מתוך המניפסט SipDemo:
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.android.sip"> ... <receiver android:name=".IncomingCallReceiver" android:label="Call Receiver" /> ... <uses-sdk android:minSdkVersion="9" /> <uses-permission android:name="android.permission.USE_SIP" /> <uses-permission android:name="android.permission.INTERNET" /> ... <uses-feature android:name="android.software.sip.voip" android:required="true" /> <uses-feature android:name="android.hardware.wifi" android:required="true" /> <uses-feature android:name="android.hardware.microphone" android:required="true" /> </manifest>
יצירת SipManager
כדי להשתמש ב-SIP API, האפליקציה צריכה ליצור אובייקט SipManager
. יש מסלול SipManager
לבצע את הפעולות הבאות באפליקציה:
- התחלת סשנים של SIP.
- שיחות יוצאות ונכנסות.
- רישום וביטול הרישום אצל ספק SIP.
- מאמת את קישוריות הסשן.
יוצרים SipManager
חדש באופן הבא:
Kotlin
val sipManager: SipManager? by lazy(LazyThreadSafetyMode.NONE) { SipManager.newInstance(this) }
Java
public SipManager sipManager = null; ... if (sipManager == null) { sipManager = SipManager.newInstance(this); }
רישום בשרת SIP
באפליקציית SIP טיפוסית ב-Android משתמש אחד או יותר, שכל אחד מהם
יש חשבון SIP. באפליקציית SIP של Android, כל חשבון SIP
שמיוצג על ידי אובייקט SipProfile
.
SipProfile
מגדיר פרופיל SIP, כולל SIP
החשבון, ופרטי הדומיין והשרת. הפרופיל שמשויך ל-SIP
במכשיר שבו פועלת האפליקציה נקראת התוכנית המקומית
פרופיל. הפרופיל שאליו הסשן מחובר נקרא
פרופיל אפליקציות להשוואה. כשאפליקציית ה-SIP מתחברת לשרת ה-SIP באמצעות
SipProfile
המקומי, זה רושם ביעילות
את המכשיר בתור המיקום שאליו צריך לשלוח שיחות SIP עבור כתובת ה-SIP שלך.
בקטע הזה מוסבר איך ליצור SipProfile
,
לרשום אותו בשרת SIP ולעקוב אחרי אירועי רישום.
יוצרים אובייקט SipProfile
באופן הבא:
Kotlin
private var sipProfile: SipProfile? = null ... val builder = SipProfile.Builder(username, domain) .setPassword(password) sipProfile = builder.build()
Java
public SipProfile sipProfile = null; ... SipProfile.Builder builder = new SipProfile.Builder(username, domain); builder.setPassword(password); sipProfile = builder.build();
קטע הקוד הבא פותח את הפרופיל המקומי לביצוע שיחות ו/או
קבלת שיחות SIP כלליות. המתקשר יוכל לבצע את השיחות הבאות באמצעות
mSipManager.makeAudioCall
הקטע הזה גם מגדיר את הפעולה
android.SipDemo.INCOMING_CALL
, שייעשה בו שימוש על ידי Intent
סינון כשהמכשיר מקבל שיחה (מידע נוסף זמין בקטע הגדרה
מסנן Intent כדי לקבל שיחות). זה שלב הרישום:
Kotlin
val intent = Intent("android.SipDemo.INCOMING_CALL") val pendingIntent: PendingIntent = PendingIntent.getBroadcast(this, 0, intent, Intent.FILL_IN_DATA) sipManager?.open(sipProfile, pendingIntent, null)
Java
Intent intent = new Intent(); intent.setAction("android.SipDemo.INCOMING_CALL"); PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, intent, Intent.FILL_IN_DATA); sipManager.open(sipProfile, pendingIntent, null);
לבסוף, הקוד הזה מגדיר SipRegistrationListener
ב-SipManager
. כאן אפשר לבדוק אם SipProfile
נרשם בהצלחה בשירות ה-SIP
ספק:
Kotlin
sipManager?.setRegistrationListener(sipProfile?.uriString, object : SipRegistrationListener { override fun onRegistering(localProfileUri: String) { updateStatus("Registering with SIP Server...") } override fun onRegistrationDone(localProfileUri: String, expiryTime: Long) { updateStatus("Ready") } override fun onRegistrationFailed( localProfileUri: String, errorCode: Int, errorMessage: String ) { updateStatus("Registration failed. Please check settings.") } })
Java
sipManager.setRegistrationListener(sipProfile.getUriString(), new SipRegistrationListener() { public void onRegistering(String localProfileUri) { updateStatus("Registering with SIP Server..."); } public void onRegistrationDone(String localProfileUri, long expiryTime) { updateStatus("Ready"); } public void onRegistrationFailed(String localProfileUri, int errorCode, String errorMessage) { updateStatus("Registration failed. Please check settings."); } }
כשהאפליקציה מסתיימת באמצעות פרופיל, היא אמורה להיסגר כדי לפנות של האובייקטים המשויכים לזיכרון, ומבטלים את רישום המכשיר מהשרת. עבור דוגמה:
Kotlin
fun closeLocalProfile() { try { sipManager?.close(sipProfile?.uriString) } catch (ee: Exception) { Log.d("WalkieTalkieActivity/onDestroy", "Failed to close local profile.", ee) } }
Java
public void closeLocalProfile() { if (sipManager == null) { return; } try { if (sipProfile != null) { sipManager.close(sipProfile.getUriString()); } } catch (Exception ee) { Log.d("WalkieTalkieActivity/onDestroy", "Failed to close local profile.", ee); } }
התחלת שיחת אודיו
כדי לבצע שיחת אודיו, אתם צריכים שיהיו לכם:
SipProfile
שמבצע את השיחה 'פרופיל מקומי') וכתובת SIP חוקית לקבלת השיחה 'פרופיל אפליקציות להשוואה').- אובייקט
SipManager
.
כדי לבצע שיחת אודיו, עליך להגדיר SipAudioCall.Listener
. חלק גדול מהאינטראקציה של הלקוח עם
סטאק ה-SIP מתבצע דרך מאזינים. בקטע הקוד הזה אפשר לראות איך SipAudioCall.Listener
מגדיר את ההגדרות אחרי השיחה
נוצרה:
Kotlin
var listener: SipAudioCall.Listener = object : SipAudioCall.Listener() { override fun onCallEstablished(call: SipAudioCall) { call.apply { startAudio() setSpeakerMode(true) toggleMute() } } override fun onCallEnded(call: SipAudioCall) { // Do something. } }
Java
SipAudioCall.Listener listener = new SipAudioCall.Listener() { @Override public void onCallEstablished(SipAudioCall call) { call.startAudio(); call.setSpeakerMode(true); call.toggleMute(); ... } @Override public void onCallEnded(SipAudioCall call) { // Do something. } };
אחרי ההגדרה של SipAudioCall.Listener
, אפשר
להתקשר. השיטה SipManager
הפונקציה makeAudioCall
מקבלת את הפרמטרים הבאים:
- פרופיל SIP מקומי (המתקשר).
- פרופיל SIP של עמית (למשתמש שאליו מתבצעת התקשרות).
SipAudioCall.Listener
כדי להאזין לשיחה אירועים מ-SipAudioCall
. זה יכול להיותnull
, אבל כפי שמתואר למעלה, ה-listener משמש כדי להגדיר דברים ברגע שהשיחה נוצרה.- ערך הזמן הקצוב לתפוגה, בשניות.
לדוגמה:
Kotlin
val call: SipAudioCall? = sipManager?.makeAudioCall( sipProfile?.uriString, sipAddress, listener, 30 )
Java
call = sipManager.makeAudioCall(sipProfile.getUriString(), sipAddress, listener, 30);
מקבל שיחות
כדי לקבל שיחות, אפליקציית SIP צריכה לכלול מחלקה משנית של BroadcastReceiver
עם יכולת להגיב ל-Intent
שמציין שיש שיחה נכנסת. לכן צריך לבצע את הפעולות הבאות
את האפליקציה שלך:
- ב
AndroidManifest.xml
, צריך להצהיר על<receiver>
. ב-SipDemo<receiver android:name=".IncomingCallReceiver" android:label="Call Receiver" />
. - מטמיעים את המקבל, שהוא מחלקה משנית של
BroadcastReceiver
. ב-SipDemoIncomingCallReceiver
. - הפעלת הפרופיל המקומי (
SipProfile
) באמצעות כוונת רכישה בהמתנה, שמפעילה את המקבל כשמישהו מתקשר לפרופיל המקומי. - מגדירים מסנן Intent שמסננים לפי הפעולה שמייצגת
שיחה נכנסת. ב-SipDemo, הפעולה הזו:
android.SipDemo.INCOMING_CALL
.
קבלן שידור לסיווג משנה
כדי לקבל שיחות, אפליקציית ה-SIP שלך חייבת להשתמש במחלקה משנית: BroadcastReceiver
.
מערכת Android מטפלת בשיחות SIP נכנסות ובשידור
קריאה ל-Intent '' (כפי שמוגדר באפליקציה) כשהוא מקבל
שיחה. הנה המחלקה המשנית:
BroadcastReceiver
מדוגמת SipDemo.
Kotlin
/** * Listens for incoming SIP calls, intercepts and hands them off to WalkieTalkieActivity. */ class IncomingCallReceiver : BroadcastReceiver() { /** * Processes the incoming call, answers it, and hands it over to the * WalkieTalkieActivity. * @param context The context under which the receiver is running. * @param intent The intent being received. */ override fun onReceive(context: Context, intent: Intent) { val wtActivity = context as WalkieTalkieActivity var incomingCall: SipAudioCall? = null try { incomingCall = wtActivity.sipManager?.takeAudioCall(intent, listener) incomingCall?.apply { answerCall(30) startAudio() setSpeakerMode(true) if (isMuted) { toggleMute() } wtActivity.call = this wtActivity.updateStatus(this) } } catch (e: Exception) { incomingCall?.close() } } private val listener = object : SipAudioCall.Listener() { override fun onRinging(call: SipAudioCall, caller: SipProfile) { try { call.answerCall(30) } catch (e: Exception) { e.printStackTrace() } } } }
Java
/** * Listens for incoming SIP calls, intercepts and hands them off to WalkieTalkieActivity. */ public class IncomingCallReceiver extends BroadcastReceiver { /** * Processes the incoming call, answers it, and hands it over to the * WalkieTalkieActivity. * @param context The context under which the receiver is running. * @param intent The intent being received. */ @Override public void onReceive(Context context, Intent intent) { SipAudioCall incomingCall = null; try { SipAudioCall.Listener listener = new SipAudioCall.Listener() { @Override public void onRinging(SipAudioCall call, SipProfile caller) { try { call.answerCall(30); } catch (Exception e) { e.printStackTrace(); } } }; WalkieTalkieActivity wtActivity = (WalkieTalkieActivity) context; incomingCall = wtActivity.sipManager.takeAudioCall(intent, listener); incomingCall.answerCall(30); incomingCall.startAudio(); incomingCall.setSpeakerMode(true); if(incomingCall.isMuted()) { incomingCall.toggleMute(); } wtActivity.call = incomingCall; wtActivity.updateStatus(incomingCall); } catch (Exception e) { if (incomingCall != null) { incomingCall.close(); } } } }
הגדרה של מסנן Intent לקבלת שיחות
כששירות SIP מקבל שיחה חדשה, הוא שולח Intent עם
מחרוזת הפעולה שסופקה על ידי האפליקציה. ב-SipDemo, מחרוזת הפעולה הזו היא
android.SipDemo.INCOMING_CALL
קטע הקוד מתוך SipDemo מראה איך האובייקט SipProfile
נוצר עם Intent בהמתנה, על סמך
מחרוזת הפעולה android.SipDemo.INCOMING_CALL
.
האובייקט PendingIntent
יבצע שידור כאשר SipProfile
יקבל קריאה:
Kotlin
val sipManager: SipManager? by lazy(LazyThreadSafetyMode.NONE) { SipManager.newInstance(this) } var sipProfile: SipProfile? = null ... val intent = Intent("android.SipDemo.INCOMING_CALL") val pendingIntent: PendingIntent = PendingIntent.getBroadcast(this, 0, intent, Intent.FILL_IN_DATA) sipManager?.open (sipProfile, pendingIntent, null)
Java
public SipManager sipManager = null; public SipProfile sipProfile = null; ... Intent intent = new Intent(); intent.setAction("android.SipDemo.INCOMING_CALL"); PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, intent, Intent.FILL_IN_DATA); sipManager.open(sipProfile, pendingIntent, null);
השידור ייקלט על ידי מסנן Intent, שלאחר מכן יופעל
הנמען (IncomingCallReceiver
). אפשר לציין כוונה
לבצע סינון בקובץ המניפסט של האפליקציה, או לבצע את הפעולה בקוד כמו ב-SipDemo
דוגמה ל-method של onCreate()
של האפליקציה
של Activity
האפליקציה:
Kotlin
class WalkieTalkieActivity : Activity(), View.OnTouchListener { ... lateinit var callReceiver: IncomingCallReceiver ... override fun onCreate(savedInstanceState: Bundle) { val filter = IntentFilter().apply { addAction("android.SipDemo.INCOMING_CALL") } callReceiver = IncomingCallReceiver() this.registerReceiver(callReceiver, filter) ... } ... }
Java
public class WalkieTalkieActivity extends Activity implements View.OnTouchListener { ... public IncomingCallReceiver callReceiver; ... @Override public void onCreate(Bundle savedInstanceState) { IntentFilter filter = new IntentFilter(); filter.addAction("android.SipDemo.INCOMING_CALL"); callReceiver = new IncomingCallReceiver(); this.registerReceiver(callReceiver, filter); ... } ... }
בדיקה של אפליקציות SIP
כדי לבדוק אפליקציות SIP, צריך:
- מכשיר נייד עם Android 2.3 ומעלה. הרצת SIP בחיבור אלחוטי, כך שעליך לבדוק במכשיר אמיתי. הבדיקה ב-AVD לא תעבוד.
- חשבון SIP. יש הרבה ספקי SIP שונים שמציעים חשבונות SIP.
- אם מבצעים שיחה, גם השיחה צריכה להיות לחשבון SIP תקין.
כדי לבדוק אפליקציית SIP:
- במכשיר, התחברות לרשת אלחוטית (הגדרות > רשתות ותקשורת אלחוטית) > Wi-Fi > הגדרות Wi-Fi).
- מגדירים את המכשיר הנייד לבדיקה, כפי שמתואר במאמר פיתוח במכשיר.
- מריצים את האפליקציה במכשיר הנייד, כפי שמתואר במאמר פיתוח במכשיר.
- אם משתמשים ב-Android Studio, אפשר לצפות בפלט של יומן האפליקציות על ידי פותחים את המסוף 'יומן אירועים' (תצוגה > חלונות של כלים > יומן אירועים).
- ודא שהאפליקציה שלך מוגדרת להפעלת Logcat באופן אוטומטי כאשר היא רצה:
- בוחרים באפשרות הפעלה > עורכים את ההגדרות האישיות.
- בוחרים בכרטיסייה שונות בחלון הפעלה/ניפוי באגים.
- בקטע Logcat, בוחרים באפשרות Show Logcat יופעל באופן אוטומטי, ולאחר מכן לוחצים על OK (אישור).