نمای کلی پروتکل شروع جلسه

eSIM و سیم کارت را شناسایی کنید

شناسایی کارت ها

دستگاه‌های Android دارای سیم‌کارت و سیم‌کارت الکترونیکی از شناسه‌های زیر در APIهای تلفن استفاده می‌کنند، از جمله [`TelephonyManager`](/reference/android/telephony/TelephonyManager) و [`SubscriptionManager`](/reference/android/telephony/SubscriptionManager): * شناسه اشتراک: شناسه منحصر به فرد برای اشتراک تلفن همراه. * فهرست یا شناسه شکاف منطقی: نمایه منحصربه‌فردی که به شکاف سیم‌کارت منطقی اشاره دارد. شناسه‌های شکاف‌های منطقی از 0 شروع می‌شوند و بسته به تعداد اسلات‌های فعال پشتیبانی‌شده در یک دستگاه بالا می‌روند. به عنوان مثال، یک دستگاه دو سیم کارته معمولاً دارای اسلات 0 و اسلات 1 است. اگر دستگاهی دارای چندین اسلات فیزیکی باشد اما فقط از یک اسلات فعال پشتیبانی کند، فقط شناسه شکاف منطقی 0 خواهد داشت. به یک اسلات سیم کارت فیزیکی. شناسه‌های اسلات فیزیکی از 0 شروع می‌شوند و بسته به تعداد اسلات‌های فیزیکی روی دستگاه بالا می‌روند. این با تعداد اسلات های منطقی یک دستگاه متفاوت است، که مربوط به تعداد اسلات های فعالی است که یک دستگاه قادر به استفاده از آن است. برای مثال، دستگاهی که بین حالت دو سیم کارته و تک سیم کارته سوئیچ می کند، ممکن است همیشه دو اسلات فیزیکی داشته باشد، اما در حالت تک سیم کارت تنها یک اسلات منطقی خواهد داشت. * شناسه کارت: شناسه منحصر به فرد مورد استفاده برای شناسایی کارت Uicc. ![نمودار نحوه استفاده از شناسه ها در کیس با دو اسلات منطقی و سه اسلات فیزیکی](/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 (پروفایل‌های فعال چندگانه) فعال هستند.

نمای کلی پروتکل شروع جلسه

اندروید یک API ارائه می دهد که از پروتکل شروع جلسه (SIP) پشتیبانی می کند. این به شما امکان می دهد ویژگی های تلفن اینترنتی مبتنی بر SIP را به برنامه های خود اضافه کنید. Android شامل یک پشته کامل پروتکل SIP و خدمات مدیریت تماس یکپارچه است که به برنامه‌ها اجازه می‌دهد به راحتی تماس‌های صوتی خروجی و ورودی را بدون نیاز به مدیریت جلسات، ارتباطات در سطح انتقال، یا ضبط صدا یا پخش مستقیم، تنظیم کنند.

در اینجا نمونه هایی از انواع برنامه هایی که ممکن است از SIP API استفاده کنند آورده شده است:

  • ویدئو کنفرانس
  • پیام رسانی فوری

الزامات و محدودیت ها

در اینجا شرایط لازم برای توسعه یک برنامه SIP وجود دارد:

  • شما باید دستگاه تلفن همراهی داشته باشید که دارای اندروید 2.3 یا بالاتر باشد.
  • SIP از طریق یک اتصال داده بی سیم اجرا می شود، بنابراین دستگاه شما باید اتصال داده (با سرویس داده تلفن همراه یا Wi-Fi) داشته باشد. این بدان معناست که نمی‌توانید روی AVD تست کنید، فقط می‌توانید روی یک دستگاه فیزیکی تست کنید. برای جزئیات، به آزمایش برنامه های SIP مراجعه کنید.
  • هر شرکت کننده در جلسه ارتباط برنامه باید یک حساب SIP داشته باشد. بسیاری از ارائه دهندگان SIP مختلف وجود دارند که حساب های SIP را ارائه می دهند.

توجه: کتابخانه android.net.sip از تماس های ویدیویی پشتیبانی نمی کند. اگر می‌خواهید تماس VOIP را با استفاده از یک پشته SIP مانند android.net.sip پیاده‌سازی کنید، به یکی از بسیاری از گزینه‌های متن باز مدرن به عنوان پایه‌ای برای اجرای هر تماس VOIP نگاه کنید. از طرف دیگر، می‌توانید ConnectionService API را پیاده‌سازی کنید تا ادغام دقیق این تماس‌ها در برنامه Dialer دستگاه فراهم شود.

کلاس ها و رابط های SIP API

در اینجا خلاصه ای از کلاس ها و یک رابط ( SipRegistrationListener ) موجود در Android SIP 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 رابطی که شنونده رویدادهای ثبت SIP است.

ایجاد مانیفست

اگر در حال توسعه برنامه‌ای هستید که از SIP API استفاده می‌کند، به یاد داشته باشید که این ویژگی فقط در Android 2.3 (سطح API 9) و نسخه‌های بالاتر پلتفرم پشتیبانی می‌شود. همچنین، در میان دستگاه‌هایی که اندروید 2.3 (سطح API 9) یا بالاتر دارند، همه دستگاه‌ها از SIP پشتیبانی نمی‌کنند.

برای استفاده از SIP، مجوزهای زیر را به مانیفست برنامه خود اضافه کنید:

  • android.permission.USE_SIP
  • android.permission.INTERNET

برای اطمینان از اینکه برنامه شما فقط می تواند روی دستگاه هایی نصب شود که قابلیت پشتیبانی از SIP را دارند، موارد زیر را به مانیفست برنامه خود اضافه کنید:

<uses-sdk android:minSdkVersion="9" />

این نشان می دهد که برنامه شما به اندروید 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 جدید را به صورت زیر نمونه سازی می کنید:

کاتلین

val sipManager: SipManager? by lazy(LazyThreadSafetyMode.NONE) {
    SipManager.newInstance(this)
}

جاوا

public SipManager sipManager = null;
...
if (sipManager == null) {
    sipManager = SipManager.newInstance(this);
}

ثبت نام با سرور SIP

یک برنامه SIP معمولی اندروید شامل یک یا چند کاربر است که هر کدام یک حساب SIP دارند. در یک برنامه Android SIP، هر حساب SIP توسط یک شی SipProfile نشان داده می شود.

SipProfile یک نمایه SIP شامل یک حساب SIP و اطلاعات دامنه و سرور را تعریف می کند. نمایه مرتبط با حساب SIP در دستگاهی که برنامه را اجرا می کند، نمایه محلی نامیده می شود. نمایه ای که جلسه به آن متصل است، پروفایل همتا نامیده می شود. هنگامی که برنامه SIP شما با SipProfile محلی به سرور SIP وارد می‌شود، دستگاه را به‌عنوان مکانی برای ارسال تماس‌های SIP برای آدرس SIP شما ثبت می‌کند.

این بخش نحوه ایجاد یک SipProfile ، ثبت آن با سرور SIP و پیگیری رویدادهای ثبت نام را نشان می دهد.

شما یک شی SipProfile را به صورت زیر ایجاد می کنید:

کاتلین

private var sipProfile: SipProfile? = null
...

val builder = SipProfile.Builder(username, domain)
        .setPassword(password)
sipProfile = builder.build()

جاوا

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 را تنظیم می‌کند، که وقتی دستگاه تماسی دریافت می‌کند، توسط یک فیلتر هدف استفاده می‌شود ( به تنظیم فیلتر هدف برای دریافت تماس‌ها مراجعه کنید). این مرحله ثبت نام است:

کاتلین

val intent = Intent("android.SipDemo.INCOMING_CALL")
val pendingIntent: PendingIntent = PendingIntent.getBroadcast(this, 0, intent, Intent.FILL_IN_DATA)
sipManager?.open(sipProfile, pendingIntent, 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);

در نهایت، این کد یک SipRegistrationListener را در SipManager تنظیم می کند. این ردیابی می کند که آیا SipProfile با موفقیت در ارائه دهنده خدمات SIP شما ثبت شده است یا خیر:

کاتلین

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.")
    }
})

