@tencentcloud/sdk-mcp 1.7.3 → 1.7.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +13 -0
- package/README.md +13 -13
- package/knowledge/path-meta.js +23 -1
- package/package.json +1 -1
- package/resource/index/manifest.json +1 -1
- package/resource/integration/callkit/preset/android/integration.md +4 -0
- package/resource/integration/callkit/preset/flutter/integration.md +4 -0
- package/resource/integration/callkit/preset/ios/integration.md +14 -13
- package/resource/integration/callkit/preset/vue/integration.md +0 -3
- package/resource/integration/chat/preset/android/integration.md +3 -145
- package/resource/integration/chat/preset/flutter/integration.md +20 -128
- package/resource/integration/chat/preset/ios/integration.md +2 -269
- package/resource/integration/chat/preset/react/integration.md +27 -1
- package/resource/integration/chat/preset/uni-app/integration.md +5 -1
- package/resource/integration/chat/preset/vue/integration.md +21 -31
- package/resource/integration/livekit/preset/live/android/live-host-integration.md +4 -0
- package/resource/integration/livekit/preset/live/ios/live-host-integration.md +4 -0
- package/resource/integration/livekit/preset/live/vue/live-list-integration.md +3 -4
- package/resource/integration/livekit/preset/live/vue/live-player-desk-integration.md +0 -1
- package/resource/integration/livekit/preset/live/vue/live-player-h5-integration.md +0 -1
- package/resource/integration/livekit/preset/live/vue/live-pusher-integration.md +4 -9
- package/resource/integration/roomkit/preset/vue/integration.md +0 -213
- package/resource/knowledge/callkit/best-practice/android/video-chat-dating.md +490 -0
- package/resource/knowledge/callkit/best-practice/flutter/android-keep-call-alive-background.md +79 -0
- package/resource/knowledge/callkit/best-practice/flutter/background-incoming-call-no-notification.md +99 -0
- package/resource/knowledge/callkit/best-practice/flutter/ios-keep-call-alive-background.md +93 -0
- package/resource/knowledge/callkit/best-practice/flutter/ios-startup-crash-version-voip.md +68 -0
- package/resource/knowledge/callkit/core-sdk/flutter/offline-push.md +1 -1
- package/resource/knowledge/callkit/core-sdk/ios/answer-call.md +9 -7
- package/resource/knowledge/callkit/core-sdk/ios/make-call.md +10 -7
- package/resource/knowledge/callkit/core-sdk/miniprogram/call-engine.md +19 -19
- package/resource/knowledge/callkit/core-sdk/miniprogram/call-event.md +16 -16
- package/resource/knowledge/callkit/core-sdk/uni-app/answer-call.md +0 -84
- package/resource/knowledge/callkit/core-sdk/uni-app/make-call.md +0 -102
- package/resource/knowledge/callkit/core-sdk/web/call-event.md +2 -2
- package/resource/knowledge/callkit/faq/error-code.md +62 -36
- package/resource/knowledge/callkit/faq/uniapp-miniprogram.md +1 -1
- package/resource/knowledge/callkit/preset/android/api.md +10 -10
- package/resource/knowledge/callkit/preset/harmonyos/api.md +362 -0
- package/resource/knowledge/callkit/preset/harmonyos/integration.md +322 -0
- package/resource/knowledge/callkit/preset/ios/api.md +9 -9
- package/resource/knowledge/callkit/preset/miniprogram/api-uniapp.md +293 -0
- package/resource/knowledge/callkit/preset/miniprogram/api.md +19 -19
- package/resource/knowledge/callkit/preset/miniprogram/integration.md +292 -0
- package/resource/knowledge/callkit/preset/miniprogram/uniapp-integration.md +521 -0
- package/resource/knowledge/callkit/preset/uni-app/api.md +49 -0
- package/resource/knowledge/callkit/preset/uni-app/integration.md +353 -0
- package/resource/knowledge/chat/preset/android-view/integration.md +52 -100
- package/resource/knowledge/chat/preset/ios/features/language.md +5 -5
- package/resource/knowledge/chat/preset/ios-uikit/integration.md +184 -923
- package/resource/knowledge/chat/preset/react/features/search.md +9 -214
- package/resource/knowledge/chat/preset/react/h5/integration.md +965 -0
- package/resource/knowledge/chat/preset/vue/features/chat-header.md +0 -36
- package/resource/knowledge/chat/preset/vue/features/contact-list.md +0 -34
- package/resource/knowledge/chat/preset/vue/features/conversation-list.md +0 -39
- package/resource/knowledge/chat/preset/vue/features/conversation-preview.md +0 -74
- package/resource/knowledge/chat/preset/vue/features/search.md +9 -790
- package/resource/knowledge/chat/preset/vue/h5/integration.md +724 -0
- package/resource/knowledge/livekit/core-sdk/features/uni-app/live-list.md +0 -167
- package/resource/knowledge/livekit/core-sdk/live/android/co-guest-interaction.md +1 -1
- package/resource/knowledge/livekit/core-sdk/live/android/host-interaction.md +1 -1
- package/resource/knowledge/livekit/core-sdk/live/flutter/co-guest-interaction.md +1 -1
- package/resource/knowledge/livekit/core-sdk/live/flutter/host-interaction.md +1 -1
- package/resource/knowledge/livekit/core-sdk/live/flutter/integration.md +1 -1
- package/resource/knowledge/livekit/core-sdk/live/ios/co-guest-interaction.md +1 -1
- package/resource/knowledge/livekit/core-sdk/live/ios/host-interaction.md +1 -1
- package/resource/knowledge/livekit/core-sdk/live/ios/integration.md +2 -2
- package/resource/knowledge/livekit/core-sdk/live/uni-app/co-guest-interaction.md +1 -66
- package/resource/knowledge/livekit/core-sdk/live/uni-app/host-interaction.md +1 -66
- package/resource/knowledge/livekit/core-sdk/live/uni-app/integration.md +1 -1
- package/resource/knowledge/livekit/core-sdk/voice/android/co-guest-interaction.md +1 -1
- package/resource/knowledge/livekit/core-sdk/voice/android/host-interaction.md +2 -2
- package/resource/knowledge/livekit/core-sdk/voice/flutter/co-guest-interaction.md +1 -1
- package/resource/knowledge/livekit/core-sdk/voice/ios/co-guest-interaction.md +1 -1
- package/resource/knowledge/livekit/core-sdk/voice/ios/host-interaction.md +2 -2
- package/resource/knowledge/livekit/core-sdk/voice/uni-app/integration.md +2 -2
- package/resource/knowledge/livekit/preset/live/vue/features/barrage.md +1 -24
- package/resource/knowledge/livekit/preset/live/vue/features/live-audience-list.md +0 -3
- package/resource/knowledge/livekit/preset/live/vue/features/live-view.md +0 -5
- package/resource/knowledge/push/api-reference/harmonyos.md +9 -9
- package/resource/knowledge/push/api-reference/unity.md +10 -10
- package/resource/knowledge/push/api-reference/unreal-engine.md +11 -11
- package/resource/knowledge/push/integration/android.md +57 -13
- package/resource/knowledge/push/integration/donut.md +3 -3
- package/resource/knowledge/push/integration/flutter.md +38 -24
- package/resource/knowledge/push/integration/harmonyos.md +1 -11
- package/resource/knowledge/push/integration/ios.md +21 -6
- package/resource/knowledge/push/integration/react-native.md +1 -1
- package/resource/knowledge/push/integration/uni-app.md +1 -1
- package/resource/knowledge/push/integration/unity.md +1 -1
- package/resource/knowledge/push/integration/unreal-engine.md +2 -2
- package/resource/knowledge/roomkit/core-sdk/android/room-state.md +3 -3
- package/resource/knowledge/roomkit/core-sdk/android/schedule-room.md +4 -4
- package/resource/knowledge/roomkit/core-sdk/flutter/room-state.md +2 -2
- package/resource/knowledge/roomkit/core-sdk/flutter/schedule-room.md +4 -4
- package/resource/knowledge/roomkit/core-sdk/ios/room-state.md +3 -3
- package/resource/knowledge/roomkit/core-sdk/ios/schedule-room.md +4 -4
- package/resource/knowledge/roomkit/core-sdk/vue/device-detection.md +0 -9
- package/resource/knowledge/roomkit/core-sdk/vue/free-beauty-panel.md +0 -9
- package/resource/knowledge/roomkit/core-sdk/vue/room-chat.md +0 -3
- package/resource/knowledge/roomkit/core-sdk/vue/room-view.md +0 -16
- package/resource/knowledge/roomkit/core-sdk/vue/schedule-room.md +0 -3
- package/resource/knowledge/roomkit/core-sdk/vue/virtual-background.md +0 -3
- package/resource/knowledge/roomkit/core-sdk/vue/whiteboard-annotation.md +0 -15
- package/resource/knowledge/roomkit/preset/android/integration.md +1 -202
- package/resource/knowledge/roomkit/preset/flutter/integration.md +13 -13
- package/resource/knowledge/roomkit/preset/harmonyos/integration.md +6 -2
- package/resource/knowledge/roomkit/preset/ios/integration.md +0 -201
- package/resource/knowledge/roomkit/preset/react/integration.md +0 -202
- package/resource/knowledge/roomkit/preset/uniapp-app/integration.md +207 -509
- package/resource/knowledge/rtcengine/web/plugin/42-advanced-realtime-transcriber.md +25 -6
- package/server.js +1 -1
- package/utils/report-cls-client.js +1 -1
- package/utils/report-es-client.js +1 -1
|
@@ -0,0 +1,490 @@
|
|
|
1
|
+
本文将为您介绍如何快速跑通音视频通话 Demo。跟随本文档,您可以在 10 分钟内跑通 Demo,并最终体验一个包含完备 UI 界面的 1v1 视频交友功能。
|
|
2
|
+
|
|
3
|
+
## 前提条件
|
|
4
|
+
|
|
5
|
+
### 环境准备
|
|
6
|
+
- 安装 [Android Studio](https://developer.android.com/studio)。
|
|
7
|
+
|
|
8
|
+
- 两台以上 Android 5.0 的设备。
|
|
9
|
+
|
|
10
|
+
### 开通服务
|
|
11
|
+
|
|
12
|
+
## 跑通 Demo
|
|
13
|
+
|
|
14
|
+
### 步骤 1: 下载 Demo
|
|
15
|
+
|
|
16
|
+
您可以直接从 GitHub 下载 [VideoChat Demo](https://github.com/Tencent-RTC/video-chat-solution) 源码,或者在命令行中运行以下命令:
|
|
17
|
+
``` java
|
|
18
|
+
git clone https://github.com/Tencent-RTC/video-chat-solution.git
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
### 步骤 2: 配置 Demo
|
|
22
|
+
1. **配置 SDKAppID 和 SecretKey (必须):**打开 `video-chat-solution/blob/main/android/app/src/main/java/io/trtc/uikit/demo/debug/GenerateTestUserSig.java` 文件,将开通服务时获取到的 `SDKAppID` 和 `SDKSecretKey` 填入其中:
|
|
23
|
+
|
|
24
|
+
2. **配置美颜(可选):**Demo 默认集成了腾讯基础美颜,需配置 License 方可生效。请参考 [License 指引](https://cloud.tencent.com/document/product/616/79137) 获取 LicenseURL 和 LicenseKey,并将其填入 `video-chat-solution/android/app/src/main/java/io/trtc/uikit/demo/debug/GenerateTestUserSig.java` 文件中。
|
|
25
|
+
|
|
26
|
+
### 步骤 3: 运行 Demo
|
|
27
|
+
1. **导入推荐测试用户:**为了方便体验,请运行项目 `video-chat-solution/tools/import_users_to_video_chat.py` 脚本(需填入您的 AppID 和 SecretKey)。该脚本将自动注册 6 个推荐测试账号,登录后即可在“交友”模块中看到他们。
|
|
28
|
+
|
|
29
|
+
2. **编译运行:**请选择设备并运行 Demo。
|
|
30
|
+
|
|
31
|
+
3. **Demo 运行成功:**完成登录后,展示如下界面。
|
|
32
|
+
|
|
33
|
+
### 步骤 4: 视频与聊天互动
|
|
34
|
+
1. **与推荐用户互动:**您可以使用另一台设备 B 登录 “推荐用户” 的账号(以 UserID: VideoChatlinxiaoyu 为例),完成 1v1 聊天与视频互动。
|
|
35
|
+
|
|
36
|
+
- **设备 A :** 登录账号并关注推荐用户 “陈可欣”,并进行聊天和视频互动:
|
|
37
|
+
|
|
38
|
+
- **设备 B** : 登录账号,进行聊天与视频互动。
|
|
39
|
+
|
|
40
|
+
## 快速接入
|
|
41
|
+
|
|
42
|
+
为方便您快速上线,您可以直接集成 Demo 中的 UI 组件完成 1v1 聊天、通话等核心功能 。
|
|
43
|
+
|
|
44
|
+
### 步骤 1: 集成组件
|
|
45
|
+
1. 从 GitHub 仓库下载 [VideoChat Demo](https://github.com/Tencent-RTC/video-chat-solution) 源码,并拷贝 `video-chat` 和 `tuikit` 组件复制到您的工程目录下:
|
|
46
|
+
|
|
47
|
+
2. 在 `settings.gradle` 中添加以下代码,完成功能接入。
|
|
48
|
+
|
|
49
|
+
``` java
|
|
50
|
+
// 引入上层应用模块
|
|
51
|
+
include ':app'
|
|
52
|
+
|
|
53
|
+
// 引入 1v1 视频交友界面模块
|
|
54
|
+
include ':video-chat'
|
|
55
|
+
|
|
56
|
+
// 引入公共模块
|
|
57
|
+
include(":atomic_x")
|
|
58
|
+
project(":atomic_x").projectDir = file("./tuikit/atomic_x")
|
|
59
|
+
|
|
60
|
+
// 引入会话模块
|
|
61
|
+
include ':tuichat'
|
|
62
|
+
project(':tuichat').projectDir = file("./tuikit/chat")
|
|
63
|
+
|
|
64
|
+
// 引入美颜功能模块
|
|
65
|
+
include ':tebeautykit'
|
|
66
|
+
project(':tebeautykit').projectDir = file("./tuikit/tebeautykit")
|
|
67
|
+
|
|
68
|
+
// 引入特效播放器模块
|
|
69
|
+
include ':tceffectplayerkit'
|
|
70
|
+
project(':tceffectplayerkit').projectDir = file("./tuikit/tceffectplayerkit")
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### 步骤 2: 完成登录
|
|
74
|
+
|
|
75
|
+
登录鉴权后才能正常使用组件的功能。调用 LoginStore 的 login 接口,传入上文获取的 sdkAppID、userID、userSig 进行登录鉴权:
|
|
76
|
+
``` java
|
|
77
|
+
|
|
78
|
+
import io.trtc.tuikit.atomicxcore.api.CompletionHandler
|
|
79
|
+
import io.trtc.tuikit.atomicxcore.api.login.LoginStore
|
|
80
|
+
|
|
81
|
+
LoginStore.shared.login(
|
|
82
|
+
context,
|
|
83
|
+
sdkAppID, // Int,控制台获取
|
|
84
|
+
userID, // String
|
|
85
|
+
userSig, // String,控制台或服务端生成
|
|
86
|
+
object : CompletionHandler {
|
|
87
|
+
override fun onSuccess() {
|
|
88
|
+
// 登录成功,可跳转会话列表或聊天页
|
|
89
|
+
}
|
|
90
|
+
override fun onFailure(code: Int, desc: String) {
|
|
91
|
+
// 登录失败,可弹框报错
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
)
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
> **注意:**
|
|
98
|
+
> 在正式的生产环境中,建议在您的服务端生成 UserSig,在需要时由 App 向业务服务器发起请求获取动态 UserSig 进行鉴权。详见 服务端生成 UserSig。
|
|
99
|
+
>
|
|
100
|
+
|
|
101
|
+
### 步骤 3: 构建推荐用户列表界面
|
|
102
|
+
|
|
103
|
+
1. **添加界面:**在您的项目中添加 “推荐的人列表 (MeetPage)”:
|
|
104
|
+
|
|
105
|
+
``` java
|
|
106
|
+
import com.tencent.qcloud.tuikit.videochat.page.meet.MeetPage
|
|
107
|
+
|
|
108
|
+
class MeetPageFragment : Fragment() {
|
|
109
|
+
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
|
110
|
+
super.onViewCreated(view, savedInstanceState)
|
|
111
|
+
addMeetPage()
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
private fun addMeetPage() {
|
|
115
|
+
val meetPage = MeetPage(requireContext())
|
|
116
|
+
val container = findViewById<FrameLayout>(R.id.meet_container)
|
|
117
|
+
container.addView(meetPage, MATCH_PARENT, MATCH_PARENT)
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
```
|
|
121
|
+
2. **输入数据:**您可以通过 `setPageUsers` 输入推荐用户列表,并监听上拉刷新(`onLoadMoreRequested`)在尾部追加用户数据、下拉刷新回调(`onRefreshRequested`)全量更新用户数据。
|
|
122
|
+
|
|
123
|
+
``` java
|
|
124
|
+
import com.tencent.qcloud.tuikit.videochat.page.meet.MeetPage
|
|
125
|
+
|
|
126
|
+
meetPage.setListener(object : MeetPage.Listener {
|
|
127
|
+
// 下拉刷新时触发该回调
|
|
128
|
+
override fun onRefreshRequested() {
|
|
129
|
+
// 全量更新用户列表
|
|
130
|
+
fetchUsers { users, hasMore ->
|
|
131
|
+
// 输入用户列表
|
|
132
|
+
meetPage.setPageUsers(users, hasMore)
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// 上拉刷新时触发该回调。
|
|
137
|
+
override fun onLoadMoreRequested() {
|
|
138
|
+
// 尾部追加新用户列表
|
|
139
|
+
fetchNextPage { users, hasMore ->
|
|
140
|
+
// 输入用户列表
|
|
141
|
+
meetPage.setPageUsers(users, hasMore)
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
})
|
|
145
|
+
```
|
|
146
|
+
- **setPageUsers 详细说明:**
|
|
147
|
+
|
|
148
|
+
``` java
|
|
149
|
+
fun setPageUsers(users: List<V2TIMUserFullInfo>, hasMore: Boolean)
|
|
150
|
+
```
|
|
151
|
+
| <strong>参数</strong> | <strong>类型</strong> | <strong>说明</strong> |
|
|
152
|
+
| --- | --- | --- |
|
|
153
|
+
| users | List<<a href="https://im.sdk.qcloud.com/doc/zh-cn/classcom_1_1tencent_1_1imsdk_1_1v2_1_1V2TIMUserFullInfo.html">V2TIMUserFullInfo</a>> | 用户列表,<a href="https://im.sdk.qcloud.com/doc/zh-cn/classcom_1_1tencent_1_1imsdk_1_1v2_1_1V2TIMUserFullInfo.html">V2TIMUserFullInfo</a> 为包含用户的 ID、昵称、头像、性别等重要信息的结构体。 |
|
|
154
|
+
| hasMore | Boolean | 表示是否还有下一页:<br>- true: 还有下一页,滚到底会继续触发 onLoadMoreRequested()<br>- false:已无更多数据,滚到底不再触发回调 |
|
|
155
|
+
|
|
156
|
+
3. **切换布局(可选)**:MeetPage 提供了“卡片”和“列表”两种布局模式,您可以通过 `setLayoutTemplate` 选择您喜欢的布局。
|
|
157
|
+
|
|
158
|
+
``` java
|
|
159
|
+
import com.tencent.qcloud.tuikit.videochat.page.meet.MeetPage
|
|
160
|
+
|
|
161
|
+
class MeetPageFragment : Fragment() {
|
|
162
|
+
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
|
163
|
+
super.onViewCreated(view, savedInstanceState)
|
|
164
|
+
addMeetPage()
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
private fun addMeetPage() {
|
|
168
|
+
val meetPage = MeetPage(requireContext())
|
|
169
|
+
// 设置布局
|
|
170
|
+
meetPage.setLayoutTemplate(MeetPage.Template.LIST) // 设置布局为列表布局(默认)
|
|
171
|
+
// meetPage.setLayoutTemplate(MeetPage.Template.GRID) // 设置布局为卡片布局
|
|
172
|
+
val container = findViewById<FrameLayout>(R.id.meet_container)
|
|
173
|
+
container.addView(meetPage, MATCH_PARENT, MATCH_PARENT)
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
```
|
|
177
|
+
- **setLayoutTemplate** **详细说明:**
|
|
178
|
+
|
|
179
|
+
``` java
|
|
180
|
+
fun setLayoutTemplate(template: MeetPage.Template)
|
|
181
|
+
```
|
|
182
|
+
| <strong>参数</strong> | <strong>类型</strong> | <strong>说明</strong> |
|
|
183
|
+
| --- | --- | --- |
|
|
184
|
+
| template | MeetPage.Template | 布局的类型:<br>- MeetPage.Template.LIST :列表布局。<br>- MeetPage.Template.GRID :卡片布局。 |
|
|
185
|
+
|
|
186
|
+
### 步骤 4: 构建会话列表界面
|
|
187
|
+
|
|
188
|
+
会话列表只需要创建 `ConversationPage` 对象加入到自己的布局中即可。会话列表会从数据库中读取最近聊天记录,当用户点击聊天记录时,`ConversationPage` 会默认跳转到聊天界面。
|
|
189
|
+
|
|
190
|
+
- **示例代码如下:**
|
|
191
|
+
|
|
192
|
+
``` java
|
|
193
|
+
val conversationPage = ConversationPage()
|
|
194
|
+
|
|
195
|
+
// R.id.container 为您的布局中容纳会话列表 Fragment 的 FrameLayout
|
|
196
|
+
supportFragmentManager.beginTransaction()
|
|
197
|
+
.add(R.id.container, conversationPage)
|
|
198
|
+
.commit()
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
### 步骤 5: 构建聊天界面
|
|
202
|
+
|
|
203
|
+
聊天界面用于展示和发送消息。您可通过如下方法构建界面:
|
|
204
|
+
|
|
205
|
+
- **示例代码如下:**
|
|
206
|
+
|
|
207
|
+
``` java
|
|
208
|
+
Bundle param = new Bundle();
|
|
209
|
+
param.putInt(TUIConstants.TUIChat.CHAT_TYPE, V2TIMConversation.V2TIM_C2C);
|
|
210
|
+
val userId = "jack" // 对方的 UserId
|
|
211
|
+
param.putString(TUIConstants.TUIChat.CHAT_ID, userId);
|
|
212
|
+
TUICore.startActivity("TUIC2CChatActivity", param);
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
### 步骤 6: 音视频通话
|
|
216
|
+
|
|
217
|
+
在社交娱乐场景中,由于通话需求复杂多样,我们推荐您使用 [AtomicxCore SDK](https://liteav.sdk.cloudcachetci.com/doc/product/tuikit/atomic-x/android/zh/-atomic-x%20-core%20-a-p-i/io.trtc.tuikit.atomicxcore.api.call/-call-store/index.html) 来灵活定制您的通话场景。以 video-chat 模块的通话界(VideoCallPage)为例,它基于 SDK 的 CallStore 模块构建,内部已深度集成了美颜、关注操作以及对方信息展示等核心 UI 元素。您既可以将其作为源码参考,也可以直接接入项目中,从而快速搭建出专属的通话界面。
|
|
218
|
+
|
|
219
|
+
- **发起视频通话示例代码:**您可通过 [CallStore.calls](https://liteav.sdk.cloudcachetci.com/doc/product/tuikit/atomic-x/android/zh/-atomic-x%20-core%20-a-p-i/io.trtc.tuikit.atomicxcore.api.call/-call-store/calls.html) 发起视频通话,并在成功回调中拉起通话界面。
|
|
220
|
+
|
|
221
|
+
``` java
|
|
222
|
+
// 通过 AtomicxCore SDK 的通话模块 CallStore.calls 发起视频通话。
|
|
223
|
+
CallStore.shared.calls(list, mediaType, params, object : CompletionHandler {
|
|
224
|
+
override fun onFailure(code: Int, desc: String) {
|
|
225
|
+
completion?.onFailure(code, desc)
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
override fun onSuccess() {
|
|
229
|
+
completion?.onSuccess()
|
|
230
|
+
// 通话成功,拉起 VideoCallPage 通话界面
|
|
231
|
+
val intent = Intent(context, VideoCallPage::class.java)
|
|
232
|
+
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
|
|
233
|
+
context.startActivity(intent)
|
|
234
|
+
}
|
|
235
|
+
})
|
|
236
|
+
```
|
|
237
|
+
- **AtomicxCore SDK 通话模块核心 API 说明:**
|
|
238
|
+
|
|
239
|
+
|**模块**|**功能描述**|
|
|
240
|
+
|---------|---------|
|
|
241
|
+
|[CallCoreView](https://liteav.sdk.cloudcachetci.com/doc/product/tuikit/atomic-x/android/zh/-atomic-x%20-core%20-a-p-i/io.trtc.tuikit.atomicxcore.api.view/-call-core-view/index.html)|通话视图核心组件。自动监听 CallStore 数据并完成画面渲染,同时提供布局切换、头像与图标配置等 UI 定制化能力。|
|
|
242
|
+
|[CallStore](https://liteav.sdk.cloudcachetci.com/doc/product/tuikit/atomic-x/android/zh/-atomic-x%20-core%20-a-p-i/io.trtc.tuikit.atomicxcore.api.call/-call-store/index.html)|通话生命周期管理:拨打电话、接通电话、拒接电话、挂断电话。实时获取参与通话人员音视频状态,通话计时、通话记录等数据。|
|
|
243
|
+
|[DeviceStore](https://liteav.sdk.cloudcachetci.com/doc/product/tuikit/atomic-x/android/zh/-atomic-x%20-core%20-a-p-i/io.trtc.tuikit.atomicxcore.api.device/-device-store/index.html)|音视频设备控制:麦克风(开关 / 音量)、摄像头(开关 / 切换 / 画质)、屏幕共享,设备状态实时监听。|
|
|
244
|
+
|
|
245
|
+
## 更多功能
|
|
246
|
+
|
|
247
|
+
您可以接入以下功能提高您 App 的核心竞争力,为您的用户带来更佳体验。
|
|
248
|
+
| <strong>功能</strong> | <strong>描述</strong> | <strong>接入文档</strong> |
|
|
249
|
+
| --- | --- | --- |
|
|
250
|
+
| 通话计费 | 我们为您提供了精准的服务端通话状态回调,您可以监听通话开始和通话结束的服务端回调完成通话计费功能。 | - 开始通话后回调<br>- 通话结束后回调 |
|
|
251
|
+
| 接入美颜 | 我们提供了两种美颜特效方案:<strong>基础美颜</strong>(内置)和<strong>高级美颜</strong>(需额外集成和付费)。您可以根据自己的需求选择合适的方案。 | 接入美颜 |
|
|
252
|
+
| 接入美声 | TRTC 音频美声功能的实现方法和应用场景,帮助开发者为用户打造丰富多彩的音频互动体验。 | 接入美声 |
|
|
253
|
+
| 接入 AI 实时翻译 | 应用出海必备功能,帮助您为用户打破语言壁垒。 | 接入 AI 实时翻译 |
|
|
254
|
+
| 音视频内容审核 | 1v1 社交娱乐应用必备功能,帮助您审核音视频媒体流、文字内容信息是否违规,防止应用被下架。 | - <a href="https://cloud.tencent.com/document/product/647/77791">音视频内容审核</a><br>- <a href="https://cloud.tencent.com/document/product/269/103732">文本内容审核</a> |
|
|
255
|
+
|
|
256
|
+
## 常见问题
|
|
257
|
+
|
|
258
|
+
### 为什么 Demo 的美颜不生效?
|
|
259
|
+
|
|
260
|
+
Demo 默认集成了美颜功能,但需要 License 鉴权。请您检查 `video-chat-solution/android/app/src/main/java/io/trtc/uikit/demo/debug/GenerateTestUserSig.java` 中的 `LicenseURL`、`LicenseKey` 是否正确。获取可参考 [License 指引](https://cloud.tencent.com/document/product/616/79137)。
|
|
261
|
+
|
|
262
|
+
### 如何自定义 UI ?
|
|
263
|
+
|
|
264
|
+
若您的 UI 定制需求极高,我们推荐您:
|
|
265
|
+
1. **通话模块:**您可以使用 AtomicxCore SDK (示例代码可参考:无 UI 接入)完成通话模块的界面定制,其核心模块如下:
|
|
266
|
+
|
|
267
|
+
|**模块**|**说明**|
|
|
268
|
+
|---------|---------|
|
|
269
|
+
|[LoginStore](https://liteav.sdk.cloudcachetci.com/doc/product/tuikit/atomic-x/android/zh/-atomic-x%20-core%20-a-p-i/io.trtc.tuikit.atomicxcore.api.login/-login-store/index.html)|登录管理类,用于处理用户登录、登出及用户信息管理等业务逻辑。 LoginStore 提供了一套完整的登录管理 API,包括用户登录、登出、设置个人信息等功能。 通过该类,可以管理用户的登录状态和用户资料。|
|
|
270
|
+
|[CallCoreView](https://liteav.sdk.cloudcachetci.com/doc/product/tuikit/atomic-x/android/zh/-atomic-x%20-core%20-a-p-i/io.trtc.tuikit.atomicxcore.api.view/-call-core-view/index.html)|通话视图核心组件。自动监听 CallStore 数据并完成画面渲染,同时提供布局切换、头像与图标配置等 UI 定制化能力。|
|
|
271
|
+
|[CallStore](https://liteav.sdk.cloudcachetci.com/doc/product/tuikit/atomic-x/android/zh/-atomic-x%20-core%20-a-p-i/io.trtc.tuikit.atomicxcore.api.call/-call-store/index.html)|通话生命周期管理:拨打电话、接通电话、拒接电话、挂断电话。实时获取参与通话人员音视频状态,通话计时、通话记录等数据。|
|
|
272
|
+
|[DeviceStore](https://liteav.sdk.cloudcachetci.com/doc/product/tuikit/atomic-x/android/zh/-atomic-x%20-core%20-a-p-i/io.trtc.tuikit.atomicxcore.api.device/-device-store/index.html)|音视频设备控制:麦克风(开关 / 音量)、摄像头(开关 / 切换 / 画质)、屏幕共享,设备状态实时监听。|
|
|
273
|
+
|
|
274
|
+
2. **聊天互动模块可参考:**[IM SDK 无 UI 接入](https://cloud.tencent.com/document/product/269/75283)。
|
|
275
|
+
|
|
276
|
+
### 如何自定义聊天通话消息上屏?
|
|
277
|
+
|
|
278
|
+
当通话状态发生改变时,IM 将下发通话状态变更的消息,信令协议如下,根据您是否使用我们提供的 UI 代码,您可以有两种解决方案:
|
|
279
|
+
|
|
280
|
+
|**问题**|**说明**|
|
|
281
|
+
|---------|---------|
|
|
282
|
+
|如何判断 “发起通话”|actionType = 1 且 cmd = 'videoCall' 或 'audioCall'|
|
|
283
|
+
|如何判断 “已接听”|actionType = 3 |
|
|
284
|
+
|如何判断 “通话已结束”,“通话时长是多少”|actionType = 1 且 cmd = 'hangup',通话时长取 call_end 字段,单位:秒|
|
|
285
|
+
|如何判断 “取消通话”|actionType = 2|
|
|
286
|
+
|如何判断 “拒绝通话”|actionType = 4|
|
|
287
|
+
|如何判断对端忙线产生的 “拒绝通话”|actionType = 4 且 cmd = "line_busy"|
|
|
288
|
+
|如何被叫判断 “超时未接听”|actionType = 5|
|
|
289
|
+
|
|
290
|
+
- **方案一:修改我们提供的 UI 源代码**
|
|
291
|
+
|
|
292
|
+
您可以找到 `tuikit/TUIChat/tuichat/src/main/java/com/tencent/qcloud/tuikit/tuichat/bean/CallModel.java` 源码,修改 `getContentForSimplifyAppearance` 函数完成自定义通话状态消息上屏。
|
|
293
|
+
|
|
294
|
+
``` java
|
|
295
|
+
/**
|
|
296
|
+
* 定制 1v1 通话状态消息上屏文案
|
|
297
|
+
*
|
|
298
|
+
* 修改位置:CallModel.java → getContentForSimplifyAppearance()
|
|
299
|
+
* 只需修改 participantType == CALL_PARTICIPANT_TYPE_C2C 分支内的文案即可。
|
|
300
|
+
*
|
|
301
|
+
* 以下字段在方法内可直接使用:
|
|
302
|
+
* - protocolType:通话协议类型(发起/接听/拒绝/取消/挂断/超时/忙线)
|
|
303
|
+
* - participantRole:当前用户角色(主叫 CALLER / 被叫 CALLEE)
|
|
304
|
+
* - streamMediaType:媒体类型(语音 VOICE / 视频 VIDEO)
|
|
305
|
+
* - duration:通话时长(秒)
|
|
306
|
+
*/
|
|
307
|
+
|
|
308
|
+
// =================== 示例:定制 1v1 通话上屏文案 ===================
|
|
309
|
+
|
|
310
|
+
// 在 getContentForSimplifyAppearance() 方法中,
|
|
311
|
+
// 找到 if (participantType == CALL_PARTICIPANT_TYPE_C2C) 分支,修改如下:
|
|
312
|
+
|
|
313
|
+
if (participantType == CALL_PARTICIPANT_TYPE_C2C) {
|
|
314
|
+
// 判断媒体类型,用于拼接文案前缀
|
|
315
|
+
val mediaPrefix = if (streamMediaType == CALL_STREAM_MEDIA_TYPE_VIDEO) {
|
|
316
|
+
"[视频通话]" // 填写您的自定义视频通话文案
|
|
317
|
+
} else {
|
|
318
|
+
"[语音通话]" // 填写您的自定义语音通话文案
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
val isCaller = (participantRole == CALL_PARTICIPANT_ROLE_CALLER)
|
|
322
|
+
|
|
323
|
+
// display 为显示的通话状态上屏消息
|
|
324
|
+
display = when (protocolType) {
|
|
325
|
+
// 通话被拒绝(actionType = 4,不含 line_busy)
|
|
326
|
+
CALL_PROTOCOL_TYPE_REJECT -> {
|
|
327
|
+
if (isCaller) {
|
|
328
|
+
"$mediaPrefix 对方已拒绝"
|
|
329
|
+
} else {
|
|
330
|
+
"$mediaPrefix 已拒绝"
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
// 通话已取消(actionType = 2,主叫取消)
|
|
335
|
+
CALL_PROTOCOL_TYPE_CANCEL -> {
|
|
336
|
+
if (isCaller) {
|
|
337
|
+
"$mediaPrefix 已取消"
|
|
338
|
+
} else {
|
|
339
|
+
"$mediaPrefix 对方已取消"
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
// 通话结束(actionType = 1,cmd = "hangup")
|
|
344
|
+
// duration 字段为通话时长,单位:秒
|
|
345
|
+
CALL_PROTOCOL_TYPE_HANGUP -> {
|
|
346
|
+
val formattedDuration = DateTimeUtil.formatSecondsTo00(duration)
|
|
347
|
+
"$mediaPrefix 通话时长 $formattedDuration"
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
// 超时未接听(actionType = 5)
|
|
351
|
+
CALL_PROTOCOL_TYPE_TIMEOUT -> {
|
|
352
|
+
if (isCaller) {
|
|
353
|
+
"$mediaPrefix 对方无应答"
|
|
354
|
+
} else {
|
|
355
|
+
"$mediaPrefix 未接听"
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
// 忙线拒绝(actionType = 4,顶层 JSON 包含 "line_busy" 字段)
|
|
360
|
+
CALL_PROTOCOL_TYPE_LINE_BUSY -> {
|
|
361
|
+
if (isCaller) {
|
|
362
|
+
"$mediaPrefix 对方忙线"
|
|
363
|
+
} else {
|
|
364
|
+
"$mediaPrefix 忙线未接听"
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
// 发起通话(actionType = 1,cmd = "videoCall" 或 "audioCall")
|
|
369
|
+
CALL_PROTOCOL_TYPE_SEND -> {
|
|
370
|
+
"$mediaPrefix 发起通话"
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
// 已接听(actionType = 3)
|
|
374
|
+
CALL_PROTOCOL_TYPE_ACCEPT -> {
|
|
375
|
+
"$mediaPrefix 已接听"
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
else -> {
|
|
379
|
+
context.getString(R.string.invalid_command)
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
```
|
|
384
|
+
- **方案二:自实现通话状态上屏的聊天记录**
|
|
385
|
+
|
|
386
|
+
您可以设置 [IM 消息监听器](https://cloud.tencent.com/document/product/269/75318) 实现通话状态消息上屏,示例代码如下:
|
|
387
|
+
|
|
388
|
+
``` java
|
|
389
|
+
// 设置消息监听器
|
|
390
|
+
V2TIMManager.getMessageManager().addAdvancedMsgListener(advancedMsgListener)
|
|
391
|
+
|
|
392
|
+
/**
|
|
393
|
+
* 收到新消息
|
|
394
|
+
* @param msg 消息
|
|
395
|
+
*/
|
|
396
|
+
override fun onRecvNewMessage(msg: V2TIMMessage) {
|
|
397
|
+
// 获取信令信息,非信令消息返回 null
|
|
398
|
+
val signalingInfo = V2TIMManager.getSignalingManager().getSignalingInfo(msg)
|
|
399
|
+
?: return
|
|
400
|
+
|
|
401
|
+
// 只处理 1v1 单聊(groupID 为空表示单聊,非空表示群聊)
|
|
402
|
+
if (!signalingInfo.groupID.isNullOrEmpty()) {
|
|
403
|
+
return
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
// 解析信令的 data 字段(JSON 格式)
|
|
407
|
+
val gson = Gson()
|
|
408
|
+
val jsonData: Map<String, Any> = try {
|
|
409
|
+
gson.fromJson(signalingInfo.data, object : TypeToken<Map<String, Any>>() {}.type)
|
|
410
|
+
} catch (e: Exception) {
|
|
411
|
+
return
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
// 校验 businessID,确认是通话信令消息
|
|
415
|
+
val businessId = jsonData["businessID"] as? String
|
|
416
|
+
if (businessId != "av_call" && businessId != "tuikit_calling") {
|
|
417
|
+
return
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
// 提取 data 子对象中的 cmd
|
|
421
|
+
val dataMap = jsonData["data"] as? Map<*, *>
|
|
422
|
+
val cmd = dataMap?.get("cmd") as? String
|
|
423
|
+
|
|
424
|
+
// 根据 actionType 判断通话状态
|
|
425
|
+
when (signalingInfo.actionType) {
|
|
426
|
+
|
|
427
|
+
// ========== actionType = 1:发起邀请 ==========
|
|
428
|
+
V2TIMSignalingInfo.SIGNALING_ACTION_TYPE_INVITE -> {
|
|
429
|
+
when (cmd) {
|
|
430
|
+
// 发起视频通话
|
|
431
|
+
"videoCall" -> {
|
|
432
|
+
val mediaType = "video"
|
|
433
|
+
Log.i(TAG, "发起通话 | 类型: $mediaType, 主叫: ${msg.sender}")
|
|
434
|
+
}
|
|
435
|
+
// 发起语音通话
|
|
436
|
+
"audioCall" -> {
|
|
437
|
+
val mediaType = "audio"
|
|
438
|
+
Log.i(TAG, "发起通话 | 类型: $mediaType, 主叫: ${msg.sender}")
|
|
439
|
+
}
|
|
440
|
+
// 挂断(通话结束)
|
|
441
|
+
"hangup" -> {
|
|
442
|
+
// 通话时长从顶层 call_end 字段获取,单位:秒
|
|
443
|
+
val duration = jsonData["call_end"]
|
|
444
|
+
?.toString()?.toDoubleOrNull()?.toInt() ?: 0
|
|
445
|
+
Log.i(TAG, "通话结束 | 时长: ${duration}秒")
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
// ========== actionType = 2:取消通话(主叫取消) ==========
|
|
451
|
+
V2TIMSignalingInfo.SIGNALING_ACTION_TYPE_CANCEL_INVITE -> {
|
|
452
|
+
Log.i(TAG, "通话已取消 | 主叫: ${msg.sender}")
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
// ========== actionType = 3:接听通话(被叫接受) ==========
|
|
456
|
+
V2TIMSignalingInfo.SIGNALING_ACTION_TYPE_ACCEPT_INVITE -> {
|
|
457
|
+
Log.i(TAG, "通话已接听")
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
// ========== actionType = 4:拒绝通话(被叫拒绝) ==========
|
|
461
|
+
V2TIMSignalingInfo.SIGNALING_ACTION_TYPE_REJECT_INVITE -> {
|
|
462
|
+
// 判断是否为忙线拒绝:顶层 JSON 包含 "line_busy" 字段
|
|
463
|
+
if (jsonData.containsKey("line_busy")) {
|
|
464
|
+
Log.i(TAG, "对方忙线拒绝")
|
|
465
|
+
} else {
|
|
466
|
+
Log.i(TAG, "通话被拒绝")
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
// ========== actionType = 5:超时未接听 ==========
|
|
471
|
+
V2TIMSignalingInfo.SIGNALING_ACTION_TYPE_INVITE_TIMEOUT -> {
|
|
472
|
+
Log.i(TAG, "超时未接听")
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
```
|
|
477
|
+
|
|
478
|
+
### 提高通话触达率?
|
|
479
|
+
1. **接入离线推送提高通话触达率:**
|
|
480
|
+
|
|
481
|
+
- 中国大陆:接入 Notification
|
|
482
|
+
|
|
483
|
+
- 海外:接入 FCM
|
|
484
|
+
|
|
485
|
+
2. **提供推送控制:**根据我们的经验,超过 90% 的用户接不到通话通知的原因是手动关闭了应用的通知权限。为确保通话可达率,我们强烈建议:
|
|
486
|
+
|
|
487
|
+
- **审慎发送通知:**避免向用户推送低质量或无关联的通知,减少用户因骚扰而关闭通知权限的可能性。
|
|
488
|
+
|
|
489
|
+
- **提供精细控制:**借鉴微信等优秀应用的做法,在应用设置内为用户提供独立的开关,分别控制“Notification”和“FCM Data Message”,而非引导用户去系统设置中一刀切地关闭所有通知。
|
|
490
|
+
|
package/resource/knowledge/callkit/best-practice/flutter/android-keep-call-alive-background.md
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: TUICallKit Flutter 应用切后台/最小化时保持 Android 通话不中断(前台服务配置)
|
|
3
|
+
product: call
|
|
4
|
+
frameworks: [flutter, android]
|
|
5
|
+
scope: platform_specific
|
|
6
|
+
tags: [TUICallKit, Flutter, Android, 前台服务, foreground service, CallForegroundService, 后台保活, FOREGROUND_SERVICE_MICROPHONE, FOREGROUND_SERVICE_CAMERA, Android14, foregroundServiceType, MethodChannel]
|
|
7
|
+
version_range: ">=2.0.0"
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# TUICallKit Flutter 应用切后台/最小化时保持 Android 通话不中断(前台服务配置)
|
|
11
|
+
|
|
12
|
+
## 1. 核心结论
|
|
13
|
+
|
|
14
|
+
- 需要:Android 系统会限制后台应用访问麦克风/摄像头,通话切后台或锁屏后若无前台服务保活,音视频采集会被系统中断。
|
|
15
|
+
- 根因:Android 9(API 28)起访问麦克风/摄像头需声明前台服务权限;Android 14(API 34)起强制要求前台服务显式声明 `foregroundServiceType`,否则启动前台服务会抛异常。
|
|
16
|
+
- 修复方向:TUICallKit Flutter **未内置**该前台服务,需在 Android 原生层自行实现 `CallForegroundService`,并通过 `MethodChannel` 从 Flutter 侧在合适时机调用其 `start()`/`stop()`。
|
|
17
|
+
- 版本/限制:`targetSdkVersion >= 34` 时,若 `<service>` 未声明 `android:foregroundServiceType="camera|microphone"`,调用 `startForegroundService` 会抛 `MissingForegroundServiceTypeException` 导致崩溃。
|
|
18
|
+
|
|
19
|
+
## 2. 字段语义对照
|
|
20
|
+
|
|
21
|
+
| 字段/能力 | 作用 | 说明 |
|
|
22
|
+
|---|---|---|
|
|
23
|
+
| `FOREGROUND_SERVICE` | 声明使用前台服务的基础权限 | Android 9(API 28)起需声明 |
|
|
24
|
+
| `FOREGROUND_SERVICE_MICROPHONE` / `FOREGROUND_SERVICE_CAMERA` | 声明前台服务使用麦克风/摄像头 | Android 14(API 34)起必须声明 |
|
|
25
|
+
| `android:foregroundServiceType="camera\|microphone"` | `<service>` 标签声明服务类型 | 与上述权限一一对应,缺失会在 API 34+ 崩溃 |
|
|
26
|
+
| `CallForegroundService`(需自行实现) | 保活的前台服务类 | TUICallKit 不内置,需开发者创建并调用 `startForeground` |
|
|
27
|
+
| `MethodChannel` | Flutter 与 Android 原生层通信桥 | 用于在通话开始/切后台时从 Flutter 侧触发 `start()` |
|
|
28
|
+
|
|
29
|
+
## 3. 机制/时序
|
|
30
|
+
|
|
31
|
+
应用切后台/锁屏 -> Android 系统回收后台麦克风/摄像头访问权限 -> 通话采集被中断(无声/黑屏) -> 排查:确认是否声明前台服务权限与 `<service>` -> 定位:缺少 `CallForegroundService` 或未在切后台时触发 `start()` -> 修复:声明权限 + 实现前台服务类 + `MethodChannel` 桥接触发 -> 复验:切后台/锁屏后音视频采集持续正常,通知栏出现常驻通知。
|
|
32
|
+
|
|
33
|
+
## 4. 标准用法
|
|
34
|
+
|
|
35
|
+
1. 在 `AndroidManifest.xml` 声明前台服务权限,并为 `<service>` 声明 `foregroundServiceType`:
|
|
36
|
+
|
|
37
|
+
``` xml
|
|
38
|
+
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
|
39
|
+
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_CAMERA" />
|
|
40
|
+
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MICROPHONE" />
|
|
41
|
+
|
|
42
|
+
<application>
|
|
43
|
+
<service
|
|
44
|
+
android:name=".CallForegroundService"
|
|
45
|
+
android:enabled="true"
|
|
46
|
+
android:exported="false"
|
|
47
|
+
android:foregroundServiceType="camera|microphone" />
|
|
48
|
+
</application>
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
2. 在 Android 原生层实现 `CallForegroundService`(继承 `Service`,`onCreate` 中调用 `startForeground` 并携带常驻通知),提供 `start(context)`/`stop(context)` 静态方法供外部调用。
|
|
52
|
+
|
|
53
|
+
3. 在 Flutter 侧注册 `MethodChannel`,在通话开始(`calls`/`accept` 成功)或应用即将进入后台时调用原生 `CallForegroundService.start()`;通话结束(`hangup`/`onCallEnd`)时调用 `stop()`,避免服务常驻空跑。
|
|
54
|
+
|
|
55
|
+
4. iOS 侧同步配置 `Background Modes`(勾选 `Audio, AirPlay, and Picture in Picture` 与 `Voice over IP`)并在通话前配置 `AVAudioSession`,同样通过 `MethodChannel` 在合适时机触发对应的后台保活逻辑。
|
|
56
|
+
|
|
57
|
+
## 5. 结果判定
|
|
58
|
+
|
|
59
|
+
- 应用切到后台或锁屏后,通话音频/视频采集不中断,对端仍能听到/看到本端画面。
|
|
60
|
+
- 系统通知栏出现前台服务的常驻通知(如"正在通话中")。
|
|
61
|
+
- `targetSdkVersion >= 34` 的设备上不会因缺少 `foregroundServiceType` 声明而崩溃。
|
|
62
|
+
|
|
63
|
+
## 6. 常见误区
|
|
64
|
+
|
|
65
|
+
- 误区 1:认为 TUICallKit Flutter SDK 内置了前台服务保活能力,无需自行实现(实际需要开发者自行创建 `CallForegroundService` 并接入,SDK 不会自动处理)。
|
|
66
|
+
- 误区 2:只在 `AndroidManifest.xml` 声明了权限和 `<service>`,但未通过 `MethodChannel` 在通话中实际调用 `start()`,导致服务从未真正启动,权限声明形同摆设。
|
|
67
|
+
- 误区 3:`targetSdkVersion` 升到 34+ 后仍只声明 `FOREGROUND_SERVICE` 权限,漏掉 `FOREGROUND_SERVICE_CAMERA`/`FOREGROUND_SERVICE_MICROPHONE` 及对应的 `foregroundServiceType`,上线后在 Android 14 设备上崩溃。
|
|
68
|
+
|
|
69
|
+
## 7. 问题定义(检索辅助,极简)
|
|
70
|
+
|
|
71
|
+
Flutter TUICallKit 在 Android 应用切后台/最小化时如何保持语音/视频通话不中断,是否需要麦克风/摄像头前台服务与常驻通知,Android 14+ 的推荐接入方式。
|
|
72
|
+
|
|
73
|
+
## 8. 同义问法覆盖(检索召回,极简)
|
|
74
|
+
|
|
75
|
+
- Flutter TUICallKit Android 切到后台通话会断吗?
|
|
76
|
+
- TUICallKit Android 前台服务怎么配置?
|
|
77
|
+
- Android 14 FOREGROUND_SERVICE_MICROPHONE 怎么加?
|
|
78
|
+
- Flutter 通话应用最小化后麦克风/摄像头没反应怎么办?
|
|
79
|
+
- CallForegroundService 需要自己实现吗?
|