نظرة عامة على بروتوكول بدء الجلسة

رصد شرائح eSIM وشرائح SIM

جارٍ الكشف عن البطاقات

تستخدم أجهزة Android المزوّدة بشرائح SIM وشرائح eSIM أرقام التعريف التالية في واجهات برمجة تطبيقات الاتصالات الهاتفية، بما في ذلك [`PhoneManager`](/reference/android/telephony/PhoneManager) و[`SUBSCRIPTIONManager`](/reference/android/telephony/SUBSCRIPTIONManager): * معرّف الاشتراك: معرّف فريد للاشتراك المتوافق مع الأجهزة الجوّالة. * فهرس أو رقم التعريف المنطقي: فهرس فريد يشير إلى فتحة شريحة SIM منطقية. تبدأ أرقام تعريف الخانات المنطقية من 0 وتزداد استنادًا إلى عدد الخانات النشطة المتوافقة على الجهاز. على سبيل المثال، غالبًا ما يكون الجهاز الذي بشريحتَي SIM مزوَّدًا بالمنفذ 0 والفتحة 1. إذا كان الجهاز يحتوي على عدة خانات فعلية ولكن لا يتوافق إلا مع فتحة نشطة واحدة، سيكون له رقم تعريف الفتحة المنطقي 0 فقط. * رقم التعريف أو فهرس الفتحة المادية: فهرس فريد يشير إلى فتحة شريحة SIM. تبدأ أرقام تعريف الخانات المادية من 0 وتزداد اعتمادًا على عدد الخانات الفعلية على الجهاز. ويختلف هذا عن عدد الخانات المنطقية في الجهاز، والتي تتوافق مع عدد الخانات النشطة التي يمكن للجهاز استخدامها. على سبيل المثال، قد يحتوي الجهاز الذي يبدّل بين وضع بشريحتَي SIM ووضع شريحة 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 واجهة برمجة تطبيقات تتوافق مع بروتوكول بدء الجلسة (SIP). يتيح لك ذلك إضافة ميزات الاتصال الهاتفي على الإنترنت المستندة إلى SIP إلى تطبيقاتك. يشتمل Android على حزمة كاملة من بروتوكول SIP وخدمات متكاملة لإدارة المكالمات تسمح للتطبيقات بإعداد المكالمات الصوتية الصادرة والواردة بسهولة، بدون الحاجة إلى إدارة الجلسات أو الاتصالات على مستوى النقل أو تسجيل الصوت أو التشغيل مباشرةً.

في ما يلي أمثلة على أنواع التطبيقات التي قد تستخدم واجهة برمجة تطبيقات SIP:

  • تطبيقات اجتماعات الفيديو
  • الرسائل الفورية

المتطلبات والقيود

في ما يلي متطلبات تطوير تطبيق SIP:

  • يجب أن يكون لديك جهاز جوّال يعمل بنظام التشغيل Android 2.3 أو إصدار أحدث.
  • يعمل SIP على اتصال بيانات لاسلكي، لذا يجب أن يتوفّر على جهازك اتصال بيانات (باستخدام خدمة بيانات الجوّال أو شبكة Wi-Fi). وهذا يعني أنّه لا يمكنك إجراء اختبار على AVD، ولكن يمكنك إجراء اختبار على جهاز مادي فقط. لمعرفة التفاصيل، يُرجى الاطّلاع على اختبار تطبيقات SIP.
  • يجب أن يكون لدى كل مشارك في جلسة اتصال التطبيق حساب SIP. هناك العديد من مقدمي خدمة SIP المختلفين الذين يقدمون حسابات SIP.

ملاحظة: لا تتوافق مكتبة android.net.sip مع مكالمات الفيديو. إذا أردت إجراء مكالمات VOIP باستخدام حزمة SIP مثل android.net.sip، يمكنك البحث عن أحد البدائل الحديثة ومفتوحة المصدر كأساس لأي تنفيذ ميزة مكالمات VOIP. بدلاً من ذلك، يمكنك تنفيذ واجهة برمجة التطبيقات ConnectionService لتوفير تكامل وثيق بين هذه المكالمات في تطبيق برنامج الاتصال على الجهاز.

فئات وواجهات SIP API

في ما يلي ملخّص للصفوف وواجهة واحدة (SipRegistrationListener) المضمّنة في واجهة برمجة تطبيقات Android SIP:

الصف/الواجهة الوصف
SipAudioCall معالجة مكالمة صوتية على الإنترنت عبر SIP.
SipAudioCall.Listener أداة معالجة الأحداث ذات الصلة بمكالمة SIP، مثلاً عند تلقّي مكالمة ("عند الرنين") أو عند إصدار مكالمة ("عند الاتصال").
SipErrorCode تحدد رموز الخطأ التي يتم عرضها أثناء إجراءات SIP.
SipManager توفر واجهات برمجة تطبيقات لمهام SIP، مثل بدء اتصالات SIP، وتوفّر إمكانية الوصول إلى خدمات SIP ذات الصلة.
SipProfile تحدد هذه السمة ملف SIP الشخصي، بما في ذلك حساب SIP ومعلومات النطاق والخادم.
SipProfile.Builder صف مساعد لإنشاء ملف شخصي على SipProfile.
SipSession يمثل جلسة SIP مرتبطة بمربع حوار SIP أو معاملة مستقلة ليست داخل مربع حوار.
SipSession.Listener أداة معالجة للأحداث ذات الصلة بجلسة SIP، مثلاً عند تسجيل جلسة ("عند التسجيل") أو عندما تكون هناك مكالمة صادرة ("عند الاتصال").
SipSession.State تحدِّد هذه السياسة حالات جلسة SIP، مثل "التسجيل" و"مكالمة صادرة" و "في المكالمة".
SipRegistrationListener تمثّل هذه السمة واجهة أداة معالجة أحداث تسجيل SIP.

