Descripción general del protocolo de inicio de sesión

Cómo detectar eSIM y tarjetas SIM

Detecta tarjetas

Los dispositivos Android con tarjetas SIM y eSIM usan los siguientes IDs en la línea de telefonía APIs, incluidas [`TelephonyManager`](/reference/android/telephony/Manager) y [`SubscriptionManager`](/reference/android/telephony/SubscriptionManager): * ID de suscripción: ID único correspondiente a una suscripción para dispositivos móviles. * Índice o ID de ranura lógico: índice único que hace referencia a una ranura SIM lógica. Los IDs de ranura lógicos comienzan en 0 y aumentan según la cantidad de ranuras activas admitidas en un dispositivo. Por ejemplo, un dispositivo con doble tarjeta SIM, por lo general, tiene las ranuras 0 y 1. Si un dispositivo tiene varias ranuras físicas, pero solo admite una ranura activa, solo tendrá el ID de ranura lógico 0. * Índice o ID de ranura física: Es un índice único que hace referencia a una ranura SIM física. Los IDs de ranuras físicas comienzan en 0 y aumentan según la cantidad de ranuras físicas ranuras en el dispositivo. Esto difiere de la cantidad de ranuras lógicas que puede tener un dispositivo que tiene, lo que corresponde a la cantidad de ranuras activas que puede alcanzar un dispositivo usan. Por ejemplo, un dispositivo que alterna entre una tarjeta SIM doble y una SIM única siempre puede tener dos ranuras físicas, pero en el modo de una sola SIM tendrá solo una ranura lógica. * ID de la tarjeta: Es un ID único que se usa para identificar una UiccCard. ![Un diagrama que muestra cómo se usan los IDs en un caso con dos ranuras lógicas y tres ranuras físicas](/images/guide/topics/connectivity/tel-ids.png) En el diagrama anterior: * El dispositivo tiene dos ranuras lógicas. * En la ranura física 0, hay una tarjeta UICC física con un perfil activo. * En la ranura física 2, hay un eUICC con un perfil activo. * La ranura física 1 no está en uso en este momento. ![Un diagrama que muestra cómo se usan los IDs en un caso con tres ranuras lógicas y dos ranuras físicas](/images/guide/topics/connectivity/tel-ids-2.png) En el diagrama anterior: * El dispositivo tiene tres ranuras lógicas. * En la ranura física 0, hay una tarjeta UICC física con un perfil activo. * En la ranura física 1, hay un eUICC que tiene dos perfiles descargados, ambos activos mediante MEP (múltiples perfiles habilitados).

Descripción general del protocolo de inicio de sesión

Android ofrece una API que admite el Protocolo de inicio de sesión (SIP). Esto te permite agregar funciones de telefonía por Internet basadas en SIP a tus aplicaciones. Android incluye una pila completa de protocolos SIP y administración de llamadas integrada que permiten a las aplicaciones configurar fácilmente llamadas de voz entrantes y salientes, sin tener que administrar sesiones, comunicación a nivel de transporte o audio grabar o reproducir directamente.

Estos son ejemplos de los tipos de aplicaciones que pueden usar la API de SIP:

  • Videoconferencias
  • Mensajería instantánea

Requisitos y limitaciones

Estos son los requisitos para desarrollar una aplicación SIP:

  • Debes tener un dispositivo móvil con Android 2.3 o versiones posteriores.
  • SIP se ejecuta a través de una conexión de datos inalámbrica, por lo que tu dispositivo debe tener una (con servicio de datos para celulares o Wi-Fi). Esto significa que No puedes realizar pruebas en AVD. Solo puedes hacerlo en un dispositivo físico. Para obtener más información, consulta Prueba de aplicaciones SIP.
  • Cada participante en la sesión de comunicación de la solicitud debe tener un cuenta SIP. Hay muchos proveedores de SIP diferentes que ofrecen cuentas SIP.

Nota: La biblioteca android.net.sip no es compatible con las llamadas. Si quieres implementar llamadas VoIP usando una pila SIP como android.net.sip, mira uno de los tantos modelos de código abierto alternativas como base para cualquier implementación de llamadas VoIP. Por otro lado, puedes implementar el ConnectionService API para proporcionar una integración estrecha de estas llamadas en el Teléfono del dispositivo .

Clases e interfaces de API de SIP

Este es un resumen de las clases y una interfaz (SipRegistrationListener) que se incluyen en el SIP de Android API:

