入门指南
Copy a setup prompt with the install steps and the full markdown guide for this plugin.
Set up this Capacitor plugin in the project.
Use the package manager already used by the project.
Install these package(s): `@capgo/capacitor-twilio-voice`
Run the required Capacitor sync/update step after installation.
Read this markdown guide for the full setup steps: https://raw.githubusercontent.com/Cap-go/website/refs/heads/main/apps/docs/src/content/docs/zh/docs/plugins/twilio-voice/getting-started.mdx
Use that guide for platform-specific steps, native file edits, permissions, config changes, imports, and usage setup.
If that guide references other docs pages, read them too.
npm install @capgo/capacitor-twilio-voicenpx cap syncyarn add @capgo/capacitor-twilio-voicenpx cap syncpnpm add @capgo/capacitor-twilio-voicenpx cap syncbun add @capgo/capacitor-twilio-voicenpx cap sync您需要一个 Twilio 账户和访问令牌以进行身份验证。如果您还没有账户,请在 Twilio 注册。
将所需权限添加到您的 Info.plist:
<key>NSMicrophoneUsageDescription</key><string>This app needs microphone access for voice calls</string>对于带有 PushKit 的来电:
- 在 Xcode 功能中启用推送通知
- 添加 VoIP 后台模式
- 在 Twilio 控制台中配置 VoIP 证书
Android
Section titled “Android”将所需权限添加到您的 AndroidManifest.xml:
<uses-permission android:name="android.permission.RECORD_AUDIO" /><uses-permission android:name="android.permission.INTERNET" /><uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /><uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" /><uses-permission android:name="android.permission.USE_FULL_SCREEN_INTENT" />配置 Firebase 推送通知:
- 将
google-services.json添加到您的 Android 项目 - 在 Twilio 控制台中配置 FCM
import { TwilioVoice } from '@capgo/capacitor-twilio-voice';
// 使用 Twilio 进行身份验证await TwilioVoice.login({ accessToken: 'your-twilio-access-token'});
// 拨打电话await TwilioVoice.makeCall({ to: '+1234567890'});
// 监听通话事件TwilioVoice.addListener('callConnected', (data) => { console.log('通话已连接:', data.callSid);});
TwilioVoice.addListener('callDisconnected', (data) => { console.log('通话已断开:', data.callSid);});
TwilioVoice.addListener('incomingCall', (data) => { console.log('来电来自:', data.from);
// 接受通话 TwilioVoice.acceptCall({ callSid: data.callSid });
// 或拒绝 // TwilioVoice.rejectCall({ callSid: data.callSid });});
// 静音/取消静音通话await TwilioVoice.muteCall({ muted: true, callSid: 'current-call-sid'});
// 切换扬声器await TwilioVoice.setSpeaker({ enabled: true});
// 结束通话await TwilioVoice.endCall({ callSid: 'current-call-sid'});
// 登出await TwilioVoice.logout();API 参考
Section titled “API 参考”login(options)
Section titled “login(options)”login(options: { accessToken: string }) => Promise<void>使用访问令牌对 Twilio 进行身份验证。
| 参数 | 类型 |
|---|---|
options | { accessToken: string } |
logout()
Section titled “logout()”logout() => Promise<void>结束用户会话并清除通话状态。
isLoggedIn()
Section titled “isLoggedIn()”isLoggedIn() => Promise<{ loggedIn: boolean }>检查当前身份验证状态。
返回: Promise<{ loggedIn: boolean }>
makeCall(options)
Section titled “makeCall(options)”makeCall(options: { to: string; params?: Record<string, string> }) => Promise<{ callSid: string }>向指定号码发起呼出通话。
| 参数 | 类型 |
|---|---|
options | { to: string; params?: Record<string, string> } |
返回: Promise<{ callSid: string }>
acceptCall(options)
Section titled “acceptCall(options)”acceptCall(options: { callSid: string }) => Promise<void>接受来电。
| 参数 | 类型 |
|---|---|
options | { callSid: string } |
rejectCall(options)
Section titled “rejectCall(options)”rejectCall(options: { callSid: string }) => Promise<void>拒绝来电。
| 参数 | 类型 |
|---|---|
options | { callSid: string } |
endCall(options?)
Section titled “endCall(options?)”endCall(options?: { callSid?: string }) => Promise<void>终止活动通话。
| 参数 | 类型 |
|---|---|
options | { callSid?: string }(可选) |
muteCall(options)
Section titled “muteCall(options)”muteCall(options: { muted: boolean; callSid?: string }) => Promise<void>静音或取消静音通话音频。
| 参数 | 类型 |
|---|---|
options | { muted: boolean; callSid?: string } |
setSpeaker(options)
Section titled “setSpeaker(options)”setSpeaker(options: { enabled: boolean }) => Promise<void>切换扬声器输出。
| 参数 | 类型 |
|---|---|
options | { enabled: boolean } |
sendDigits(options)
Section titled “sendDigits(options)”sendDigits(options: { digits: string; callSid?: string }) => Promise<void>在通话期间发送 DTMF 音调。
| 参数 | 类型 |
|---|---|
options | { digits: string; callSid?: string } |
registered- 成功注册到 Twiliounregistered- 从 Twilio 注销registrationFailed- 注册失败incomingCall- 收到来电callConnected- 通话成功连接callDisconnected- 通话已断开callRinging- 呼出通话正在响铃callReconnecting- 通话正在重新连接callReconnected- 中断后通话重新连接qualityWarning- 通话质量警告error- 发生错误
// 处理来电TwilioVoice.addListener('incomingCall', (data) => { console.log('来电来自:', data.from); console.log('通话 SID:', data.callSid);
// 显示来电界面 showIncomingCallScreen({ from: data.from, callSid: data.callSid });});
// 处理通话状态变化TwilioVoice.addListener('callConnected', (data) => { console.log('通话已连接:', data.callSid); startCallTimer();});
TwilioVoice.addListener('callDisconnected', (data) => { console.log('通话已结束:', data.callSid); stopCallTimer(); hideCallScreen();});
// 处理质量警告TwilioVoice.addListener('qualityWarning', (data) => { console.warn('通话质量警告:', data.warning); showQualityWarning(data.warning);});
// 处理错误TwilioVoice.addListener('error', (error) => { console.error('Twilio 错误:', error.message); handleError(error);});
// 使用完毕后移除监听器const listener = await TwilioVoice.addListener('callConnected', (data) => { console.log('已连接');});
// 稍后...listener.remove();import { TwilioVoice } from '@capgo/capacitor-twilio-voice';
class VoiceCallService { private currentCallSid: string | null = null; private isMuted = false; private isSpeakerOn = false;
async initialize(accessToken: string) { try { // 登录到 Twilio await TwilioVoice.login({ accessToken });
// 检查登录状态 const { loggedIn } = await TwilioVoice.isLoggedIn(); console.log('登录状态:', loggedIn);
// 设置事件监听器 this.setupEventListeners();
} catch (error) { console.error('初始化失败:', error); } }
setupEventListeners() { // 注册事件 TwilioVoice.addListener('registered', () => { console.log('成功注册到 Twilio'); });
TwilioVoice.addListener('registrationFailed', (error) => { console.error('注册失败:', error); });
// 来电 TwilioVoice.addListener('incomingCall', async (data) => { console.log('来电来自:', data.from);
const accepted = await this.showIncomingCallDialog(data.from);
if (accepted) { await TwilioVoice.acceptCall({ callSid: data.callSid }); this.currentCallSid = data.callSid; } else { await TwilioVoice.rejectCall({ callSid: data.callSid }); } });
// 通话事件 TwilioVoice.addListener('callConnected', (data) => { console.log('通话已连接'); this.currentCallSid = data.callSid; this.showCallScreen(); });
TwilioVoice.addListener('callDisconnected', () => { console.log('通话已断开'); this.currentCallSid = null; this.hideCallScreen(); });
TwilioVoice.addListener('callRinging', () => { console.log('通话响铃中...'); });
// 质量警告 TwilioVoice.addListener('qualityWarning', (data) => { console.warn('通话质量警告:', data.warning); this.showQualityIndicator(data.warning); }); }
async makeCall(phoneNumber: string) { try { const result = await TwilioVoice.makeCall({ to: phoneNumber, params: { // 可选的自定义参数 customerId: 'customer-123' } });
this.currentCallSid = result.callSid; console.log('通话已发起:', result.callSid); } catch (error) { console.error('拨打电话失败:', error); } }
async endCall() { if (this.currentCallSid) { await TwilioVoice.endCall({ callSid: this.currentCallSid }); this.currentCallSid = null; } }
async toggleMute() { this.isMuted = !this.isMuted; await TwilioVoice.muteCall({ muted: this.isMuted, callSid: this.currentCallSid || undefined }); }
async toggleSpeaker() { this.isSpeakerOn = !this.isSpeakerOn; await TwilioVoice.setSpeaker({ enabled: this.isSpeakerOn }); }
async sendDTMF(digits: string) { if (this.currentCallSid) { await TwilioVoice.sendDigits({ digits, callSid: this.currentCallSid }); } }
async logout() { await TwilioVoice.logout(); }
private async showIncomingCallDialog(from: string): Promise<boolean> { // 显示原生对话框或自定义界面 return confirm(`来自 ${from} 的来电`); }
private showCallScreen() { // 显示通话界面 console.log('显示通话界面'); }
private hideCallScreen() { // 隐藏通话界面 console.log('隐藏通话界面'); }
private showQualityIndicator(warning: string) { // 显示质量警告 console.log('质量警告:', warning); }}
// 用法const voiceService = new VoiceCallService();
// 使用来自后端的访问令牌初始化const token = await fetchTwilioToken();await voiceService.initialize(token);
// 拨打电话await voiceService.makeCall('+1234567890');
// 控制通话await voiceService.toggleMute();await voiceService.toggleSpeaker();await voiceService.sendDTMF('1');
// 结束通话await voiceService.endCall();
// 登出await voiceService.logout();- 从后端服务器获取访问令牌,永远不要将其嵌入到应用中
- 为长时间运行的会话实现令牌刷新逻辑
- 使用重新连接逻辑处理网络中断
- 为通话状态提供视觉反馈
- 在实际设备上测试推送通知
- 实现适当的错误处理
- 在组件卸载时清理监听器
- 在拨打电话之前请求麦克风权限
安全注意事项
Section titled “安全注意事项”- 永远不要在应用中存储 Twilio 凭证
- 在后端生成访问令牌
- 实现令牌过期和刷新
- 对所有令牌请求使用 HTTPS
- 在服务器端验证来电
通话无法连接
Section titled “通话无法连接”- 验证访问令牌有效且未过期
- 检查网络连接
- 确保已授予麦克风权限
- 验证 Twilio 账户配置正确
推送通知不起作用
Section titled “推送通知不起作用”- 验证 PushKit/FCM 证书在 Twilio 中配置
- 检查设备已注册推送通知
- 使用生产证书测试
- 检查麦克风权限
- 验证扬声器/蓝牙设置
- 在实际设备上测试音频路由
来电者名称显示(CapacitorTwilioCallerName)
Section titled “来电者名称显示(CapacitorTwilioCallerName)”默认情况下,来电显示来电者的电话号码或客户端 ID。您可以通过从 TwiML 后端传递 CapacitorTwilioCallerName 参数来自定义显示友好名称。
在为 <Client> 拨号生成 TwiML 响应时,添加 CapacitorTwilioCallerName 参数:
// Java 示例Parameter callerNameParam = new Parameter.Builder() .name("CapacitorTwilioCallerName") .value("John Doe") .build();
Client client = new Client.Builder(identity) .parameter(callerNameParam) .build();
Dial dial = new Dial.Builder() .client(client) .build();// Node.js 示例const VoiceResponse = require('twilio').twiml.VoiceResponse;
const response = new VoiceResponse();const dial = response.dial();dial.client({ name: 'CapacitorTwilioCallerName', value: 'John Doe'}, identity);- 当您的后端收到来电时,它生成 TwiML 来路由通话
- 包含带有来电者显示名称的
CapacitorTwilioCallerName参数 - 插件自动提取此参数并将其用于:
- iOS CallKit 来电屏幕
- Android 来电通知
incomingCall事件中的from字段- 通话状态中的
pendingInvites数组
如果未提供 CapacitorTwilioCallerName,插件会回退到来电者的电话号码或客户端 ID。