إنشاء البيان

إذا كنت تطور تطبيقًا يستخدم واجهة برمجة تطبيقات SIP، فتذكر أن هذه الميزة متوافقة فقط مع Android 2.3 (مستوى واجهة برمجة التطبيقات 9) والإصدارات الأحدث من النظام الأساسي. بالإضافة إلى ذلك، لن توفر جميع الأجهزة دعم SIP بين الأجهزة التي تعمل بالإصدار 2.3 من نظام التشغيل Android (المستوى 9 من واجهة برمجة التطبيقات) أو الإصدارات الأحدث.

لاستخدام SIP، أضِف الأذونات التالية إلى بيان التطبيق:

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

لضمان إمكانية تثبيت تطبيقك على الأجهزة التي يمكنها دعم SIP، أضِف ما يلي إلى بيان التطبيق:

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

يشير هذا إلى أنّ تطبيقك يتطلب نظام التشغيل Android 2.3 أو إصدارًا أحدث. لمزيد من المعلومات، يُرجى الاطّلاع على مستويات واجهة برمجة التطبيقات والوثائق المتعلقة بالعنصر <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، يجب أن ينشئ تطبيقك عنصر 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

يتضمّن تطبيق Android SIP النموذجي مستخدمًا واحدًا أو أكثر، يمتلك كل منهم حساب SIP. في تطبيق Android SIP، يمثِّل كل حساب 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، والذي سيتم استخدامه بواسطة فلتر أهداف عندما يتلقّى الجهاز مكالمة (راجِع إعداد فلتر أهداف لتلقّي المكالمات). في ما يلي خطوة التسجيل:

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، ولكن كما هو موضّح أعلاه، يتم استخدام أداة الاستماع لضبط الإعدادات بعد بدء المكالمة.
  • قيمة المهلة بالثواني.

مثلاً:

Kotlin

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

Java

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.

جهاز استقبال البث للفئة الفرعية

لتلقّي المكالمات، يجب أن يستخدم تطبيق SIP الفئة الفرعية BroadcastReceiver. يعالج نظام Android مكالمات SIP الواردة ويبث نية "مكالمة واردة" (على النحو الذي يحدّده التطبيق) عندما يتلقّى مكالمة. إليك رمز الفئة الفرعية 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();
            }
        }
    }
}

إعداد فلتر أهداف لتلقّي المكالمات

عندما تتلقى خدمة SIP اتصالاً جديدًا، فإنها ترسل هدفًا من خلال سلسلة الإجراء التي يوفرها التطبيق. في SipDemo، سلسلة الإجراء هذه هي android.SipDemo.INCOMING_CALL.

يعرض مقتطف الرمز هذا من SipDemo كيفية إنشاء كائن SipProfile بنية في انتظار المراجعة استنادًا إلى سلسلة الإجراء 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);

سيتم اعتراض البث من خلال فلتر الأهداف، والذي سيؤدي بعد ذلك إلى إطلاق جهاز الاستقبال (IncomingCallReceiver). ويمكنك تحديد فلتر هدف في ملف بيان تطبيقك، أو تنفيذه في رمز كما في طريقة onCreate() لنموذج تطبيق SipDemo في التطبيق 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، تحتاج إلى ما يلي:

  • جهاز جوّال يعمل بالإصدار 2.3 من نظام التشغيل Android أو إصدار أحدث يعمل SIP عبر شبكات لاسلكية، لذلك يجب عليك الاختبار على جهاز فعلي. لن تنجح عملية اختبار "متوسّط مدة المشاهدة".
  • حساب SIP. هناك العديد من مقدمي خدمة SIP المختلفين الذين يقدمون حسابات SIP.
  • إذا كنت تجري مكالمة، يجب أن تكون أيضًا لحساب SIP صالح.

لاختبار تطبيق SIP:

  1. على جهازك، اتصل بشبكة لاسلكية (الإعدادات > اللاسلكي والشبكات > Wi-Fi > إعدادات Wi-Fi).
  2. عليك إعداد جهازك الجوّال للاختبار، كما هو موضَّح في التطوير على جهاز.
  3. شغِّل تطبيقك على جهازك الجوّال، كما هو موضح في التطوير على جهاز.
  4. إذا كنت تستخدم Android Studio، يمكنك عرض نتائج سجلّ التطبيق من خلال فتح وحدة تحكّم سجلّ الأحداث (عرض > نوافذ الأداة > سجل الأحداث).
  5. تأكّد من إعداد تطبيقك لتشغيل Logcat تلقائيًا عند تشغيله:
    1. اختَر تشغيل > تعديل عمليات الضبط.
    2. اختَر علامة التبويب إعدادات متنوعة في نافذة عمليات ضبط التشغيل/تصحيح الأخطاء.
    3. ضمن Logcat، اختَر عرض logcat تلقائيًا، ثم اختَر OK (حسنًا).