Wykrywanie kart eSIM i kart SIM
Wykrywam karty
Urządzenia z Androidem z kartami SIM i kartami eSIM używają w telewizji następujących identyfikatorów: interfejsów API, w tym [„TelephonyManager”](/reference/android/telephony/TelephonyManager) i [`SubscriptionManager`](/reference/android/telephony/SubscriptionManager): * Identyfikator subskrypcji: unikalny identyfikator subskrypcji mobilnej. * Logiczny indeks gniazda lub identyfikator: unikalny indeks odnoszący się do logicznego gniazda karty SIM. Logiczne identyfikatory przedziałów zaczynają się od 0 i zwiększają się w zależności od liczby obsługiwane aktywne przedziały na urządzeniu. Na przykład zwykle urządzenia 2 SIM ma miejsce 0 i 1. Jeśli urządzenie ma wiele gniazd fizycznych, ale tylko obsługuje jeden aktywny przedział, będzie miał tylko identyfikator logiczny 0. * Fizyczny indeks gniazda lub identyfikator: unikalny indeks odnoszący się do fizycznego gniazda karty SIM. Identyfikatory przedziałów fizycznych zaczynają się od 0 i zwiększają się w zależności od liczby fizycznych gniazda na urządzeniu. Ta wartość różni się od liczby przedziałów logicznych urządzenia , która odpowiada liczbie aktywnych przedziałów, które może obsłużyć urządzenie. . Na przykład urządzenie przełączające się między kartami 2 SIM i 1 SIM tryb może mieć zawsze dwa gniazda fizyczne, a w trybie jednej karty SIM tylko jeden przedział logiczny. * Identyfikator karty: unikalny identyfikator służący do identyfikacji karty UiccCard. ![Schemat użycia identyfikatorów w przypadku z 2 przedziałami logicznymi i 3 przedziałami fizycznymi](/images/guide/topics/connectivity/tel-ids.png) Na powyższym diagramie: * Urządzenie ma dwa gniazda logiczne. * W gnieździe fizycznym 0 znajduje się fizyczna karta UICC z aktywnym profilem. * W fizycznym przedziale 2 jest to eUICC z aktywnym profilem. * Gniazdo fizyczne 1 nie jest obecnie używane. ![Schemat użycia identyfikatorów w przypadku z 3 przedziałami logicznymi i 2 przedziałami fizycznymi](/images/guide/topics/connectivity/tel-ids-2.png) Na powyższym diagramie: * Urządzenie ma 3 gniazda logiczne. * W gnieździe fizycznym 0 znajduje się fizyczna karta UICC z aktywnym profilem. * W fizycznym przedziale 1 jest to eUICC z 2 pobranymi profilami, z których oba są aktywne przy użyciu wielu włączonych profili MEP.
Omówienie protokołu inicjowania sesji
Android udostępnia interfejs API, który obsługuje protokół SIP (Session Initiation Protocol). Dzięki temu możesz dodać do swoich aplikacji funkcje telefonii internetowej oparte na SIP. Android obejmuje pełny stos protokołów SIP i zintegrowane zarządzanie połączeniami które pozwalają aplikacjom łatwo konfigurować wychodzące i przychodzące połączenia głosowe, bez konieczności zarządzania sesjami, komunikacją na poziomie transportu czy dźwiękiem. bezpośrednio nagrywać lub odtwarzać treści.
Oto przykłady typów aplikacji, które mogą używać interfejsu SIP API:
- Rozmowy wideo
- Komunikator internetowy
Wymagania i ograniczenia
Oto wymagania dotyczące programowania aplikacji SIP:
- Musisz mieć urządzenie mobilne z systemem Android 2.3 lub nowszym.
- SIP jest przesyłany przez bezprzewodowe połączenie transmisji danych, dlatego urządzenie musi mieć dostępną połączenie (przez komórkową usługę transmisji danych lub Wi-Fi). Oznacza to, że musisz nie możesz przeprowadzić testów na urządzeniu AVD – możesz to zrobić tylko na urządzeniu fizycznym. Więcej informacji: Testowanie aplikacji SIP
- Każdy uczestnik sesji komunikacyjnej w aplikacji musi mieć Konto SIP. Konta SIP oferuje wielu różnych dostawców SIP.
Uwaga: biblioteka android.net.sip
nie obsługuje filmów.
połączeń. Jeśli chcesz wdrożyć połączenia VOIP za pomocą stosu SIP, takiego jak
android.net.sip
, zapoznaj się z jednym z wielu nowoczesnych rozwiązań typu open source
jako podstawę implementacji VOIP. Ewentualnie
możesz zastosować
ConnectionService
Interfejs API zapewniający ścisłą integrację tych połączeń z Telefonem na urządzeniu
.
Klasy i interfejsy SIP API
Oto podsumowanie klas i 1 interfejsu
(SipRegistrationListener
) uwzględnione w Android SIP
Interfejs API:
Klasa/interfejs | Opis |
---|---|
SipAudioCall |
Obsługuje internetowe połączenie głosowe przez SIP. |
SipAudioCall.Listener |
Detektor zdarzeń związanych z połączeniem SIP, na przykład podczas nawiązywania połączenia odebrane („sygnał dzwonienia”) lub połączenie wychodzące („trwa dzwonienie”). |
SipErrorCode |
Definiuje kody błędów zwracanych podczas działań SIP. |
SipManager |
Udostępnia interfejsy API do zadań SIP, takich jak inicjowanie połączeń SIP, oraz dostęp do powiązanych usług SIP. |
SipProfile |
Definiuje profil SIP, w tym konto SIP, domenę i informacje o serwerze. |
SipProfile.Builder |
Klasa pomocnicza do tworzenia profilu SipProfile. |
SipSession |
Reprezentuje sesję SIP, która jest powiązana z oknem SIP lub samodzielną transakcją poza oknem. |
SipSession.Listener |
Detektor zdarzeń związanych z sesją SIP, na przykład podczas rejestrowania sesji („w trakcie rejestracji”) lub połączenie wychodzące („trwa połączenie”). |
SipSession.State |
Definiuje stany sesji SIP, takie jak „rejestrowanie”, „połączenie wychodzące” i „w trakcie rozmowy”. |
SipRegistrationListener |
Interfejs, który jest detektorem zdarzeń rejestracji SIP. |
Tworzę plik manifestu
Jeśli tworzysz aplikację korzystającą z interfejsu SIP API, pamiętaj, że jest obsługiwana tylko w Androidzie 2.3 (poziom API 9) i nowszych wersjach platformy. Poza tym na urządzeniach z Androidem 2.3 (poziom interfejsu API 9) lub nowszym nie wszystkie urządzenia obsługują protokół SIP.
Aby używać SIP, dodaj do pliku manifestu aplikacji te uprawnienia:
android.permission.USE_SIP
android.permission.INTERNET
Aby aplikacje można było instalować tylko na urządzeniach, obsługujące SIP, dodaj poniższy kod do plik manifestu:
<uses-sdk android:minSdkVersion="9" />
Oznacza to, że aplikacja wymaga systemu Android 2.3 lub nowszego. Dla:
więcej informacji znajdziesz w
Poziomy interfejsu API
oraz dokumentacja usługi
<uses-sdk>
.
Aby kontrolować sposób filtrowania aplikacji z urządzeń, które nie obsługują SIP (np. w Google Play), dodaj ten kod do plik manifestu:
<uses-feature android:name="android.software.sip.voip" />
Oznacza to, że Twoja aplikacja używa interfejsu SIP API. Deklaracja powinna
dodaj atrybut android:required
, który wskazuje, czy
chcesz, aby aplikacja była odfiltrowywana z urządzeń, które nie obsługują SIP.
Mogą być też potrzebne inne deklaracje <uses-feature>
,
w zależności od implementacji. Więcej informacji znajdziesz w dokumentacji
dla wartości
<uses-feature>
.
Jeśli Twoja aplikacja jest przeznaczona do odbierania połączeń, musisz też zdefiniować odbiornik (podklasę BroadcastReceiver
) w pliku manifestu aplikacji:
<receiver android:name=".IncomingCallReceiver" android:label="Call Receiver" />
Oto fragmenty pliku manifestu 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>
Tworzę SipManagera
Aby można było korzystać z interfejsu SIP API, aplikacja musi utworzyć obiekt SipManager
. SipManager
zajmuje
zadbaj o następujące elementy swojej aplikacji:
- Inicjuję sesje SIP.
- inicjowanie i odbieranie połączeń,
- Rejestrowanie i wyrejestrowanie u dostawcy SIP.
- Weryfikuję połączenia sesji.
Tworzysz nową instancję SipManager
w ten sposób:
Kotlin
val sipManager: SipManager? by lazy(LazyThreadSafetyMode.NONE) { SipManager.newInstance(this) }
Java
public SipManager sipManager = null; ... if (sipManager == null) { sipManager = SipManager.newInstance(this); }
Rejestrowanie na serwerze SIP
Z typowej aplikacji SIP na Androida korzysta co najmniej 1 użytkownik, z których każdy
ma konto SIP. W aplikacji SIP na Androidzie każde konto SIP
reprezentowane przez obiekt SipProfile
.
SipProfile
definiuje profil SIP, w tym profil SIP
informacje o koncie oraz domenie i serwerze. Profil powiązany z SIP
na urządzeniu, na którym jest uruchomiona aplikacja, nazywamy lokalne
profil. Profil, z którym jest połączona sesja, nosi nazwę
profilu porównawczego. Gdy aplikacja SIP zaloguje się na serwerze SIP za pomocą
SipProfile
, spowoduje to efektywne zarejestrowanie
urządzenia jako lokalizacji, do której chcesz wysyłać połączenia SIP z adresu SIP.
W tej sekcji dowiesz się, jak utworzyć SipProfile
,
zarejestrować go na serwerze SIP i śledzić zdarzenia rejestracji.
Obiekt SipProfile
możesz utworzyć w ten sposób:
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();
Ten fragment kodu otwiera lokalny profil umożliwiający nawiązywanie połączeń lub
odbieranie ogólnych połączeń SIP. Rozmówca może wykonywać kolejne połączenia
mSipManager.makeAudioCall
Ten fragment określa także akcję,
android.SipDemo.INCOMING_CALL
, które będą używane przez intencję
można filtrować, gdy urządzenie zostanie odebrane (patrz Konfigurowanie
filtr intencji do odbierania połączeń). Etap rejestracji:
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);
Na koniec ten kod ustawia SipRegistrationListener
w: SipManager
. Śledzi, czy urządzenie SipProfile
zostało zarejestrowane w usłudze SIP
dostawca:
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."); } }
Gdy aplikacja skończy korzystać z profilu, powinna zamknąć się bezpłatnie. powiązanych obiektów do pamięci i wyrejestrować urządzenie z serwera. Dla: przykład:
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); } }
Rozpoczynanie rozmowy głosowej
Aby rozpocząć rozmowę głosową, musisz mieć:
SipProfile
, który nawiązuje połączenie (parametr „lokalny profil”) i prawidłowy adres SIP umożliwiający odebranie połączenia ( „profil równorzędny”).- Obiekt
SipManager
.
Aby rozpocząć rozmowę głosową, musisz skonfigurować SipAudioCall.Listener
. Duża część interakcji klienta z
stosunki SIP są możliwe dzięki detektorom. Ten fragment kodu zawiera informacje o konfiguracji usługi SipAudioCall.Listener
po zakończeniu połączenia
ustanowiono:
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. } };
Po skonfigurowaniu usługi SipAudioCall.Listener
możesz:
zadzwoń. Metoda SipManager
makeAudioCall
przyjmuje te parametry:
- Lokalny profil SIP (rozmówca).
- profil SIP połączenia równorzędnego (użytkownik jest wywoływany).
SipAudioCall.Listener
, aby odsłuchać rozmowę wydarzenia odSipAudioCall
. Może to byćnull
, Jak widać powyżej, detektor służy do konfigurowania ustawień po zakończeniu połączenia .- Wartość limitu czasu w sekundach.
Na przykład:
Kotlin
val call: SipAudioCall? = sipManager?.makeAudioCall( sipProfile?.uriString, sipAddress, listener, 30 )
Java
call = sipManager.makeAudioCall(sipProfile.getUriString(), sipAddress, listener, 30);
Odbieranie połączeń
Aby odbierać połączenia, aplikacja SIP musi zawierać podklasę BroadcastReceiver
, która może reagować na intencję
z informacją o nadejściu połączenia. Dlatego musisz wykonać następujące czynności w sekcji
Twojej aplikacji:
- W
AndroidManifest.xml
zadeklaruj parametr<receiver>
W SipDemo jest to<receiver android:name=".IncomingCallReceiver" android:label="Call Receiver" />
- Zaimplementuj odbiornik, który jest podklasą klasy
BroadcastReceiver
. W SipDemo jest toIncomingCallReceiver
- Zainicjuj profil lokalny (
SipProfile
) za pomocą intencja oczekująca, która uruchamia odbiorcę, gdy ktoś zadzwoni do profilu lokalnego. - Skonfiguruj filtr intencji, który filtruje według działania reprezentującego
połączenie przychodzące. W SipDemo to działanie jest
android.SipDemo.INCOMING_CALL
Odbieranie podklasyfikacji BroadcastReceive
Aby można było odbierać połączenia, aplikacja SIP musi podklasa BroadcastReceiver
.
System Android obsługuje przychodzące połączenia SIP i przesyła „przychodzące
wywołaj" intencję (zdefiniowaną przez aplikację), gdy otrzymana
przez telefon. Oto podklasa:
BroadcastReceiver
z przykładu 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(); } } } }
Konfiguruję filtr intencji, aby otrzymywać połączenia
Po otrzymaniu nowego połączenia usługa SIP wysyła intencję z
ciąg znaków działania dostarczony przez aplikację. W SipDemo ten ciąg znaków działania to
android.SipDemo.INCOMING_CALL
Ten fragment kodu z SipDemo pokazuje, jak obiekt SipProfile
jest tworzony z oczekującą intencją opartą na
ciąg działania android.SipDemo.INCOMING_CALL
.
Obiekt PendingIntent
przeprowadzi transmisję, gdy SipProfile
otrzyma wywołanie:
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);
Transmisja zostanie przechwycona przez filtr intencji, który następnie się uruchomi
odbiornik (IncomingCallReceiver
). Możesz określić intencję
w pliku manifestu aplikacji lub zrób to w kodzie, tak jak w przypadku SipDemo
metoda onCreate()
przykładowej aplikacji
Activity
aplikacji:
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); ... } ... }
Testowanie aplikacji SIP
Aby przetestować aplikacje SIP, potrzebujesz:
- Urządzenie mobilne z Androidem 2.3 lub nowszym. Przebieg SIP bezprzewodowo, więc musisz przeprowadzić test na konkretnym urządzeniu. Testowanie za pomocą AVD się nie uda.
- konto SIP. Konta SIP oferuje wielu różnych dostawców SIP.
- Jeśli nawiązujesz połączenie, musi ono też być powiązane z prawidłowym kontem SIP.
Aby przetestować aplikację SIP:
- Na urządzeniu połącz się z siecią bezprzewodową (Ustawienia > Sieci zwykłe i bezprzewodowe > Wi-Fi > Ustawienia Wi-Fi).
- Urządzenie mobilne musisz przygotować do testów w sposób opisany w artykule Tworzenie aplikacji na urządzeniu.
- Uruchom aplikację na urządzeniu mobilnym w sposób opisany w artykule Tworzenie aplikacji na urządzeniu.
- Jeśli korzystasz z Android Studio, dane wyjściowe dziennika aplikacji możesz wyświetlić, otwórz konsolę dziennika zdarzeń (Widok > Okna narzędzi > Dziennik zdarzeń).
- Sprawdź, czy aplikacja jest skonfigurowana tak, aby automatycznie uruchamiała Logcat po uruchomieniu:
- Wybierz Uruchom > Edytuj konfiguracje.
- Wybierz kartę Inne w oknie Konfiguracje uruchamiania/debugowania.
- W sekcji Logcat wybierz Wyświetl logcat automatycznie, a następnie kliknij OK.