جاوا

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.");
    }
}

وقتی برنامه شما با استفاده از یک نمایه تمام شد، باید آن را ببندد تا اشیاء مرتبط در حافظه آزاد شود و دستگاه از سرور لغو ثبت شود. به عنوان مثال:

کاتلین

fun closeLocalProfile() {
    try {
        sipManager?.close(sipProfile?.uriString)
    } catch (ee: Exception) {
        Log.d("WalkieTalkieActivity/onDestroy", "Failed to close local profile.", ee)
    }
}

جاوا

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 پس از برقراری تماس، موارد را تنظیم می‌کند:

کاتلین

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.
    }
}

جاوا

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 باشد، اما همانطور که در بالا نشان داده شده است، پس از برقراری تماس از شنونده برای تنظیم موارد استفاده می شود.
  • مقدار وقفه، در ثانیه.

به عنوان مثال:

کاتلین

val call: SipAudioCall? = sipManager?.makeAudioCall(
        sipProfile?.uriString,
        sipAddress,
        listener,
        30
)

جاوا

call = sipManager.makeAudioCall(sipProfile.getUriString(), sipAddress, listener, 30);

در حال دریافت تماس

برای دریافت تماس، یک برنامه SIP باید شامل یک زیر کلاس از BroadcastReceiver باشد که توانایی پاسخگویی به هدفی را داشته باشد که نشان دهنده وجود تماس ورودی است. بنابراین، شما باید در برنامه خود موارد زیر را انجام دهید:

  • در AndroidManifest.xml ، یک <receiver> را اعلام کنید. در SipDemo ، این <receiver android:name=".IncomingCallReceiver" android:label="Call Receiver" /> است.
  • گیرنده را که زیر کلاس BroadcastReceiver است پیاده سازی کنید. در SipDemo ، این IncomingCallReceiver است.
  • نمایه محلی ( SipProfile ) را با یک هدف معلق راه اندازی کنید که وقتی شخصی با نمایه محلی تماس می گیرد، گیرنده شما را فعال می کند.
  • یک فیلتر هدف تنظیم کنید که با عملکردی که یک تماس ورودی را نشان می دهد فیلتر می کند. در SipDemo ، این عمل android.SipDemo.INCOMING_CALL است.

