סקירה כללית של הפרוטוקול להפעלת סשן

זיהוי כרטיסי 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. ב-SipDemo IncomingCallReceiver.
  • הפעלת הפרופיל המקומי (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:

  1. במכשיר, התחברות לרשת אלחוטית (הגדרות > רשתות ותקשורת אלחוטית) &gt; Wi-Fi > הגדרות Wi-Fi).
  2. מגדירים את המכשיר הנייד לבדיקה, כפי שמתואר במאמר פיתוח במכשיר.
  3. מריצים את האפליקציה במכשיר הנייד, כפי שמתואר במאמר פיתוח במכשיר.
  4. אם משתמשים ב-Android Studio, אפשר לצפות בפלט של יומן האפליקציות על ידי פותחים את המסוף 'יומן אירועים' (תצוגה > חלונות של כלים > יומן אירועים).
  5. ודא שהאפליקציה שלך מוגדרת להפעלת Logcat באופן אוטומטי כאשר היא רצה:
    1. בוחרים באפשרות הפעלה > עורכים את ההגדרות האישיות.
    2. בוחרים בכרטיסייה שונות בחלון הפעלה/ניפוי באגים.
    3. בקטע Logcat, בוחרים באפשרות Show Logcat יופעל באופן אוטומטי, ולאחר מכן לוחצים על OK (אישור).