偵測 eSIM 卡和 SIM 卡
正在偵測卡片
裝有 SIM 卡和 eSIM 卡的 Android 裝置會在電話中使用下列 ID API,包含 [`TelephonyManager`](/reference/android/telephony/TelephonyManager) 和 [`SubscriptionManager`](/reference/android/telephony/SubscriptionManager): * 訂閱 ID:行動訂閱項目的專屬 ID。 * 邏輯運算單元索引或 ID:代表邏輯 SIM 卡插槽的不重複索引。 邏輯運算單元 ID 從 0 開始,然後視數量而定 裝置上支援的有效運算單元。例如,雙 SIM 卡裝置通常會使用 包含版位 0 和版位 1。如果裝置有多個實體運算單元 僅支援一個有效版位,只有邏輯運算單元 ID 0。 * 實體運算單元索引或 ID:代表實體 SIM 卡插槽的不重複索引。 實體運算單元 ID 從 0 開始,然後視實體數量而定 版位顯示這個值與裝置的邏輯運算單元數量不同 ,且對應了裝置可使用的運算單元數量 使用方式。例如,在雙 SIM 卡和單一 SIM 卡之間切換的裝置 模式可能會一律有兩個實體運算單元,但在單一 SIM 卡模式中, 只會有一個邏輯運算單元 * 卡片 ID:用於識別 UiccCard 的專屬 ID。  在上圖中: * 裝置有兩個邏輯版位。 * 實體插槽 0 中有實體 UICC 卡,以及有效的設定檔。 * 實體插槽 2 是具備有效設定檔的 eUICC。 * 目前未使用實體運算單元 1。  在上圖中: * 裝置有三個邏輯插槽。 * 實體插槽 0 中有實體 UICC 卡,以及有效的設定檔。 * 實體版位 1 是 eUICC,其中包含兩個下載的設定檔,兩者皆使用 MEP (多重啟用的設定檔) 進行使用。
對話啟動協定總覽
Android 提供的 API 支援工作階段啟動協定 (SIP)。 這可讓你將 SIP 式網路電話功能加入應用程式。 Android 提供完整的 SIP 通訊協定堆疊和整合式通話管理功能 服務,以便輕鬆設定撥出電話和接聽語音電話; 不必管理工作階段、傳輸層級通訊或音訊 錄製或直接播放
以下列舉幾種可能使用 SIP API 的應用程式類型:
- 視訊會議
- 即時通訊軟體
規定和限制
以下是開發 SIP 應用程式的需求條件:
- 你的行動裝置必須搭載 Android 2.3 以上版本。
- SIP 透過無線數據連線執行,因此您的裝置必須有資料 連線 (透過行動數據服務或 Wi-Fi 連線)。這表示 您無法在 AVD 上測試,因此只能在實體裝置上測試。詳情請參閱 測試 SIP 應用程式。
- 應用程式通訊工作階段中的每位參與者都必須擁有 SIP 帳戶。許多不同的 SIP 供應商都提供 SIP 帳戶,
注意:android.net.sip
程式庫不支援影片
呼叫。如要使用如 VOIP 堆疊執行 VOIP 通話,例如:
android.net.sip
,來看看眾多現代開放原始碼軟體
替代選項。另外
您就能實作
ConnectionService
敬上
提供 API,以便將這些呼叫緊密整合到裝置的撥號程式
應用程式。
SIP API 類別和介面
以下是各類別和單一介面的摘要
(SipRegistrationListener
) 隨附於 Android SIP
API:
類別/介面 | 說明 |
---|---|
SipAudioCall |
透過 SIP 處理網路語音通話。 |
SipAudioCall.Listener |
與 SIP 呼叫相關事件的監聽器,例如通話正在進行中 或接聽來電 (「通話中」)。 |
SipErrorCode |
定義在 SIP 動作期間傳回的錯誤代碼。 |
SipManager |
提供用於 SIP 工作 (例如啟動 SIP 連線) 的 API,並提供存取權 與相關的 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) 以上版本支援此功能。 平台。此外,在搭載 Android 2.3 (API 級別 9) 以上版本的裝置中 並非所有裝置都會提供 SIP 支援。
如要使用 SIP,請將下列權限加入應用程式的資訊清單中:
android.permission.USE_SIP
android.permission.INTERNET
確保應用程式只能安裝在已安裝 請將下列項目新增至應用程式的 資訊清單:
<uses-sdk android:minSdkVersion="9" />
這表示您的應用程式需要 Android 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 伺服器註冊
典型的 Android SIP 應用程式牽涉到一或多位使用者,每個使用者
擁有 SIP 帳戶。在 Android SIP 應用程式中,每個 SIP 帳戶
由 SipProfile
物件表示
SipProfile
定義了 SIP 設定檔 (包括 SIP)
以及網域和伺服器資訊與 SIP 相關聯的設定檔
帳戶稱為「本機」
設定檔。連線至工作階段的設定檔稱為
對等互連個人資料。當 SIP 應用程式透過
本機 SipProfile
,這樣會有效註冊
讓系統將 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);
最後,此程式碼會在 SipManager
上設定 SipRegistrationListener
。用於追蹤「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
。
將 BroadcastReceiver 設為子類別
如要接聽來電,SIP 應用程式必須將 BroadcastReceiver
設為子類別。
Android 系統會處理收到的 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 服務收到新呼叫時,會發出符合下列條件的意圖:
應用程式提供的動作字串。在 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
)。您可以指定意圖
,或像 SipDemo 一樣,在程式碼中執行
範例應用程式的 onCreate()
方法
應用程式的 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 應用程式,您需要符合下列條件:
- 搭載 Android 2.3 以上版本的行動裝置。SIP 通過轉移 因此您必須在實際裝置上進行測試。AVD 測試將無法運作。
- SIP 帳戶。許多不同的 SIP 供應商都提供 SIP 帳戶,
- 如要撥打電話,通話對像也僅限有效的 SIP 帳戶。
如何測試 SIP 應用程式:
- 在裝置上,連線至無線網路 (依序前往「設定」>「無線與網路」) >Wi-Fi >Wi-Fi 設定)。
- 按照在裝置上開發的說明,設定用於測試的行動裝置。
- 按照在裝置上開發的說明,在行動裝置上執行您的應用程式。
- 如果您使用的是 Android Studio,可以透過下列方式查看應用程式記錄的輸出內容: 開啟「事件記錄」控制台 (依序點選「檢視」>「工具視窗」>「事件記錄」)。
- 請確認您的應用程式已設為在執行時自動啟動 Logcat:
- 選取 執行 >編輯設定。
- 選取「Run/Debug Configurations」視窗中的「Miscellaneous」分頁標籤。
- 在「Logcat」下方,選取「Show logcat 自動」,然後 選取「確定」。