Clase/interfaz Descripción
SipAudioCall Procesa una llamada de audio de Internet a través de SIP.
SipAudioCall.Listener Objeto de escucha de eventos relacionados con una llamada SIP, como cuando se está realizando una llamada recibidas ("al sonar") o que una llamada sea saliente ("llamando").
SipErrorCode Define los códigos de error que se muestran durante las acciones de SIP.
SipManager Proporciona APIs para tareas de SIP, como iniciar conexiones SIP, y proporciona acceso a servicios SIP relacionados.
SipProfile Define un perfil de SIP, que incluye una cuenta SIP y la información de dominio y servidor.
SipProfile.Builder Clase auxiliar para crear un SipProfile.
SipSession Representa una sesión SIP asociada con un diálogo SIP o una transacción independiente. no dentro de un diálogo.
SipSession.Listener Objeto de escucha de eventos relacionados con una sesión SIP, como cuando se registra una sesión ("al registrarse") o que una llamada sea saliente ("llamando").
SipSession.State Define estados de sesión SIP, como "registrando", "llamada saliente" y "en llamada".
SipRegistrationListener Una interfaz que es un objeto de escucha de los eventos de registro SIP.

Cómo se crea el manifiesto

Si estás desarrollando una aplicación que usa la API de SIP, recuerda que el es compatible solo con Android 2.3 (nivel de API 9) y versiones posteriores de en la plataforma. Además, entre los dispositivos con Android 2.3 (nivel de API 9) o versiones posteriores, no todos los dispositivos serán compatibles con SIP.

Para usar SIP, agrega los siguientes permisos al manifiesto de tu aplicación:

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

Para asegurarte de que tu aplicación solo se pueda instalar en dispositivos que estén soporta SIP, agrega lo siguiente a la dirección de tu aplicación manifiesto:

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

Esto indica que tu aplicación requiere Android 2.3 o versiones posteriores. Para más información, consulta Niveles de API y la documentación del <uses-sdk> .

Para controlar cómo se filtra tu aplicación desde dispositivos que no son compatibles SIP (por ejemplo, en Google Play), agrega lo siguiente al directorio de tu aplicación manifiesto:

<uses-feature android:name="android.software.sip.voip" />

Esto declara que tu aplicación usa la API de SIP. La declaración debe incluye un atributo android:required que indique si quieren que la aplicación se filtre de dispositivos que no ofrezcan compatibilidad con SIP. Es posible que también se necesiten otras declaraciones <uses-feature>. según tu implementación. Para obtener más información, consulta la documentación para el <uses-feature> .

Si tu aplicación está diseñada para recibir llamadas, también debes definir un receptor (subclase BroadcastReceiver) en su manifiesto:

<receiver android:name=".IncomingCallReceiver" android:label="Call Receiver" />

Estos son extractos del manifiesto de 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>

Cómo crear SipManager

Para usar la API de SIP, tu aplicación debe crear un objeto SipManager. SipManager toma se ocupará de lo siguiente en tu aplicación:

  • Iniciar sesiones SIP
  • Iniciar y recibir llamadas
  • Registrar y cancelar el registro con un proveedor SIP
  • Verificar la conectividad de la sesión

Crea una instancia nueva de SipManager de la siguiente manera:

Kotlin

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

Java

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

Cómo registrarse con un servidor SIP

Una aplicación SIP para Android típica implica uno o más usuarios, cada uno de los cuales tiene una cuenta SIP. En una aplicación SIP para Android, cada cuenta SIP se se representa con un objeto SipProfile.

Un SipProfile define un perfil de SIP, incluido un SIP. cuenta e información de dominio y servidor. El perfil asociado con el SIP en el dispositivo que ejecuta la aplicación se denomina local perfil. El perfil al que está conectada la sesión se denomina perfil similar. Cuando tu aplicación SIP accede al servidor SIP con el SipProfile local, esto registra efectivamente el dispositivo como la ubicación para enviar llamadas SIP a tu dirección SIP.

En esta sección, se muestra cómo crear un SipProfile, registrarla en un servidor SIP y hacer un seguimiento de los eventos de registro.

Crea un objeto SipProfile de la siguiente manera:

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

El siguiente extracto de código abre el perfil local para realizar llamadas o para recibir llamadas SIP genéricas. El emisor puede hacer llamadas subsiguientes a través de mSipManager.makeAudioCall Este extracto también define la acción android.SipDemo.INCOMING_CALL, que utilizará un intent cuando el dispositivo recibe una llamada (consulta Configuración un filtro de intents para recibir llamadas). Este es el paso de registro:

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

Finalmente, este código configura un SipRegistrationListener en el SipManager. Esto realiza un seguimiento de si el SipProfile se registró correctamente con tu servicio SIP proveedor:

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

Cuando tu aplicación termine de usar un perfil, debería cerrarse y liberarse los objetos asociados a la memoria y cancelar el registro del dispositivo en el servidor. Por ejemplo:

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

