产品动态
产品近期公告
关于 TRTC Live 正式上线的公告
关于TRTC Conference 正式版上线的公告
Conference 商业化版本即将推出
关于多人音视频 Conference 开启内测公告
关于音视频通话 Call 正式版上线的公告
关于腾讯云音视频终端 SDK 播放升级及新增授权校验的公告
关于 TRTC 应用订阅套餐服务上线的相关说明

模块 | 功能描述 |
通话视图核心组件。自动监听 CallStore 数据并完成画面渲染,同时提供布局切换、头像与图标配置等 UI 定制化能力。 | |
通话生命周期管理:拨打电话、接通电话、拒接电话、挂断电话。实时获取参与通话人员音视频状态,通话计时、通话记录等数据。 | |
音视频设备控制:麦克风(开关 / 音量)、摄像头(开关 / 切换 / 画质)、屏幕共享,设备状态实时监听。 |
api "io.trtc.uikit:atomicx-core:latest.release" 和 api "com.tencent.imsdk:imsdk-plus:8.7.7201" 依赖,然后执行 Gradle Sync 。dependencies {api "io.trtc.uikit:atomicx-core:latest.release"api "com.tencent.imsdk:imsdk-plus:8.7.7201"// 其他依赖...}

class MainActivity : ComponentActivity() {override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)// CallStore 初始化CallStore.sharedval sdkAppId = 1400000001 // 替换为您的 SDKAppIDval userId = "test_001" // 替换为您的 UserIDval userSig = "xxxxxxxxxxx" // 替换为您的 UserSigLoginStore.shared.login(this,sdkAppId,userId,userSig,object : CompletionHandler {override fun onSuccess() {// 完成 TUICallEngine 的初始化TUICallEngine.createInstance(this@MainActivity).init(sdkAppId, userId, userSig, null)// 登录成功处理Log.d("Login", "login success");}override fun onFailure(code: Int, desc: String) {// 登录失败处理Log.e("Login", "login failed, code: $code, error: $desc");}})}}
参数 | 类型 | 说明 |
userId | String | 当前用户的唯一 ID,仅包含英文字母、数字、连字符和下划线。为避免多端登录冲突,请勿使用 1、123 等简单 ID。 |
sdkAppId | int | |
userSig | String | 用于腾讯云鉴权的票据。请注意: 开发环境:您可以采用本地 GenerateTestUserSig.genTestUserSig 函数生成 userSig 或者通过 UserSig 辅助工具 生成临时的 UserSig。 生产环境:为了防止密钥泄露,请务必采用服务端生成 UserSig 的方式。详细信息请参考 服务端生成 UserSig。 |
class CallActivity : AppCompatActivity() {private var callCoreView: CallCoreView? = null// 1.创建通话页面容器override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)// 2.通话页面绑定 CallCoreViewcallCoreView = CallCoreView(this)setContentView(callCoreView)}}
功能 | 说明 | 参考文档 |
设置布局模式 | 支持自由切换布局模式。若未设置,将根据通话人数自动适配布局。 | |
设置头像 | 支持通过传入头像资源路径,为特定用户自定义头像。 | |
设置音量提示图标 | 支持根据不同音量等级,配置个性化的音量指示图标。 | |
设置网络提示图标 | 支持根据实时网络质量,配置对应的网络状态提示图标。 | |
设置等待接听用户的动画 | 在多人通话场景下,支持传入 GIF 图像路径,为待接听状态的用户展示动画。 |
import io.trtc.tuikit.atomicxcore.api.call.CallStoreimport io.trtc.tuikit.atomicxcore.api.view.CallCoreViewimport io.trtc.tuikit.atomicxcore.api.device.DeviceStoreclass CallActivity : AppCompatActivity() {private var buttonContainer: Button? = nulloverride fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)// 其他初始化代码// 创建底部栏容器createButtonContainer()setContentView(buttonContainer)}private fun createButtonContainer() {buttonContainer = LinearLayout(this).apply {orientation = LinearLayout.HORIZONTALgravity = Gravity.CENTERlayoutParams = FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT,FrameLayout.LayoutParams.WRAP_CONTENT).apply {gravity = Gravity.BOTTOMbottomMargin = dpToPx(80)}}}}
import io.trtc.tuikit.atomicxcore.api.call.CallStoreimport io.trtc.tuikit.atomicxcore.api.view.CallCoreViewimport io.trtc.tuikit.atomicxcore.api.device.DeviceStoreclass CallActivity : AppCompatActivity() {private var buttonContainer: Button? = nullprivate var buttonHangup: Button? = nulloverride fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)// 其他初始化代码// 1.在底部工具栏容器中添加挂断按钮addHangupButton()setContentView(buttonContainer)}private fun addHangupButton() {buttonHangup = Button(this).apply {text = "挂断"layoutParams = LinearLayout.LayoutParams(0, LinearLayout.LayoutParams.WRAP_CONTENT, 1f).apply {marginEnd = dpToPx(8)}setOnClickListener {// 2.在点击事件中调用 hangup 接口并销毁页面CallStore.shared.hangup(null)finish()}}buttonContainer?.addView(buttonHangup)}}
import io.trtc.tuikit.atomicxcore.api.call.CallStoreimport io.trtc.tuikit.atomicxcore.api.view.CallCoreViewimport io.trtc.tuikit.atomicxcore.api.device.DeviceStoreclass CallActivity : AppCompatActivity() {private var buttonContainer: Button? = nullprivate var buttonMicrophone: Button? = nulloverride fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)// 其他初始化代码// 1.在底部工具栏容器中添加麦克风开关addMicrophoneButton()setContentView(buttonContainer)}private fun addMicrophoneButton() {buttonMicrophone = Button(this).apply {layoutParams = LinearLayout.LayoutParams(0, LinearLayout.LayoutParams.WRAP_CONTENT, 1f).apply {setMargins(16, 0, 16, 0)}setOnClickListener {// 2.点击事件调用开启或关闭麦克风val isMicrophoneOpen = DeviceStore.shared().deviceState.microphoneStatus.value == DeviceStatus.ONif (isMicrophoneOpen) {DeviceStore.shared().closeLocalMicrophone()} else {DeviceStore.shared().openLocalMicrophone(null)}}}val isMicrophoneOpen = DeviceStore.shared().deviceState.microphoneStatus.value == DeviceStatus.ONbuttonMicrophone?.text = if (isMicrophoneOpen) "关麦克风" else "开麦克风"buttonContainer?.addView(buttonMicrophone)}}
import io.trtc.tuikit.atomicxcore.api.call.CallStoreimport io.trtc.tuikit.atomicxcore.api.view.CallCoreViewimport io.trtc.tuikit.atomicxcore.api.device.DeviceStoreclass CallActivity : AppCompatActivity() {private var buttonContainer: Button? = nullprivate var buttonCamera: Button? = nulloverride fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)// 其他初始化代码// 1.在底部工具栏容器中添加摄像头开关按钮addCameraButton()setContentView(buttonContainer)}private fun addCameraButton() {buttonCamera = Button(this).apply {layoutParams = LinearLayout.LayoutParams(0, LinearLayout.LayoutParams.WRAP_CONTENT, 1f).apply {setMargins(16, 0, 16, 0)}setOnClickListener {// 2.点击事件调用开启或关闭摄像头val isCameraOpen = DeviceStore.shared().deviceState.cameraStatus.value == DeviceStatus.ONif (isCameraOpen) {DeviceStore.shared().closeLocalCamera()} else {val isFrontCamera = DeviceStore.shared().deviceState.isFrontCamera.valueDeviceStore.shared().openLocalCamera(isFrontCamera, null)}}}val isCameraOpen = DeviceStore.shared().deviceState.cameraStatus.value == DeviceStatus.ONbuttonCamera?.text = if (isCameraOpen) "关摄像头" else "开摄像头"buttonContainer?.addView(buttonCamera)}}
import io.trtc.tuikit.atomicxcore.api.call.*import io.trtc.tuikit.atomicxcore.api.device.DeviceStoreimport kotlinx.coroutines.*class CallActivity : AppCompatActivity() {private var buttonCamera: Button? = nullprivate var buttonMicrophone: Button? = nulloverride fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)// 其他初始化代码// 1.监听麦克风和摄像头的状态observeDeviceState()}private fun observeDeviceState() {deviceStateJob = CoroutineScope(Dispatchers.Main).launch {supervisorScope {launch {DeviceStore.shared().deviceState.cameraStatus.collect { status ->// 2.更新摄像头按钮文本buttonCamera?.text = if (status == DeviceStatus.ON) "关闭摄像头" else "开启摄像头"}}launch {DeviceStore.shared().deviceState.microphoneStatus.collect { status ->// 2.更新麦克风按钮文本buttonMicrophone?.text = if (status == DeviceStatus.ON) "关闭麦克风" else "开启麦克风"}}}}}}
AndroidManifest.xml 文件中声明应用需要的摄像头和麦克风权限。<manifest xmlns:android="http://schemas.android.com/apk/res/android"><!-- 麦克风权限 --><uses-permission android:name="android.permission.RECORD_AUDIO" /><!-- 摄像头权限 --><uses-permission android:name="android.permission.CAMERA" /><application><!-- ... --><activityandroid:name=".CallActivity"android:exported="false"android:screenOrientation="portrait" /></application></manifest>
// 动态申请权限private fun requestAllCallPermissions() {val allPermissions = arrayOf(Manifest.permission.CAMERA,Manifest.permission.RECORD_AUDIO)if (!checkPermissions(allPermissions)) {ActivityCompat.requestPermissions(this, allPermissions, PERMISSION_REQUEST_CODE)}}// 处理权限申请结果override fun onRequestPermissionsResult(requestCode: Int,permissions: Array<out String>,grantResults: IntArray) {super.onRequestPermissionsResult(requestCode, permissions, grantResults)if (requestCode == PERMISSION_REQUEST_CODE) {// 检查是否所有权限都已授予var allGranted = truefor (result in grantResults) {if (result != PackageManager.PERMISSION_GRANTED) {allGranted = falsebreak}}if (allGranted) {// 权限申请成功} else {// 部分权限被拒绝}}}
calls 发起通话。import io.trtc.tuikit.atomicxcore.api.CompletionHandlerimport io.trtc.tuikit.atomicxcore.api.call.CallMediaTypeimport io.trtc.tuikit.atomicxcore.api.call.CallStoreclass MainActivity : ComponentActivity() {// 1.发起通话private fun startCall(userIdList: List<String>, mediaType: CallMediaType) {CallStore.shared.calls(userIdList, mediaType, null, object : CompletionHandler {override fun onFailure(code: Int, desc: String) {}override fun onSuccess() {// 2.开启媒体设备openDeviceForMediaType(mediaType)// 3.唤起通话页面val intent = Intent(this@MainActivity, CallActivity::class.java)startActivity(intent)}})}private fun openDeviceForMediaType(mediaType: CallMediaType?) {if (mediaType == null) {return}DeviceStore.shared().openLocalMicrophone(null)if (mediaType == CallMediaType.Video) {val isFrontCamera = DeviceStore.shared().deviceState.isFrontCamera.valueDeviceStore.shared().openLocalCamera(isFrontCamera, null)}}}
参数 | 类型 | 是否必填 | 说明 |
userIdList | List<String> | 是 | 目标用户的 userId 列表。 |
mediaType | 是 | 通话媒体类型,用于指定发起音频通话还是视频通话。 CallMediaType.Video:视频通话。CallMediaType.Audio:语音通话。 | |
params | 否 | 通话扩展参数,如:房间号、通话邀请超时时间等。 roomId (String):房间 ID,可选参数,未指定时由服务端自动分配。timeout (Int):呼叫超时时间(秒)。userData (String):用户自定义数据。chatGroupId (String):Chat 群组 ID,用于群组通话场景。isEphemeralCall (Boolean):是否为加密通话(不产生通话记录)。 |
onCallEnded 事件。onCallEnded 触发后,销毁通话页面。import io.trtc.tuikit.atomicxcore.api.call.CallEndReasonimport io.trtc.tuikit.atomicxcore.api.call.CallListenerimport io.trtc.tuikit.atomicxcore.api.call.CallMediaTypeimport io.trtc.tuikit.atomicxcore.api.call.CallStoreclass CallActivity : AppCompatActivity() {private var callListener: CallListener? = nulloverride fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)// ... 其他初始化代码// 1.监听通话结束事件addListener()}private fun addListener() {callListener = object : CallListener() {override fun onCallEnded(callId: String, mediaType: CallMediaType, reason: CallEndReason, userId: String) {// 2.销毁通话页面finish()}}callListener?.let { CallStore.shared.addListener(it) }}}
参数 | 类型 | 说明 |
callId | String | 此次通话的唯一标识。 |
mediaType | 通话媒体类型,用于指定发起音频通话还是视频通话。 CallMediaType.Video:视频通话。CallMediaType.Audio:语音通话。 | |
reason | 通话结束的原因。 Unknown:未知原因,无法确定结束原因。Hangup:正常挂断,用户主动挂断通话。Reject:拒绝接听,被叫方拒绝来电。NoResponse:无响应,被叫方未在超时时间内接听。Offline:对方离线,被叫方不在线。LineBusy:对方忙线,被叫方正在通话中。Canceled:通话取消,主叫方在对方接听前取消。OtherDeviceAccepted:其他设备已接听,通话已在另一登录设备上接听。OtherDeviceReject:其他设备已拒绝,通话已在另一登录设备上拒绝。EndByServer:服务器结束,通话被服务器终止。 | |
userId | String | 触发结束的用户 ID 。 |


private fun setIconResourcePath() {val volumeLevelIcons = mapOf(VolumeLevel.Mute to "对应图标资源的路径")val callCoreView = CallCoreView(context)callCoreView.setVolumeLevelIcons(volumeLevelIcons)}
参数 | 类型 | 是否必填 | 说明 |
icons | 是 | 音量等级与图标资源的映射表。 key ( VolumeLevel ) 表示音量等级: VolumeLevel.Mute:表示麦克风关闭,静音状态。VolumeLevel.Low:表示音量范围 (0-25]。VolumeLevel.Medium:表示音量范围 (25-50]。VolumeLevel.High:表示音量范围在 (50-75]。VolumeLevel.Peak:表示音量范围在 (75-100]。Value ( String ) 表示对应音量等级的图标资源路径。 |

private fun setNetworkQualityIcons() {val volumeLevelIcons = mapOf(NetworkQuality.BAD to "对应图标的路径")val callCoreView = CallCoreView(context)callCoreView.setNetworkQualityIcons(volumeLevelIcons)}
参数 | 类型 | 是否必填 | 说明 |
icons | 是 | 网络质量与图标资源的映射表。 Key ( NetworkQuality ):表示网络质量等级。 NetworkQuality.UNKNOWN:未知网络状态。NetworkQuality.EXCELLENT:网络状态极佳。NetworkQuality.GOOD:网络状态较好。NetworkQuality.POOR:网络状态较差。NetworkQuality.BAD:网络状态差。NetworkQuality.VERY_BAD:网络状态极差。NetworkQuality.DOWN:网络断开。Value ( String ):对应网络状态的图标资源路径。 |
图标 | 说明 | 下载地址 |
![]() | 网络较差的提示图标。 您可以将该图标等级设置为 NetworkQuality.BAD、NetworkQuality.VERY_BAD 或 NetworkQuality.DOWN ,当网络较差时显示该图标。 |
private fun setParticipantAvatars() {val avatars: MutableMap<String, String> = mutableMapOf()val userId = "" // 用户 IDval avatarPath = "" // 用户默认头像资源的路径avatars[userId] = avatarPathval callCoreView = CallCoreView(context)callCoreView.setParticipantAvatars(avatars)}
参数 | 类型 | 是否必填 | 说明 |
icons | Map<String, String> | 是 | 用户头像映射表。 Key:用户的 userID 。 Value:该用户的头像资源绝对路径。 |
图标 | 说明 | 下载地址 |
![]() | 默认头像。 当用户头像加载失败或无头像时,您可以给该用户设置此默认头像。 |

private fun setWaitingAnimation() {val waitingAnimationPath = "" // 等待动画 GIF 图像资源的路径val callCoreView = CallCoreView(context)callCoreView.setWaitingAnimation(waitingAnimationPath)}
参数 | 类型 | 是否必填 | 说明 |
path | String | 是 | GIF 格式图像资源的绝对路径。 |
图标 | 说明 | 下载地址 |
![]() | 用户等待接听动画。 群组通话时设置的动画。设置后,当用户的状态为等待接听时,显示该动画。 |
CallStore.observerState.activeCall , 建立当前活跃通话的响应式监听。activeCall.duration 字段绑定至 UI 控件。该字段为响应式数据,会自动驱动 UI 实时刷新,无需手动维护定时器。import android.content.Contextimport androidx.appcompat.widget.AppCompatTextViewimport androidx.core.content.ContextCompatimport com.tencent.qcloud.tuicore.util.DateTimeUtilimport io.trtc.tuikit.atomicxcore.api.call.CallStoreimport io.trtc.tuikit.atomicxcore.api.call.CallParticipantStatusimport kotlinx.coroutines.CoroutineScopeimport kotlinx.coroutines.Dispatchersimport kotlinx.coroutines.Jobimport kotlinx.coroutines.launchclass TimerView(context: Context) : AppCompatTextView(context) {private var subscribeStateJob: Job? = nulloverride fun onAttachedToWindow() {super.onAttachedToWindow()// 1.数据层订阅 activeCallregisterActiveCallObserver()}private fun registerActiveCallObserver() {subscribeStateJob = CoroutineScope(Dispatchers.Main).launch {CallStore.shared.observerState.activeCall.collect { activeCall ->// 2.绑定通话计时数据,更新通话计时updateDurationView(activeCall)}}}private fun updateDurationView(activeCall: CallInfo) {val currentDuration = activeCall.durationtext = DateTimeUtil.formatSecondsTo00(currentDuration.toInt())}override fun onDetachedFromWindow() {super.onDetachedFromWindow()subscribeStateJob?.cancel()}}
val user = UserProfile()user.userID = "" // 您的 userIduser.avatarURL = "" // 头像的 urluser.nickname = "" // 需要设置的昵称LoginStore.shared.setSelfInfo(user, object : CompletionHandler {override fun onSuccess() {// 设置成功回调}override fun onFailure(code: Int, desc: String) {// 设置失败回调}})
参数 | 类型 | 是否必填 | 说明 |
userProfile | 是 | 用户信息结构体。 userID (String):用户的 ID 。avatarURL (String):用户头像的 URL。nickname (String):用户的昵称。 | |
completion | CompletionHandler | 否 | 操作完成回调,用于返回接通电话的结果。 |
Float 模式,多人通话场景下则自动切换为 Grid 模式。不同布局模式的说明如下:Float 模式 | Grid 模式 | PIP 模式 |
![]() | ![]() | ![]() |
布局逻辑:呼叫等待时全屏显示己方画面;接通后全屏显示对方画面,己方画面以悬浮小窗展示。 交互特性:支持小窗拖拽移动,点击小窗可实现大小画面互换。 | 布局逻辑:所有成员画面呈网格状平铺排列成宫格模式布局,适用 2 人以上通话,支持点击放大画面功能。 交互特性:支持点击特定成员画面放大查看。 | 布局逻辑:1v1 场景固定显示对方画面,多人场景:采用当前发言者(Active Speaker) 策略,自动识别并全屏展示正在说话的用户。 交互特性:等待时显示自己的画面,接通后还会显示通话计时。 |
private fun setLayoutTemplate() {val callCoreView = CallCoreView(context)val template = CallLayoutTemplate.Grid// 设置布局模式callCoreView.setLayoutTemplate(template)setContentView(callCoreView)}
参数 | 类型 | 是否必填 | 说明 |
template | 是 | CallCoreView 的布局模式。 CallLayoutTemplate.Float:布局逻辑:呼叫等待时全屏显示己方画面;接通后全屏显示对方画面,己方画面以悬浮小窗展示。 交互特性:支持小窗拖拽移动,点击小窗可实现大小画面互换。 CallLayoutTemplate.Grid:布局逻辑:所有成员画面呈网格状平铺排列成宫格模式布局,适用 2 人以上通话,支持点击放大画面功能。 交互特性:支持点击特定成员画面放大查看。 CallLayoutTemplate.Pip:布局逻辑:1v1 场景固定显示对方画面,多人场景:采用当前发言者(Active Speaker) 策略,自动识别并全屏展示正在说话的用户。 交互特性:等待时显示自己的画面,接通后还会显示通话计时。 |
val callParams = CallParams()callParams.timeout = 30 // 设置通话超时CallStore.shared.calls(userIdList, CallMediaType.Video, callParams, null)
参数 | 类型 | 是否必填 | 说明 |
userIdList | List<String> | 是 | 目标用户的 userId 列表。 |
mediaType | 是 | 通话媒体类型,用于指定发起音频通话还是视频通话。 CallMediaType.Video:视频通话。CallMediaType.Audio:语音通话。 | |
params | 否 | 通话扩展参数,如:房间号、通话邀请超时时间等。 roomId (String):房间 ID,可选参数,未指定时由服务端自动分配。timeout (Int):呼叫超时时间(秒)。userData (String):用户自定义数据。chatGroupId (String):Chat 群组 ID,用于群组通话场景。isEphemeralCall (Boolean):是否为加密通话(不产生通话记录)。 |
Pip 布局获得更好的体验。enterPictureInPictureMode 启动画中画模式。private fun enterPictureInPictureModeWithBuild() {if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && hasPipModePermission()) {val pictureInPictureParams: PictureInPictureParams.Builder = PictureInPictureParams.Builder()val floatViewWidth = resources.getDimensionPixelSize(R.dimen.callkit_video_small_view_width)val floatViewHeight = resources.getDimensionPixelSize(R.dimen.callkit_video_small_view_height)val aspectRatio = Rational(floatViewWidth, floatViewHeight)pictureInPictureParams.setAspectRatio(aspectRatio).build()this.enterPictureInPictureMode(pictureInPictureParams.build())}}
onPictureInPictureModeChanged 回调中,若检测到进入画中画模式,请将 CallCoreView 的布局设置为 Pip 模式:val callCoreView = CallCoreView(context)override fun onPictureInPictureModeChanged(isInPictureInPictureMode: Boolean) {super.onPictureInPictureModeChanged(isInPictureInPictureMode)if (isInPictureInPictureMode) {callCoreView.setLayoutTemplate(CallLayoutTemplate.Pip)}}
onResume 回调。您可以在该回调中,根据当前通话的人数重新设置布局。若当前为 1 v 1 通话:设置为 Float,多人通话:设置为 Grid。val callCoreView = CallCoreView(context)override fun onResume() {super.onResume()val allParticipants = CallStore.shared.observerState.allParticipants.valueif (allParticipants.size > 2) {callCoreView?.setLayoutTemplate(CallLayoutTemplate.Grid)} else {callCoreView?.setLayoutTemplate(CallLayoutTemplate.Float)}}
WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON 标志来实现此功能,这是最简单且推荐的方式。class CallActivity : AppCompatActivity() {override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)window.addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED or // 锁屏时显示WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD or // 解锁屏幕WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON or // 保持屏幕常亮WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON // 点亮屏幕)setContentView(R.layout.activity_call)}}
MainScope().launch {CallStore.shared.observerState.selfInfo.collect { selfInfo ->if (selfInfo.status == CallParticipantStatus.Accept || selfInfo.status == CallParticipantStatus.None) {// 停止播放铃声return@collect}if (selfInfo.status == CallParticipantStatus.Waiting) {// 播放铃声}}
<manifest xmlns:android="http://schemas.android.com/apk/res/android"><uses-permission android:name="android.permission.FOREGROUND_SERVICE" /><uses-permission android:name="android.permission.FOREGROUND_SERVICE_CAMERA" /><uses-permission android:name="android.permission.FOREGROUND_SERVICE_MICROPHONE" /><application><serviceandroid:name=".CallForegroundService"android:enabled="true"android:exported="false"android:foregroundServiceType="camera|microphone" /></application></manifest>
import android.app.Notificationimport android.app.NotificationChannelimport android.app.NotificationManagerimport android.app.Serviceimport android.content.Contextimport android.content.Intentimport android.os.Buildimport android.os.IBinderimport androidx.core.app.NotificationCompatclass CallForegroundService : Service() {companion object {private const val NOTIFICATION_ID = 1001private const val CHANNEL_ID = "call_foreground_channel"fun start(context: Context) {val intent = Intent(context, CallForegroundService::class.java)if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {context.startForegroundService(intent)} else {context.startService(intent)}}fun stop(context: Context) {val intent = Intent(context, CallForegroundService::class.java)context.stopService(intent)}}override fun onCreate() {super.onCreate()createNotificationChannel()// 启动前台通知,确保后台采集权限startForeground(NOTIFICATION_ID, createNotification())}override fun onBind(intent: Intent?): IBinder? = nullprivate fun createNotification(): Notification {return NotificationCompat.Builder(this, CHANNEL_ID).setContentTitle("正在通话中").setContentText("应用正在后台运行以保持通话").setSmallIcon(android.R.drawable.ic_menu_call) // 请替换为您的应用图标.setPriority(NotificationCompat.PRIORITY_HIGH).build()}private fun createNotificationChannel() {if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {val channel = NotificationChannel(CHANNEL_ID,"通话保活服务",NotificationManager.IMPORTANCE_HIGH)val manager = getSystemService(NotificationManager::class.java)manager.createNotificationChannel(channel)}}}
功能 | 描述 | 集成指引 |
接听第一通电话 | 引导您快速完成接听流程集成。涵盖通话界面唤起、接听及拒接等核心控制功能。 |
AndroidManifest.xml 声明通话界面的 Activity 为一个独立的任务栈。<activityandroid:name=".view.CallActivity" <!-- 您的通话界面 -->android:launchMode="singleTask"android:taskAffinity="${applicationId}.call" />
文档反馈