安卓手機APP開發__構建通話應用
目錄
概述
依賴項和權限
注冊應用
平臺集成
注冊通話
添加通話
接聽來電
拒接來電
去電
將通話置于保持狀態
斷開連接
轉接音頻
前臺支持
Surface 支持
概述
使用 Telecom Jetpack 庫為用戶提供最佳視頻和音頻體驗。借助
Telecom 框架,您可以獲得通話和通知管理、前臺支持等。
新的 Jetpack 庫增加了對以下內容的支持:
??? 通話流式傳輸和轉接
??? Android Auto 和 Wear OS 集成
??? 向后兼容性
如需詳細了解如何使用 Telecom 庫構建通話應用,請參閱 Telecom 指南。
支持的電信設備
從 Android 7(API 級別 21)開始,大多數手機都支持 Telecom 框架,
必須支持 Telecom 框架,基于 SIM 卡的通話功能才能正常運行。對于
通常不需要電話實現的設備(例如平板電腦),Android 14(API 級別 34)
引入了新要求,以強制要求支持 VoIP 的平板電腦采用適當的
Telecom 框架實現。
使用 PackageManager 檢查設備是否支持電信:
packagemanager.hasSystemFeature(PackageManager.FEATURE_TELECOM)
新的 Android Telecom Jetpack 庫可讓您輕松告知平臺您的通話處于何種狀態。
依賴項和權限
首先,打開應用模塊 build.gradle 文件,然后添加 androidx Telecom 模塊的依賴項:
dependencies {
??? implementation ("androidx.core:core-telecom:1.0.0-alpha02")
}
在應用清單中,聲明您的應用使用 MANAGE_OWN_CALLS 權限:
<uses-permission android:name="android.permission.MANAGE_OWN_CALLS" />
注冊應用
如需讓 Android 知道您的應用,您必須注冊該應用及其 capability。這
會告知 Android 您的應用支持哪些功能,例如視頻通話、通話流式傳輸和保持通話。
這些信息非常重要,以便 Android 可以自行配置以使用應用的功能。
?private val callsManager = CallsManager(context)
var capabilities: @CallsManager.Companion.Capability Int =
??? CallsManager.CAPABILITY_BASELINE or
????????? CallsManager.CAPABILITY_SUPPORTS_CALL_STREAMING or
????????? CallsManager.CAPABILITY_SUPPORTS_VIDEO_CALLING
callsManager.registerAppWithTelecom(capabilities)
平臺集成
任何通話應用的兩種最常見的通話場景是來電和去電。如需正確注冊
調用的方向并適當地向用戶發送通知,請使用以下 API。
注冊通話
以下示例演示了如何注冊來電:
companion object {
? const val APP_SCHEME = "MyCustomScheme"
? const val ALL_CALL_CAPABILITIES = (CallAttributes.SUPPORTS_SET_INACTIVE
??? or CallAttributes.SUPPORTS_STREAM or CallAttributes.SUPPORTS_TRANSFER)
? const val INCOMING_NAME = "Luke"
? val INCOMING_URI: Uri = Uri.fromParts(APP_SCHEME, "", "")
? // Define all possible properties for CallAttributes
? val INCOMING_CALL_ATTRIBUTES =
??? CallAttributes(
????? INCOMING_NAME,
????? INCOMING_URI,
????? DIRECTION_INCOMING,
????? CALL_TYPE_VIDEO_CALL,
????? ALL_CALL_CAPABILITIES)
}
callAttributes 對象可以具有以下屬性:
??? displayName:調用方、會議或會話的名稱。
??? address:通話地址。請注意,這可擴展到會議鏈接。
??? direction:通話方向,例如來電或去電。
??? callType:與要傳輸的數據相關的信息,例如視頻和音頻。
??? callCapabilities:用于指定調用功能的對象。
callCapabilities 對象可以具有以下屬性:
??? streaming:指示通話是否支持將音頻流式傳輸到其他 Android 設備。
??? transfer:指示是否可以轉接來電。
??? hold:指示通話是否可以置于保持狀態。
添加通話
如果設備不支持電信,或者設置通話時出錯,則 addCall() 方法會返回異常。
try {callsManager.addCall(INCOMING_CALL_ATTRIBUTES,onIsCallAnswered, // Watch needs to know if it can answer the callonIsCallDisconnected,onIsCallActive,onIsCallInactive) {callControlScope = this}
}
注意: 添加通話并且設置 callControlScope 后,這并不意味著您正在進行通話,而是表示平臺知道您的通話。
接聽來電
撥出電話后,您必須接聽或拒絕來電。本示例演示了如何接聽來電:
when (answer(CallAttributesCompat.CALL_TYPE_AUDIO_CALL)) {is CallControlResult.Success -> {}is CallControlResult.Error -> {}
}
如果另一個通話正在進行中,answer() 將返回CallControlResult.Error,以
告知無法接聽來電的原因。在這種情況下,用戶需要將另一個通話置于保持狀態。
拒接來電
要拒絕來電,請斷開與 DisconnectCause.Rejected 的通話。
fun onRejectCall(){coroutineScope.launch {callControlScope?.let {it.disconnect(DisconnectCause(DisconnectCause.REJECTED))}}
}
去電
撥出電話時,當遠程方接聽后,您必須將通話設置為 active,讓平臺知道
通話正在進行中:
when (setActive()) {is CallControlResult.Success -> {onIsCallActive()}is CallControlResult.Error -> {updateCurrentCall {copy(errorCode = result.errorCode)}}
}
將通話置于保持狀態
如果您的通話應用支持保持通話,請使用 setInActive 告知平臺您的通話未處于活躍狀態,且麥克風和攝像頭可供其他應用隨意使用:
when (setInActive()) {is CallControlResult.Success -> {}is CallControlResult.Error -> {updateCurrentCall {copy(errorCode = result.errorCode)}}
}
斷開連接
如需斷開通話連接,請提供正當原因以告知 Telecom 堆棧斷開連接:
coroutineScope.launch {
??? callControlScope?.disconnect(DisconnectCause(DisconnectCause.LOCAL))
}
轉接音頻
在通話期間,用戶有時會在揚聲器、手機聽筒或藍牙設備等設備之間切換。
使用 availableEndpoints 和 currentCallEndpoint API
獲取用戶可用的所有設備以及哪個設備處于活動狀態的列表。
以下示例將兩個流程組合起來,創建一個界面對象,以向用戶顯示設備列表
以及哪個設備處于有效狀態:
availableEndpoint = combine(callControlScope.availableEndpoints,callControlScope.currentCallEndpoint) {availableDevices: List<CallEndpoint>, activeDevice : CallEndpoint ->availableDevices.map {EndPointUI(isActive = activeDevice.endpointName == it.endpointName, it)}
}
注意: 如果用戶連接了助聽器,平臺會自動將此設備設為默認設備。某些 OEM 可能會有不同的行為。
如需更改活躍設備,請使用 requestEndpointChange 以及要更改的 CallEndpoint。
coroutineScope.launch {
???? callControlScope?.requestEndpointChange(callEndpoint)
}
注意: 媒體流必須配置為使用 AudioManager.STREAM_VOICE_CALL
前臺支持
Telecom 庫支持前臺。對于搭載 Android 13 及更低版本的設備,此庫會
使用 ConnectionService。對于 Android 14 及更高版本,
它使用前臺類型麥克風和攝像頭來正確支持前臺服務。詳細了解前臺服務。
作為前臺要求的一部分,應用必須發布通知,讓用戶知道它正在前臺運行。
為了確保您的應用獲得前臺執行優先級,請在向平臺注冊調用后創建通知。
當應用終止調用或通知失效時,前臺優先級會被移除。
is TelecomCall.Registered -> {
??? val notification = createNotification(call)
??? notificationManager.notify(TELECOM_NOTIFICATION_ID, notification)
}
注意: 您必須在將調用添加到平臺后的 5 秒內發布通知。
Surface 支持
手表具有通用端點接收器應用。此應用可為用戶提供基本界面,例如接聽、
拒接和掛斷來電。應用通過實現 lambda 函數來支持這些操作,
以通知平臺您已在設備上執行操作。
如果您的應用沒有響應,則每個 lambda 函數都會在 5 秒后超時并拋出事務失敗。
callsManager.addCall(attributes,onIsCallAnswered, // Watch/Auto need to know if they can answer the callonIsCallDisconnected,onIsCallActive,onIsCallInactive) {
//Call Scope
}
/*** Can the call be successfully answered??* TIP: Check the connection/call state to see if you can answer a call* Example you may need to wait for another call to hold.**/
val onIsCallAnswered: suspend(type: Int) -> Unit = {}/*** Can the call perform a disconnect*/
val onIsCallDisconnected: suspend (cause: DisconnectCause) -> Unit = {}/*** Check is see if you can make the call active.* Other calls and state might stop us from activating the call*/
val onIsCallActive: suspend () -> Unit = {updateCurrentCall {}
}/*** Check to see if you can make the call inactivate*/
val onIsCallInactive: suspend () -> Unit = {}