Cómo realizar una llamada de audio

Para realizar una llamada de audio, debes contar con lo siguiente:

  • Un objeto SipProfile que realiza la llamada (el "perfil local") y una dirección SIP válida para recibir la llamada (el "perfil similar").
  • Un objeto SipManager

Para realizar una llamada de audio, debes configurar un SipAudioCall.Listener. Gran parte de la interacción del cliente con la pila SIP ocurre a través de objetos de escucha. En este fragmento, se puede ver cómo SipAudioCall.Listener configura las cosas después de que se realiza establecido:

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

Una vez que hayas configurado SipAudioCall.Listener, puedes realizar la llamada. El método SipManager makeAudioCall toma los siguientes parámetros:

  • Un perfil de SIP local (el emisor).
  • Un perfil de SIP similar (el receptor de la llamada).
  • Un SipAudioCall.Listener para escuchar la llamada eventos de SipAudioCall. Puede ser null, pero como se mostró anteriormente, el objeto de escucha se usa para configurar las cosas una vez que se realiza establecidos.
  • El valor del tiempo de espera, en segundos.

Por ejemplo:

Kotlin

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

Java

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

Cómo recibir llamadas

Para recibir llamadas, una aplicación SIP debe incluir una subclase de BroadcastReceiver que tenga la capacidad de responder a un intent lo que indica que hay una llamada entrante. Por lo tanto, debes hacer lo siguiente en tu aplicación:

  • En AndroidManifest.xml, declara un <receiver> En SipDemo, esto es <receiver android:name=".IncomingCallReceiver" android:label="Call Receiver" />
  • Implementa el receptor, que es una subclase de BroadcastReceiver. En SipDemo, esto es IncomingCallReceiver
  • Inicializa el perfil local (SipProfile) con un intent pendiente que activa tu receptor cuando alguien llama al perfil local.
  • Configura un filtro de intents que filtre por la acción que representa un llamada entrante. En SipDemo, esta acción es android.SipDemo.INCOMING_CALL

Cómo subclasificar BroadcastReceiver

Para recibir llamadas, tu aplicación SIP debe subclasificar BroadcastReceiver. El El sistema Android maneja las llamadas SIP entrantes y transmite “call” (según lo define la aplicación) cuando recibe una llamada. Este es el BroadcastReceiver con subclase de la muestra de 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();
            }
        }
    }
}

Cómo configurar un filtro de intents para recibir llamadas

Cuando el servicio SIP recibe una nueva llamada, envía un intent con el string de acción proporcionada por la aplicación. En SipDemo, esta cadena de acción se android.SipDemo.INCOMING_CALL

Este extracto de código de SipDemo muestra cómo se crea el objeto SipProfile con un intent pendiente basado en la cadena de acción android.SipDemo.INCOMING_CALL. El El objeto PendingIntent realizará una transmisión cuando SipProfile reciba una llamada:

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

El filtro de intents interceptará la transmisión, que luego se activará. el receptor (IncomingCallReceiver) Puedes especificar un intent filtrar en el archivo de manifiesto de tu aplicación o hacerlo en código, como en el caso de SipDemo método onCreate() de la aplicación de ejemplo del Activity de la aplicación:

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

Cómo probar aplicaciones SIP

Para probar aplicaciones SIP, necesitas lo siguiente:

  • Un dispositivo móvil con Android 2.3 o versiones posteriores. SIP se ejecuta en inalámbrica, por lo que debes probarla en un dispositivo real. Las pruebas en AVD no funcionarán.
  • Una cuenta SIP. Hay muchos proveedores de SIP diferentes que ofrecen cuentas SIP.
  • Si realizas una llamada, también debe ser a una cuenta SIP válida.

Para probar una aplicación SIP:

  1. En tu dispositivo, conéctate a la conexión inalámbrica (Configuración > Conexiones inalámbricas y redes). &gt; Wi-Fi > Configuración de Wi-Fi).
  2. Configura tu dispositivo móvil para realizar pruebas, como se describe en Cómo desarrollar en un dispositivo.
  3. Ejecuta la aplicación en tu dispositivo móvil, como se describe en Cómo desarrollar en un dispositivo.
  4. Si usas Android Studio, puedes ver el resultado del registro de la aplicación abrir la consola de Registro de eventos (View > Tool Windows > Event Log)
  5. Asegúrate de que tu aplicación esté configurada para iniciar Logcat automáticamente cuando se ejecute:
    1. Selecciona Run > Edit Configurations.
    2. Selecciona la pestaña Miscellaneous en la ventana Run/Debug Configurations.
    3. En Logcat, selecciona Mostrar logcat automáticamente y, luego, selecciona Aceptar.