Flutter语音通话插件twilio_voice_flutter的使用
Flutter语音通话插件twilio_voice_flutter的使用
描述
twilio_voice_flutter
包简化了与 Twilio 的 Programmable Voice SDK 的集成,使您可以在 Flutter 应用中实现 VoIP 通话。它支持 iOS 和 Android 平台,提供了易于使用的 API 来管理通话。该插件非常适合客户服务、通讯或任何需要实时语音功能的应用程序,利用 Twilio 可靠的基础架构来提供高质量的 VoIP 功能。
开始使用
添加依赖
在 pubspec.yaml
文件中添加依赖项并运行 Pub get:
dependencies:
twilio_voice_flutter: ^0.0.4
然后在您的 Dart 文件中导入包:
import 'package:twilio_voice_flutter/twilio_voice_flutter.dart';
重要提示
⚠️ 此插件需要 Firebase 设置才能进行 Twilio 语音通话!它使用 FCM 令牌处理 Android 上的通话 📲 和 VoIP 通知处理 iOS 上的通话 📞。确保两个平台都正确配置以确保通话功能顺畅。 ⚠️
平台设置
Android
要将 Twilio Voice 插件集成到您的 Android 项目中,请执行以下步骤:
- 打开项目的
AndroidManifest.xml
文件。 - 在
<application>
标签内添加以下服务声明:
<service
android:name="com.twilio.voice.flutter.fcm.VoiceFirebaseMessagingService"
android:exported="false"
android:stopWithTask="false">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
iOS
要配置您的 iOS 项目以支持 VoIP 通话,请按照以下步骤操作:
- 在 Xcode 中打开您的项目。
- 从 Project Navigator 中选择您的项目。
- 转到 Signing & Capabilities 标签页。
- 启用以下后台模式:
- Audio, AirPlay, and Picture in Picture:允许应用程序在后台继续播放音频。
- Voice over IP:允许应用程序在后台接收传入的 VoIP 通话。
- 确保
Info.plist
文件包含所需的键:
<key>UIBackgroundModes</key>
<array>
<string>audio</string>
<string>voip</string>
</array>
Twilio 语音通话访问令牌设置
此插件支持 Twilio 语音通话,适用于 Android 和 iOS。要生成访问令牌并启用 Twilio 通话,请参考官方 Twilio 存储库中的说明:
这些存储库提供了详细的指导,帮助您生成访问令牌并通过 Twilio 在 Android 和 iOS 平台上进行语音通话。⚡ 确保遵循文档中的步骤,成功将 Twilio 语音功能集成到您的应用程序中。
设置 Twilio 令牌
setTwilioToken
函数用于使用提供的访问令牌注册用户的标识信息到 Twilio Voice。此函数处理 Android 设备上的 Firebase Cloud Messaging (FCM) 令牌的检索,并注册用户到 Twilio Voice。
static Future<bool> setTwilioToken(String identity, String accessToken) async {
try {
String accessToken = await _getAccessToken(identity);
if (Platform.isAndroid) {
String? fcmToken = await FirebaseMessaging.instance.getToken() ?? "";
await TwilioVoiceFlutter.register(
identity: identity, accessToken: accessToken, fcmToken: fcmToken);
} else {
await TwilioVoiceFlutter.register(
identity: identity, accessToken: accessToken, fcmToken: "");
}
return true;
} catch (_) {
return false;
}
}
功能概述
VoIP 通话管理
- 发起通话:使用
makeCall
方法轻松开始 VoIP 通话,能够传递自定义通话数据。 - 接收传入通话:通过推送通知处理传入通话邀请,并使用内置 CallKit 支持在 iOS 上接听通话。
- 通话状态通知:通过 Flutter MethodChannel 回调保持通话状态(如响铃、连接和断开)的更新。
通话控制
- 静音/取消静音:使用
toggleMute
方法切换正在进行的通话静音状态。使用isMuted
方法检查当前是否静音。 - 扬声器控制:使用
toggleSpeaker
在设备内置扬声器和听筒之间切换。使用isSpeaker
验证当前音频路由。
iOS CallKit 集成
- CallKit 支持:在 iOS 上使用原生 CallKit 功能管理传入和传出 VoIP 通话,确保熟悉用户体验。
- 传入通话处理:向 CallKit 报告传入通话,使系统显示原生通话 UI 并正确处理中断。
- 后台 VoIP 支持:通过启用必要的后台模式并相应配置
Info.plist
,确保应用程序能够在后台接收 VoIP 通话。
推送通知支持
- VoIP 推送通知:通过 Firebase Cloud Messaging (FCM) 处理 Android 上的 VoIP 推送通知和 Apple Push Notification service (APNs) 处理 iOS 上的 VoIP 推送通知。
- 推送凭证管理:管理接收 VoIP 推送通知所需的设备和访问令牌,确保可靠通信。
DTMF(双音多频)信令
- 发送 DTMF 数字:使用
sendDigits
方法在活动通话期间发送 DTMF 音调(例如,与自动电话系统交互)。
联系人管理
- 自定义联系人数据:存储和检索自定义联系人数据(如显示名称和照片 URL),以增强通话体验,提供个性化信息。
持久化数据存储
- 令牌和联系人数据持久化:使用 iOS 上的
UserDefaults
安全地存储和检索访问令牌和联系人数据,以维护跨应用会话的状态。
带有错误管理的通话处理
- 优雅的错误处理:全面的错误处理确保有效管理和报告问题,如令牌过期或失败的通话连接。
函数概览
registerTwilio()
:使用访问令牌和设备令牌为 VoIP 推送通知注册设备。unregisterTwilio()
:注销设备的 Twilio VoIP 推送通知,移除访问令牌和设备令牌。makeCall(String to)
:发起一个语音通话到指定的接收者。如果存在活动通话,则返回错误。toggleMute()
:切换正在进行的通话静音状态。通知 Flutter 端更改。isMuted()
:返回正在进行的通话当前静音状态。toggleSpeaker()
:切换正在进行的通话扬声器模式。通知 Flutter 端更改。isSpeaker() -> Bool
:检查当前是否处于扬声器模式。hangUp()
:结束当前通话。如果没有活动通话,则清除通话相关数据。activeCall()
:返回存在的活动通话详情。sendDigits(String digits)
:在活动通话期间发送 DTMF 数字。
示例代码
下面是一个完整的示例代码,展示了如何在 Flutter 应用中使用 twilio_voice_flutter
插件:
import 'dart:async';
import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:twilio_voice_flutter/model/event.dart';
import 'package:twilio_voice_flutter/model/status.dart';
import 'package:twilio_voice_flutter/twilio_voice_flutter.dart';
import 'package:twilio_voice_flutter_example/firebase_options.dart';
import 'package:twilio_voice_flutter_example/twilio_voice_services.dart';
GlobalKey<NavigatorState> appKey = GlobalKey<NavigatorState>();
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform);
TwilioVoiceFlutter.init();
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
navigatorKey: appKey,
title: 'Twilio Voice Demo',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
useMaterial3: true,
),
home: const MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key});
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
bool _isSpeaker = false;
bool _isMuted = false;
bool _isCalling = false;
String _callStatus = "";
StreamSubscription<TwilioVoiceFlutterEvent>? callEventsListener;
final TextEditingController identifyController = TextEditingController();
void setCallEventsListener() {
callEventsListener?.cancel();
callEventsListener = null;
callEventsListener = TwilioVoiceServices.callEventsListener.listen((event) {
if (event.status == TwilioVoiceFlutterStatus.ringing ||
event.status == TwilioVoiceFlutterStatus.connected) {
_callStatus = "Ringing...";
} else if (event.status == TwilioVoiceFlutterStatus.connecting) {
_callStatus = "Connecting...";
} else if (event.status == TwilioVoiceFlutterStatus.reconnected) {
_callStatus = "Reconnected...";
} else if (event.status == TwilioVoiceFlutterStatus.disconnected) {
endCall();
}
setState(() {});
});
}
@override
void initState() {
TwilioVoiceServices.initialize();
setCallEventsListener();
super.initState();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
centerTitle: true,
title: const Text("Twilio Voice Call Example"),
),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
TextField(
controller: identifyController,
decoration: InputDecoration(
hintText: "Enter call identifier", enabled: !_isCalling),
),
const Spacer(),
Text(
_callStatus,
style: const TextStyle(fontSize: 18, fontWeight: FontWeight.w600),
),
const Spacer(),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
IconButton.filled(
onPressed: () {
toggleMuted();
},
icon: _isMuted
? const Icon(Icons.mic, size: 30,)
: const Icon(Icons.mic_off_rounded, size: 30,),
),
const SizedBox(width: 15,),
Theme(
data: ThemeData(
iconButtonTheme: IconButtonThemeData(
style: ButtonStyle(
backgroundColor: MaterialStatePropertyAll<Color>(
_isCalling ? Colors.red : Colors.green)))),
child: IconButton.filled(
color: Colors.white,
onPressed: () {
if (!_isCalling) {
makeCall(identifyController.text);
} else {
endCall();
}
},
icon: _isCalling
? const Icon(Icons.call_end, size: 30,)
: const Icon(Icons.call, size: 30,),
),
),
const SizedBox(width: 15,),
IconButton.filled(
onPressed: () {
toggleSpeaker();
},
icon: _isSpeaker
? const Icon(CupertinoIcons.speaker_fill, size: 30,)
: const Icon(CupertinoIcons.speaker_slash_fill, size: 30,)),
],
)
],
),
),
);
}
void endCall() async {
await TwilioVoiceServices.hangUp();
setState(() {
_isCalling = false;
_callStatus = "";
});
}
void makeCall(String identify) async {
setState(() {
_isCalling = true;
});
final status = await TwilioVoiceServices.makeCall(to: identify);
if (!status) {
setState(() {
_isCalling = false;
});
}
}
toggleSpeaker() async {
_isSpeaker = await TwilioVoiceServices.toggleSpeaker() ?? _isSpeaker;
setState(() {});
}
toggleMuted() async {
_isMuted = await TwilioVoiceServices.toggleMute() ?? _isMuted;
setState(() {});
}
}
这个示例展示了如何创建一个简单的界面,允许用户输入通话标识符并发起或结束通话,同时还可以切换静音和扬声器模式。
更多关于Flutter语音通话插件twilio_voice_flutter的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter语音通话插件twilio_voice_flutter的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
当然,以下是一个关于如何在Flutter项目中使用twilio_voice_flutter
插件实现语音通话功能的示例代码。请注意,为了成功运行以下代码,你需要先在Flutter项目中添加twilio_voice_flutter
依赖,并确保已经在Twilio平台上注册并获取了必要的凭证(Account SID、Auth Token和Twilio Phone Number)。
1. 添加依赖
首先,在你的pubspec.yaml
文件中添加twilio_voice_flutter
依赖:
dependencies:
flutter:
sdk: flutter
twilio_voice_flutter: ^0.6.8 # 请检查最新版本号并替换
然后运行flutter pub get
来安装依赖。
2. 配置Twilio凭证
你需要在你的应用中配置Twilio的Account SID和Auth Token。通常,这些敏感信息不应该硬编码在应用中,而是应该通过安全的后端服务提供。但为了演示目的,这里我们直接在代码中设置(生产环境中应避免这种做法)。
3. 实现语音通话功能
下面是一个简单的Flutter应用示例,展示了如何使用twilio_voice_flutter
插件来发起和接听语音通话。
import 'package:flutter/material.dart';
import 'package:twilio_voice_flutter/twilio_voice.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Twilio Voice Flutter Demo'),
),
body: VoiceCallScreen(),
),
);
}
}
class VoiceCallScreen extends StatefulWidget {
@override
_VoiceCallScreenState createState() => _VoiceCallScreenState();
}
class _VoiceCallScreenState extends State<VoiceCallScreen> {
TwilioVoice _twilioVoice = TwilioVoice();
String _callStatus = 'Not in a call';
@override
void initState() {
super.initState();
// 初始化TwilioVoice,设置Account SID和Auth Token
_twilioVoice.init(
accountSid: 'your_account_sid_here', // 替换为你的Account SID
authToken: 'your_auth_token_here', // 替换为你的Auth Token
);
// 监听通话状态变化
_twilioVoice.onCallDidStart = () {
setState(() {
_callStatus = 'Call Started';
});
};
_twilioVoice.onCallDidConnect = () {
setState(() {
_callStatus = 'Call Connected';
});
};
_twilioVoice.onCallDidDisconnect = () {
setState(() {
_callStatus = 'Call Disconnected';
});
};
_twilioVoice.onCallDidFail = (error) {
setState(() {
_callStatus = 'Call Failed: $error';
});
};
}
@override
Widget build(BuildContext context) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
_callStatus,
style: TextStyle(fontSize: 24),
),
SizedBox(height: 20),
ElevatedButton(
onPressed: () async {
// 发起通话,替换为你要拨打的Twilio Phone Number
String toPhoneNumber = '+1234567890'; // 替换为实际号码
try {
await _twilioVoice.dial(toPhoneNumber);
} catch (e) {
print('Dial failed: $e');
}
},
child: Text('Make Call'),
),
],
),
);
}
@override
void dispose() {
// 清理资源
_twilioVoice.dispose();
super.dispose();
}
}
注意事项
- 敏感信息处理:在生产环境中,避免在客户端代码中硬编码Account SID和Auth Token。应该通过安全的后端服务提供这些凭证。
- 权限处理:确保在Android和iOS项目中配置了必要的权限,比如麦克风权限。
- 错误处理:在实际应用中,应该添加更详细的错误处理和用户反馈机制。
- UI优化:示例中的UI非常简单,实际应用中你可能需要设计更复杂的UI来提供更好的用户体验。
这个示例展示了如何使用twilio_voice_flutter
插件的基本功能。根据实际需求,你可能需要扩展和调整代码。