安卓手机APP开发__构建通话应用
目录
[Surface 支持](#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() 方法会返回异常。
Kotlin
try {
callsManager.addCall(
INCOMING_CALL_ATTRIBUTES,
onIsCallAnswered, // Watch needs to know if it can answer the call
onIsCallDisconnected,
onIsCallActive,
onIsCallInactive
) {
callControlScope = this
}
}
注意: 添加通话并且设置 callControlScope 后,这并不意味着您正在进行通话,而是表示平台知道您的通话。
接听来电
拨出电话后,您必须接听或拒绝来电。本示例演示了如何接听来电:
Kotlin
when (answer(CallAttributesCompat.CALL_TYPE_AUDIO_CALL)) {
is CallControlResult.Success -> {
}
is CallControlResult.Error -> {
}
}
如果另一个通话正在进行中,answer() 将返回CallControlResult.Error,以
告知无法接听来电的原因。在这种情况下,用户需要将另一个通话置于保持状态。
拒接来电
要拒绝来电,请断开与 DisconnectCause.Rejected 的通话。
Kotlin
fun onRejectCall(){
coroutineScope.launch {
callControlScope?.let {
it.disconnect(DisconnectCause(DisconnectCause.REJECTED))
}
}
}
去电
拨出电话时,当远程方接听后,您必须将通话设置为 active,让平台知道
通话正在进行中:
Kotlin
when (setActive()) {
is CallControlResult.Success -> {
onIsCallActive()
}
is CallControlResult.Error -> {
updateCurrentCall {
copy(errorCode = result.errorCode)
}
}
}
将通话置于保持状态
如果您的通话应用支持保持通话,请使用 setInActive 告知平台您的通话未处于活跃状态,且麦克风和摄像头可供其他应用随意使用:
Kotlin
when (setInActive()) {
is CallControlResult.Success -> {
}
is CallControlResult.Error -> {
updateCurrentCall {
copy(errorCode = result.errorCode)
}
}
}
断开连接
如需断开通话连接,请提供正当原因以告知 Telecom 堆栈断开连接:
coroutineScope.launch {
callControlScope?.disconnect(DisconnectCause(DisconnectCause.LOCAL))
}
转接音频
在通话期间,用户有时会在扬声器、手机听筒或蓝牙设备等设备之间切换。
使用 availableEndpoints 和 currentCallEndpoint API
获取用户可用的所有设备以及哪个设备处于活动状态的列表。
以下示例将两个流程组合起来,创建一个界面对象,以向用户显示设备列表
以及哪个设备处于有效状态:
Kotlin
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 秒后超时并抛出事务失败。
Kotlin
callsManager.addCall(
attributes,
onIsCallAnswered, // Watch/Auto need to know if they can answer the call
onIsCallDisconnected,
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 = {}