eSIMs und SIM-Karten erkennen
Karten erkennen
Android-Geräte mit SIM-Karten und eSIMs verwenden die folgenden IDs in den Telefonie-APIs, einschließlich [`TelephonyManager`](/reference/android/telephony/TelephonyManager) und [`SubscriptionManager`](/reference/android/telephony/SubscriptionManager): * Abo-ID: eindeutige ID für ein Mobilfunkabo. * Logischer Slotindex oder ID: eindeutiger Index, der sich auf einen logischen SIM-Steckplatz bezieht. Logische Slot-IDs beginnen bei 0 und erhöhen sich je nach Anzahl der unterstützten aktiven Slots auf einem Gerät. Ein Dual-SIM-Gerät hat beispielsweise normalerweise Slot 0 und Slot 1. Wenn ein Gerät mehrere physische Slots hat, aber nur einen aktiven Slot unterstützt, hat es nur die logische Slot-ID 0. * Physischer Slotindex oder ID: eindeutiger Index, der sich auf einen physischen SIM-Steckplatz bezieht. Die IDs physischer Slots beginnen bei 0 und erhöhen sich je nach Anzahl der physischen Slots auf dem Gerät. Diese unterscheidet sich von der Anzahl der logischen Slots, die ein Gerät hat, die der Anzahl der aktiven Slots entspricht, die ein Gerät verwenden kann. Beispielsweise kann ein Gerät, das zwischen Dual-SIM- und Single-SIM-Modus wechselt, immer zwei physische Slots haben, im Einzel-SIM-Modus hat es jedoch nur einen logischen Slot. * Karten-ID: Eindeutige ID zur Identifizierung einer UiccCard. ![Diagramm zur Verwendung von IDs in einem Fall mit zwei logischen und drei physischen Slots](/images/guide/topics/connectivity/tel-ids.png) Im obigen Diagramm: * Das Gerät hat zwei logische Slots. * Im physischen Slot 0 befindet sich eine physische UICC-Karte mit einem aktiven Profil. * Im physischen Slot 2 befindet sich ein eUICC mit einem aktiven Profil. * Physischer Slot 1 wird derzeit nicht verwendet. ![Diagramm zur Verwendung von IDs in einem Fall mit drei logischen Slots und zwei physischen Slots](/images/guide/topics/connectivity/tel-ids-2.png) Im obigen Diagramm: * Das Gerät hat drei logische Slots. * Im physischen Slot 0 befindet sich eine physische UICC-Karte mit einem aktiven Profil. * Im physischen Slot 1 befindet sich ein eUICC mit zwei heruntergeladenen Profilen, die beide mit MEP (Multiple Enabled Profiles) aktiv sind.
Session Initiation Protocol – Übersicht
Android stellt eine API zur Verfügung, die das Session Initiation Protocol (SIP) unterstützt. Dadurch können Sie Ihren Anwendungen SIP-basierte Funktionen für Internettelefonie hinzufügen. Android umfasst einen vollständigen SIP-Protokoll-Stack und integrierte Anrufverwaltungsdienste, mit denen Anwendungen auf einfache Weise ausgehende und eingehende Sprachanrufe einrichten können, ohne Sitzungen, Kommunikation auf Transportebene, Audioaufzeichnungen oder -wiedergabe direkt verwalten zu müssen.
Hier sind Beispiele für die Arten von Anwendungen, die die SIP API verwenden könnten:
- Videokonferenzsysteme
- Chat
Anforderungen und Einschränkungen
Für die Entwicklung einer SIP-Anwendung gelten folgende Anforderungen:
- Sie benötigen ein Mobilgerät mit Android 2.3 oder höher.
- SIP läuft über eine drahtlose Datenverbindung. Ihr Gerät muss also über eine Datenverbindung verfügen (mit einem mobilen Datendienst oder WLAN). Das bedeutet, dass Sie nicht auf AVD testen können, sondern nur auf einem physischen Gerät. Weitere Informationen finden Sie unter SIP-Anwendungen testen.
- Jeder Teilnehmer der Kommunikationssitzung der Anwendung muss ein SIP-Konto haben. Es gibt viele verschiedene SIP-Anbieter, die SIP-Konten anbieten.
Hinweis:Videoanrufe werden von der android.net.sip
-Bibliothek nicht unterstützt. Wenn Sie VoIP-Anrufe mit einem SIP-Stack wie android.net.sip
implementieren möchten, sollten Sie eine der vielen modernen Open-Source-Alternativen als Grundlage für jede VOIP-Anrufimplementierung verwenden. Alternativ kannst du die ConnectionService
API implementieren, um diese Aufrufe eng in die Telefon-App des Geräts einzubinden.
SIP API-Klassen und -Schnittstellen
Im Folgenden finden Sie eine Zusammenfassung der Klassen und einer Schnittstelle (SipRegistrationListener
), die in der Android SIP API enthalten sind:
Klasse/Benutzeroberfläche | Beschreibung |
---|---|
SipAudioCall |
Verarbeitet einen Internet-Audioanruf über SIP. |
SipAudioCall.Listener |
Listener für Ereignisse im Zusammenhang mit einem SIP-Anruf, z. B. wenn ein Anruf empfangen wird („bei Klingeln“) oder ausgehender Anruf („bei Anrufen“). |
SipErrorCode |
Definiert Fehlercodes, die bei SIP-Aktionen zurückgegeben werden. |
SipManager |
Stellt APIs für SIP-Aufgaben wie das Initiieren von SIP-Verbindungen bereit und bietet Zugriff auf zugehörige SIP-Dienste. |
SipProfile |
Definiert ein SIP-Profil, einschließlich SIP-Konto, Domain und Serverinformationen. |
SipProfile.Builder |
Hilfsklasse zum Erstellen eines SipProfiles. |
SipSession |
Stellt eine SIP-Sitzung dar, die einem SIP-Dialog oder einer eigenständigen Transaktion außerhalb eines Dialogfelds zugeordnet ist. |
SipSession.Listener |
Listener für Ereignisse im Zusammenhang mit einer SIP-Sitzung, z. B. wenn eine Sitzung registriert wird („bei der Registrierung“) oder ein Anruf ausgehend („bei Anrufen“). |
SipSession.State |
Definiert den SIP-Sitzungsstatus, z. B. „Registrierung“, „Ausgehender Anruf“ und „Im Anruf“. |
SipRegistrationListener |
Eine Schnittstelle, die als Listener für SIP-Registrierungsereignisse fungiert. |
Manifest wird erstellt
Wenn Sie eine Anwendung entwickeln, die die SIP API verwendet, denken Sie daran, dass die Funktion nur unter Android 2.3 (API-Level 9) und höheren Versionen der Plattform unterstützt wird. Außerdem bieten nicht alle Geräte mit Android 2.3 (API-Level 9) oder höher SIP-Unterstützung.
Fügen Sie dem Manifest Ihrer App die folgenden Berechtigungen hinzu, um SIP zu verwenden:
android.permission.USE_SIP
android.permission.INTERNET
Damit Ihre Anwendung nur auf Geräten installiert werden kann, die SIP unterstützen, fügen Sie dem Manifest Ihrer Anwendung Folgendes hinzu:
<uses-sdk android:minSdkVersion="9" />
Dies bedeutet, dass für Ihre Anwendung Android 2.3 oder höher erforderlich ist. Weitere Informationen finden Sie unter API-Ebenen und in der Dokumentation zum Element <uses-sdk>
.
Wenn Sie festlegen möchten, wie Ihre App von Geräten gefiltert wird, die SIP nicht unterstützen (z. B. bei Google Play), fügen Sie dem Manifest Ihrer App Folgendes hinzu:
<uses-feature android:name="android.software.sip.voip" />
Dies gibt an, dass Ihre Anwendung die SIP API verwendet. Die Deklaration sollte ein android:required
-Attribut enthalten, das angibt, ob die App von Geräten gefiltert werden soll, die keine SIP-Unterstützung bieten.
Je nach Implementierung sind möglicherweise weitere <uses-feature>
-Deklarationen erforderlich. Weitere Informationen finden Sie in der Dokumentation zum Element <uses-feature>
.
Wenn Ihre Anwendung für den Empfang von Aufrufen konzipiert ist, müssen Sie im Manifest der Anwendung außerdem einen Empfänger (Unterklasse BroadcastReceiver
) definieren:
<receiver android:name=".IncomingCallReceiver" android:label="Call Receiver" />
Hier sind Auszüge aus dem SipDemo-Manifest:
<?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 wird erstellt
Damit Sie die SIP API verwenden können, muss Ihre Anwendung ein SipManager
-Objekt erstellen. Der SipManager
übernimmt in Ihrer Anwendung folgende Aufgaben:
- SIP-Sitzungen werden gestartet.
- Initiieren und Empfangen von Anrufen
- Bei einem SIP-Anbieter registrieren und Registrierung aufheben
- Sitzungsverbindung prüfen
So instanziieren Sie eine neue SipManager
:
Kotlin
val sipManager: SipManager? by lazy(LazyThreadSafetyMode.NONE) { SipManager.newInstance(this) }
Java
public SipManager sipManager = null; ... if (sipManager == null) { sipManager = SipManager.newInstance(this); }
Registrierung bei einem SIP-Server
An einer typischen Android-SIP-Anwendung sind ein oder mehrere Nutzer beteiligt, die jeweils ein SIP-Konto haben. In einer Android SIP-Anwendung wird jedes SIP-Konto durch ein SipProfile
-Objekt dargestellt.
Ein SipProfile
definiert ein SIP-Profil, einschließlich eines SIP-Kontos, sowie Domain- und Serverinformationen. Das mit dem SIP-Konto auf dem Gerät, auf dem die Anwendung ausgeführt wird, verknüpfte Profil wird als lokales Profil bezeichnet. Das Profil, mit dem die Sitzung verbunden ist, wird als Peer-Profil bezeichnet. Wenn sich Ihre SIP-Anwendung mit dem lokalen SipProfile
beim SIP-Server anmeldet, wird das Gerät dadurch als Standort registriert, an den SIP-Anrufe für Ihre SIP-Adresse gesendet werden können.
In diesem Abschnitt wird gezeigt, wie Sie einen SipProfile
erstellen, ihn bei einem SIP-Server registrieren und Registrierungsereignisse verfolgen.
So erstellen Sie ein SipProfile
-Objekt:
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();
Der folgende Codeauszug öffnet das lokale Profil für Anrufe und/oder den Empfang von allgemeinen SIP-Anrufen. Der Aufrufer kann über mSipManager.makeAudioCall
nachfolgende Aufrufe tätigen. In diesem Auszug wird auch die Aktion android.SipDemo.INCOMING_CALL
festgelegt, die von einem Intent-Filter verwendet wird, wenn das Gerät einen Aufruf empfängt (siehe Intent-Filter für den Empfang von Aufrufen einrichten). Dies ist der Registrierungsschritt:
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);
Schließlich wird mit diesem Code ein SipRegistrationListener
für das SipManager
festgelegt. Damit wird erfasst, ob SipProfile
bei Ihrem SIP-Dienstanbieter registriert wurde:
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."); } }
Wenn Ihre Anwendung ein Profil nicht mehr verwendet, sollte sie es schließen, um zugehörige Objekte im Arbeitsspeicher freizugeben und das Gerät vom Server zu trennen. Beispiel:
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); } }
Sprachanruf starten
Für einen Sprachanruf benötigen Sie Folgendes:
- Eine
SipProfile
, die den Anruf tätigt (das „lokale Profil“), und eine gültige SIP-Adresse für den Empfang des Anrufs (das „Peer-Profil“). - Ein
SipManager
-Objekt.
Für einen Sprachanruf solltest du eine SipAudioCall.Listener
einrichten. Ein Großteil der Clientinteraktion mit dem SIP-Stack erfolgt über Listener. In diesem Snippet sehen Sie, wie die Einrichtung von SipAudioCall.Listener
nach dem Aufruf erfolgt:
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. } };
Sobald Sie SipAudioCall.Listener
eingerichtet haben, können Sie den Anruf starten. Die SipManager
-Methode makeAudioCall
verwendet die folgenden Parameter:
- Ein lokales SIP-Profil (der Anrufer).
- Ein Peer-SIP-Profil (der angerufene Nutzer).
- Ein
SipAudioCall.Listener
, um auf die Aufrufereignisse vonSipAudioCall
zu warten. Dies kannnull
sein. Wie oben gezeigt, wird der Listener jedoch zum Einrichten von Elementen verwendet, sobald der Aufruf erfolgt. - Der Wert für das Zeitlimit in Sekunden.
Beispiele:
Kotlin
val call: SipAudioCall? = sipManager?.makeAudioCall( sipProfile?.uriString, sipAddress, listener, 30 )
Java
call = sipManager.makeAudioCall(sipProfile.getUriString(), sipAddress, listener, 30);
Anrufe erhalten
Zum Empfangen von Anrufen muss eine SIP-Anwendung eine abgeleitete Klasse von BroadcastReceiver
enthalten, die in der Lage ist, auf einen Intent zu antworten, der einen eingehenden Anruf anzeigt. Daher müssen Sie in Ihrer Anwendung Folgendes tun:
- Deklarieren Sie in
AndroidManifest.xml
einen<receiver>
. In SipDemo ist dies<receiver android:name=".IncomingCallReceiver" android:label="Call Receiver" />
. - Implementieren Sie den Empfänger, der eine abgeleitete Klasse von
BroadcastReceiver
ist. In SipDemo ist diesIncomingCallReceiver
. - Initialisieren Sie das lokale Profil (
SipProfile
) mit einem ausstehenden Intent, der Ihren Empfänger auslöst, wenn jemand das lokale Profil aufruft. - Richten Sie einen Intent-Filter ein, der nach der Aktion filtert, die einen eingehenden Anruf darstellt. In SipDemo ist diese Aktion
android.SipDemo.INCOMING_CALL
.
Abgeleitete Klasse von BroadcastReceiver
Damit Sie Anrufe empfangen können, muss Ihre SIP-Anwendung die abgeleiteten Klassen von BroadcastReceiver
haben. Das Android-System verarbeitet eingehende SIP-Anrufe und sendet den von der App definierten Intent „eingehender Anruf“, wenn ein Anruf eingeht. Hier ist der abgeleitete Code von
BroadcastReceiver
aus dem SipDemo-Beispiel.
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-Filter zum Empfang von Anrufen einrichten
Wenn der SIP-Dienst einen neuen Aufruf empfängt, sendet er einen Intent mit dem von der Anwendung bereitgestellten Aktionsstring. In SipDemo lautet dieser Aktionsstring android.SipDemo.INCOMING_CALL
.
Dieser Codeauszug aus SipDemo zeigt, wie das Objekt SipProfile
mit einem ausstehenden Intent basierend auf dem Aktionsstring android.SipDemo.INCOMING_CALL
erstellt wird. Das PendingIntent
-Objekt führt einen Broadcast aus, wenn SipProfile
einen Aufruf empfängt:
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);
Die Übertragung wird vom Intent-Filter abgefangen, der dann den Empfänger auslöst (IncomingCallReceiver
). Sie können einen Intent-Filter in der Manifestdatei Ihrer Anwendung angeben oder dies im Code wie in der Methode SipDemo
der Activity
-Methode der Beispielanwendung onCreate()
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-Anwendungen testen
Zum Testen von SIP-Anwendungen benötigen Sie Folgendes:
- Ein Mobilgerät mit Android 2.3 oder höher. SIP wird über WLAN ausgeführt, daher müssen Sie den Test auf einem echten Gerät durchführen. Tests mit AVD werden nicht funktionieren.
- Ein SIP-Konto. Es gibt viele verschiedene SIP-Anbieter, die SIP-Konten anbieten.
- Wenn Sie jemanden anrufen, muss es sich ebenfalls um ein gültiges SIP-Konto handeln.
So testen Sie eine SIP-Anwendung:
- Stellen Sie auf Ihrem Gerät eine WLAN-Verbindung her (Einstellungen > Drahtlos & Netzwerke > WLAN > WLAN-Einstellungen).
- Richten Sie Ihr Mobilgerät für Tests ein, wie unter Auf einem Gerät entwickeln beschrieben.
- Führen Sie die Anwendung wie unter Auf einem Gerät entwickeln beschrieben auf Ihrem Mobilgerät aus.
- Wenn Sie Android Studio verwenden, können Sie die Ausgabe des Anwendungslogs in der Ereignisprotokollkonsole ansehen (Ansicht > Toolfenster > Ereignisprotokoll).
- Achten Sie darauf, dass Ihre Anwendung so konfiguriert ist, dass Logcat bei der Ausführung automatisch gestartet wird:
- Wählen Sie Run > Edit Configurations (Ausführen > Konfigurationen bearbeiten) aus.
- Wählen Sie im Fenster Run/Debug Configurations den Tab Miscellaneous (Verschiedenes) aus.
- Wählen Sie unter Logcat (Logcat automatisch anzeigen) die Option Show logcat automatically (Logcat automatisch anzeigen) und dann OK aus.