Subclassing BroadcastReceiver

برای دریافت تماس، برنامه SIP شما باید BroadcastReceiver زیر کلاس قرار دهد. سیستم اندروید تماس های SIP ورودی را مدیریت می کند و یک "تماس ورودی" را پخش می کند. قصد (همانطور که برنامه تعریف می کند) زمانی که تماسی دریافت می کند. در اینجا کد BroadcastReceiver زیر کلاس از نمونه SipDemo آمده است.

کاتلین

/**
 * 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()
            }
        }
    }
}

جاوا

/**
 * 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();
            }
        }
    }
}

راه اندازی فیلتر هدف برای دریافت تماس

هنگامی که سرویس SIP یک تماس جدید دریافت می کند، یک intent را با رشته اقدام ارائه شده توسط برنامه ارسال می کند. در SipDemo، این رشته اقدام android.SipDemo.INCOMING_CALL است.

این گزیده کد از SipDemo نشان می دهد که چگونه شی SipProfile با یک هدف معلق بر اساس رشته اقدام android.SipDemo.INCOMING_CALL ایجاد می شود. هنگامی که SipProfile یک تماس دریافت می کند، شی PendingIntent یک پخش را انجام می دهد:

کاتلین

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)

جاوا

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);

پخش توسط فیلتر قصد رهگیری می شود، که سپس گیرنده ( IncomingCallReceiver ) را فعال می کند. می‌توانید یک فیلتر قصد در فایل مانیفست برنامه خود تعیین کنید، یا آن را به صورت کد مانند روش onCreate() برنامه SipDemo در Activity برنامه انجام دهید:

کاتلین

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)
        ...
    }
    ...
}

جاوا

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 به موارد زیر نیاز دارید:

  • دستگاه تلفن همراهی که دارای اندروید 2.3 یا بالاتر است. SIP از طریق بی سیم اجرا می شود، بنابراین باید روی یک دستگاه واقعی تست کنید. آزمایش بر روی AVD کار نخواهد کرد.
  • یک حساب SIP بسیاری از ارائه دهندگان SIP مختلف وجود دارند که حساب های SIP را ارائه می دهند.
  • اگر در حال برقراری تماس هستید، باید به یک حساب SIP معتبر نیز باشد.

برای آزمایش یک برنامه SIP:

  1. در دستگاه خود، به بی سیم ( تنظیمات > بی سیم و شبکه ها > Wi-Fi > تنظیمات Wi-Fi ) متصل شوید.
  2. همانطور که در Developing on a Device توضیح داده شده است، دستگاه تلفن همراه خود را برای آزمایش تنظیم کنید.
  3. همانطور که در Developing on a Device توضیح داده شده است، برنامه خود را بر روی دستگاه تلفن همراه خود اجرا کنید.
  4. اگر از Android Studio استفاده می‌کنید، می‌توانید خروجی گزارش برنامه را با باز کردن کنسول رویداد گزارش ( نمایش > ابزار ویندوز > گزارش رویداد ) مشاهده کنید.
  5. اطمینان حاصل کنید که برنامه شما به گونه ای پیکربندی شده است که Logcat را هنگام اجرا به طور خودکار راه اندازی کند:
    1. Run > Edit Configurations را انتخاب کنید.
    2. در پنجره Run/Debug Configurations، تب Miscellaneous را انتخاب کنید.
    3. در قسمت Logcat ، Show logcat automatically را انتخاب کنید و سپس OK را انتخاب کنید.
،

eSIM و سیم کارت را شناسایی کنید

شناسایی کارت ها

دستگاه‌های Android دارای سیم‌کارت و سیم‌کارت الکترونیکی از شناسه‌های زیر در APIهای تلفن استفاده می‌کنند، از جمله [`TelephonyManager`](/reference/android/telephony/TelephonyManager) و [`SubscriptionManager`](/reference/android/telephony/SubscriptionManager): * شناسه اشتراک: شناسه منحصر به فرد برای اشتراک تلفن همراه. * فهرست یا شناسه شکاف منطقی: نمایه منحصربه‌فردی که به شکاف سیم‌کارت منطقی اشاره دارد. شناسه‌های شکاف‌های منطقی از 0 شروع می‌شوند و بسته به تعداد اسلات‌های فعال پشتیبانی‌شده در یک دستگاه بالا می‌روند. به عنوان مثال، یک دستگاه دو سیم کارته معمولاً دارای اسلات 0 و اسلات 1 است. اگر دستگاهی دارای چندین اسلات فیزیکی باشد اما فقط از یک اسلات فعال پشتیبانی کند، فقط شناسه شکاف منطقی 0 خواهد داشت. به یک اسلات سیم کارت فیزیکی. شناسه‌های اسلات فیزیکی از 0 شروع می‌شوند و بسته به تعداد اسلات‌های فیزیکی روی دستگاه بالا می‌روند. این با تعداد اسلات های منطقی یک دستگاه متفاوت است، که مربوط به تعداد اسلات های فعالی است که یک دستگاه قادر به استفاده از آن است. برای مثال، دستگاهی که بین حالت دو سیم کارته و تک سیم کارته سوئیچ می کند، ممکن است همیشه دو اسلات فیزیکی داشته باشد، اما در حالت تک سیم کارت تنها یک اسلات منطقی خواهد داشت. * شناسه کارت: شناسه منحصر به فرد مورد استفاده برای شناسایی کارت Uicc. ![نمودار نحوه استفاده از شناسه ها در کیس با دو اسلات منطقی و سه اسلات فیزیکی](/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 (پروفایل‌های فعال چندگانه) فعال هستند.

نمای کلی پروتکل شروع جلسه

اندروید یک API ارائه می دهد که از پروتکل شروع جلسه (SIP) پشتیبانی می کند. این به شما امکان می دهد ویژگی های تلفن اینترنتی مبتنی بر SIP را به برنامه های خود اضافه کنید. Android شامل یک پشته کامل پروتکل SIP و خدمات مدیریت تماس یکپارچه است که به برنامه‌ها اجازه می‌دهد به راحتی تماس‌های صوتی خروجی و ورودی را بدون نیاز به مدیریت جلسات، ارتباطات در سطح انتقال، یا ضبط صدا یا پخش مستقیم، تنظیم کنند.

در اینجا نمونه هایی از انواع برنامه هایی که ممکن است از SIP API استفاده کنند آورده شده است:

  • ویدئو کنفرانس
  • پیام رسانی فوری

الزامات و محدودیت ها

در اینجا شرایط لازم برای توسعه یک برنامه SIP وجود دارد:

  • شما باید دستگاه تلفن همراهی داشته باشید که دارای اندروید 2.3 یا بالاتر باشد.
  • SIP از طریق یک اتصال داده بی سیم اجرا می شود، بنابراین دستگاه شما باید اتصال داده (با سرویس داده تلفن همراه یا Wi-Fi) داشته باشد. این بدان معناست که نمی‌توانید روی AVD تست کنید، فقط می‌توانید روی یک دستگاه فیزیکی تست کنید. برای جزئیات، به آزمایش برنامه های SIP مراجعه کنید.
  • هر شرکت کننده در جلسه ارتباط برنامه باید یک حساب SIP داشته باشد. بسیاری از ارائه دهندگان SIP مختلف وجود دارند که حساب های SIP را ارائه می دهند.

توجه: کتابخانه android.net.sip از تماس های ویدیویی پشتیبانی نمی کند. اگر می‌خواهید تماس VOIP را با استفاده از یک پشته SIP مانند android.net.sip پیاده‌سازی کنید، به یکی از بسیاری از گزینه‌های متن باز مدرن به عنوان پایه‌ای برای اجرای هر تماس VOIP نگاه کنید. از طرف دیگر، می‌توانید ConnectionService API را پیاده‌سازی کنید تا ادغام دقیق این تماس‌ها در برنامه Dialer دستگاه فراهم شود.

کلاس ها و رابط های SIP API

در اینجا خلاصه ای از کلاس ها و یک رابط ( SipRegistrationListener ) موجود در Android SIP 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 رابطی که شنونده رویدادهای ثبت SIP است.

ایجاد مانیفست

اگر در حال توسعه برنامه‌ای هستید که از SIP API استفاده می‌کند، به یاد داشته باشید که این ویژگی فقط در Android 2.3 (سطح API 9) و نسخه‌های بالاتر پلتفرم پشتیبانی می‌شود. همچنین، در میان دستگاه‌هایی که اندروید 2.3 (سطح API 9) یا بالاتر دارند، همه دستگاه‌ها از SIP پشتیبانی نمی‌کنند.

برای استفاده از SIP، مجوزهای زیر را به مانیفست برنامه خود اضافه کنید:

  • android.permission.USE_SIP
  • android.permission.INTERNET

برای اطمینان از اینکه برنامه شما فقط می تواند روی دستگاه هایی نصب شود که قابلیت پشتیبانی از SIP را دارند، موارد زیر را به مانیفست برنامه خود اضافه کنید:

<uses-sdk android:minSdkVersion="9" />

این نشان می دهد که برنامه شما به اندروید 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 جدید را به صورت زیر نمونه سازی می کنید:

کاتلین

val sipManager: SipManager? by lazy(LazyThreadSafetyMode.NONE) {
    SipManager.newInstance(this)
}

جاوا

public SipManager sipManager = null;
...
if (sipManager == null) {
    sipManager = SipManager.newInstance(this);
}

ثبت نام با سرور SIP

یک برنامه SIP معمولی اندروید شامل یک یا چند کاربر است که هر کدام یک حساب SIP دارند. در یک برنامه Android SIP، هر حساب SIP توسط یک شی SipProfile نشان داده می شود.

SipProfile یک نمایه SIP شامل یک حساب SIP و اطلاعات دامنه و سرور را تعریف می کند. نمایه مرتبط با حساب SIP در دستگاهی که برنامه را اجرا می کند، نمایه محلی نامیده می شود. نمایه ای که جلسه به آن متصل است، پروفایل همتا نامیده می شود. هنگامی که برنامه SIP شما با SipProfile محلی به سرور SIP وارد می‌شود، دستگاه را به‌عنوان مکانی برای ارسال تماس‌های SIP برای آدرس SIP شما ثبت می‌کند.

این بخش نحوه ایجاد یک SipProfile ، ثبت آن با سرور SIP و پیگیری رویدادهای ثبت نام را نشان می دهد.

شما یک شی SipProfile را به صورت زیر ایجاد می کنید:

کاتلین

private var sipProfile: SipProfile? = null
...

val builder = SipProfile.Builder(username, domain)
        .setPassword(password)
sipProfile = builder.build()

جاوا

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 را تنظیم می‌کند، که وقتی دستگاه تماسی دریافت می‌کند، توسط یک فیلتر هدف استفاده می‌شود ( به تنظیم فیلتر هدف برای دریافت تماس‌ها مراجعه کنید). این مرحله ثبت نام است:

کاتلین

val intent = Intent("android.SipDemo.INCOMING_CALL")
val pendingIntent: PendingIntent = PendingIntent.getBroadcast(this, 0, intent, Intent.FILL_IN_DATA)
sipManager?.open(sipProfile, pendingIntent, 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);

در نهایت، این کد یک SipRegistrationListener را در SipManager تنظیم می کند. این ردیابی می کند که آیا SipProfile با موفقیت در ارائه دهنده خدمات SIP شما ثبت شده است یا خیر:

کاتلین

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.")
    }
})

جاوا

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.");
    }
}

وقتی برنامه شما با استفاده از یک نمایه تمام شد، باید آن را ببندد تا اشیاء مرتبط در حافظه آزاد شود و دستگاه از سرور لغو ثبت شود. به عنوان مثال:

کاتلین

fun closeLocalProfile() {
    try {
        sipManager?.close(sipProfile?.uriString)
    } catch (ee: Exception) {
        Log.d("WalkieTalkieActivity/onDestroy", "Failed to close local profile.", ee)
    }
}

جاوا

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 پس از برقراری تماس، موارد را تنظیم می‌کند:

کاتلین

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.
    }
}

جاوا

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 باشد، اما همانطور که در بالا نشان داده شده است، پس از برقراری تماس از شنونده برای تنظیم موارد استفاده می شود.
  • مقدار وقفه، در ثانیه.

به عنوان مثال:

کاتلین

val call: SipAudioCall? = sipManager?.makeAudioCall(
        sipProfile?.uriString,
        sipAddress,
        listener,
        30
)

جاوا

call = sipManager.makeAudioCall(sipProfile.getUriString(), sipAddress, listener, 30);

در حال دریافت تماس

برای دریافت تماس، یک برنامه SIP باید شامل یک زیر کلاس از BroadcastReceiver باشد که توانایی پاسخگویی به هدفی را داشته باشد که نشان دهنده وجود تماس ورودی است. بنابراین، شما باید در برنامه خود موارد زیر را انجام دهید:

  • در AndroidManifest.xml ، یک <receiver> را اعلام کنید. در SipDemo ، این <receiver android:name=".IncomingCallReceiver" android:label="Call Receiver" /> است.
  • گیرنده را که زیر کلاس BroadcastReceiver است پیاده سازی کنید. در SipDemo ، این IncomingCallReceiver است.
  • نمایه محلی ( SipProfile ) را با یک هدف معلق راه اندازی کنید که وقتی شخصی با نمایه محلی تماس می گیرد، گیرنده شما را فعال می کند.
  • یک فیلتر هدف تنظیم کنید که با عملکردی که یک تماس ورودی را نشان می دهد فیلتر می کند. در SipDemo ، این عمل android.SipDemo.INCOMING_CALL است.

Subclassing BroadcastReceiver

برای دریافت تماس، برنامه SIP شما باید BroadcastReceiver زیر کلاس قرار دهد. سیستم اندروید تماس های SIP ورودی را مدیریت می کند و یک "تماس ورودی" را پخش می کند. قصد (همانطور که برنامه تعریف می کند) زمانی که تماسی دریافت می کند. در اینجا کد BroadcastReceiver زیر کلاس از نمونه SipDemo آمده است.

کاتلین

/**
 * 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()
            }
        }
    }
}

جاوا

/**
 * 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();
            }
        }
    }
}

راه اندازی فیلتر هدف برای دریافت تماس

هنگامی که سرویس SIP یک تماس جدید دریافت می کند، یک intent را با رشته اقدام ارائه شده توسط برنامه ارسال می کند. در SipDemo، این رشته اقدام android.SipDemo.INCOMING_CALL است.

این گزیده کد از SipDemo نشان می دهد که چگونه شی SipProfile با یک هدف معلق بر اساس رشته اقدام android.SipDemo.INCOMING_CALL ایجاد می شود. هنگامی که SipProfile یک تماس دریافت می کند، شی PendingIntent یک پخش را انجام می دهد:

کاتلین

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)

جاوا

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);

پخش توسط فیلتر قصد رهگیری می شود، که سپس گیرنده ( IncomingCallReceiver ) را فعال می کند. می‌توانید یک فیلتر قصد در فایل مانیفست برنامه خود تعیین کنید، یا آن را به صورت کد مانند روش onCreate() برنامه SipDemo در Activity برنامه انجام دهید:

کاتلین

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)
        ...
    }
    ...
}

جاوا

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 به موارد زیر نیاز دارید:

  • دستگاه تلفن همراهی که دارای اندروید 2.3 یا بالاتر است. SIP از طریق بی سیم اجرا می شود، بنابراین باید روی یک دستگاه واقعی تست کنید. آزمایش بر روی AVD کار نخواهد کرد.
  • یک حساب SIP بسیاری از ارائه دهندگان SIP مختلف وجود دارند که حساب های SIP را ارائه می دهند.
  • اگر در حال برقراری تماس هستید، باید به یک حساب SIP معتبر نیز باشد.

برای آزمایش یک برنامه SIP:

  1. در دستگاه خود، به بی سیم ( تنظیمات > بی سیم و شبکه ها > Wi-Fi > تنظیمات Wi-Fi ) متصل شوید.
  2. همانطور که در Developing on a Device توضیح داده شده است، دستگاه تلفن همراه خود را برای آزمایش تنظیم کنید.
  3. همانطور که در Developing on a Device توضیح داده شده است، برنامه خود را بر روی دستگاه تلفن همراه خود اجرا کنید.
  4. اگر از Android Studio استفاده می‌کنید، می‌توانید خروجی گزارش برنامه را با باز کردن کنسول رویداد گزارش ( نمایش > ابزار ویندوز > گزارش رویداد ) مشاهده کنید.
  5. اطمینان حاصل کنید که برنامه شما به گونه ای پیکربندی شده است که Logcat را هنگام اجرا به طور خودکار راه اندازی کند:
    1. Run > Edit Configurations را انتخاب کنید.
    2. در پنجره Run/Debug Configurations، تب Miscellaneous را انتخاب کنید.
    3. در قسمت Logcat ، Show logcat automatically را انتخاب کنید و سپس OK را انتخاب کنید.