Flutter音视频通信插件nertc的使用
nertc
Flutter 插件用于网易 RTC SDK。
Flutter音视频通信插件nertc使用方法
在 pubspec.yaml
文件中添加 nertc
作为依赖项。
iOS
在 ios/Runner/Info.plist
中添加两行配置:
- 一行键为
Privacy - Camera Usage Description
并附带描述。 - 另一行键为
Privacy - Microphone Usage Description
并附带描述。
或者以文本格式添加以下内容:
<key>NSCameraUsageDescription</key>
<string>可以使用相机吗?</string>
<key>NSMicrophoneUsageDescription</key>
<string>可以使用麦克风吗?</string>
Android
在 android/app/build.gradle
文件中将最低 Android SDK 版本设置为 21 或更高。
minSdkVersion 21
示例代码
以下是一个完整的示例代码,展示了如何使用 nertc
插件进行音视频通信。
示例代码:main.dart
import 'dart:io';
import 'dart:math';
import 'package:flutter/material.dart';
import 'settings.dart'; // 假设有一个 settings.dart 文件
import 'package:permission_handler/permission_handler.dart';
import 'about.dart';
import 'call.dart';
void main() => runApp(RtcApp());
class RtcApp extends StatelessWidget {
[@override](/user/override)
Widget build(BuildContext context) {
return MaterialApp(
title: 'FLTNERTC',
home: MainPage(),
);
}
}
class MainPage extends StatefulWidget {
[@override](/user/override)
_MainPageState createState() {
return _MainPageState();
}
}
// 定义菜单选项和确认动作
enum OptionsMenu { SETTINGS, ABOUT }
enum ConfirmAction { CANCEL, ACCEPT }
class _MainPageState extends State<MainPage> {
FocusNode _channelFocusNode = FocusNode();
FocusNode _uidFocusNode = FocusNode();
final _channelController = TextEditingController();
bool _channelValidateError = false;
final _uidController = TextEditingController();
bool _uidValidateError = false;
[@override](/user/override)
void initState() {
super.initState();
_uidController.text = Random().nextInt(1 << 32).toString();
Settings.getInstance(); // 初始化设置
}
[@override](/user/override)
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('FLTNERTC'),
actions: [
PopupMenuButton(
onSelected: (OptionsMenu result) {
_onOptionsItemSelected(result);
},
itemBuilder: (BuildContext context) =>
<PopupMenuEntry<OptionsMenu>>[
const PopupMenuItem<OptionsMenu>(
value: OptionsMenu.SETTINGS,
child: Text('Settings'),
),
const PopupMenuItem<OptionsMenu>(
value: OptionsMenu.ABOUT,
child: Text('About'),
),
],
),
],
),
body: Container(
margin: const EdgeInsets.all(15.0),
child: Column(
mainAxisSize: MainAxisSize.max,
children: [
TextField(
focusNode: _uidFocusNode,
controller: _uidController,
onChanged: (value) {
if (_uidValidateError) {
setState(() {
_uidValidateError = value.isEmpty;
});
}
},
decoration: InputDecoration(
hintText: 'UID',
errorText: _uidValidateError ? 'Required' : null),
),
Padding(
padding: EdgeInsets.symmetric(vertical: 5),
child: TextField(
controller: _channelController,
onChanged: (value) {
if (_channelValidateError) {
setState(() {
_channelValidateError = value.isEmpty;
});
}
},
autofocus: true,
focusNode: _channelFocusNode,
decoration: InputDecoration(
hintText: 'Channel Name',
errorText: _channelValidateError ? 'Required' : null),
),
),
SizedBox(height: 20),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ButtonTheme(
minWidth: 200.0,
height: 55.0,
child: RaisedButton(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(5.0)),
onPressed: () {
_channelFocusNode.unfocus();
_uidFocusNode.unfocus();
_startRTC(context);
},
child: const Text(
'开始会话',
style: TextStyle(fontWeight: FontWeight.bold),
),
),
)
],
),
],
),
),
);
}
void _onOptionsItemSelected(OptionsMenu item) {
switch (item) {
case OptionsMenu.SETTINGS:
Navigator.push(
context, MaterialPageRoute(builder: (context) => SettingsPage()));
break;
case OptionsMenu.ABOUT:
Navigator.push(
context, MaterialPageRoute(builder: (context) => AboutPage()));
break;
}
}
Future<void> _startRTC(BuildContext context) async {
_channelValidateError = _channelController.text.isEmpty;
_uidValidateError = _uidController.text.isEmpty;
setState(() {});
if (_channelValidateError || _uidValidateError) return;
// 检查权限
final permissions = [Permission.camera, Permission.microphone];
if (Platform.isAndroid) {
permissions.add(Permission.storage);
}
List<Permission> missed = [];
for (var permission in permissions) {
PermissionStatus status = await permission.status;
if (status != PermissionStatus.granted) {
missed.add(permission);
}
}
bool allGranted = missed.isEmpty;
if (!allGranted) {
List<Permission> showRationale = [];
for (var permission in missed) {
bool isShown = await permission.shouldShowRequestRationale;
if (isShown) {
showRationale.add(permission);
}
}
if (showRationale.isNotEmpty) {
ConfirmAction action = await showDialog<ConfirmAction>(
context: context,
builder: (BuildContext context) {
return AlertDialog(
content: const Text('你需要允许一些权限'),
actions: [
FlatButton(
child: const Text('取消'),
onPressed: () {
Navigator.of(context).pop(ConfirmAction.CANCEL);
},
),
FlatButton(
child: const Text('同意'),
onPressed: () {
Navigator.of(context).pop(ConfirmAction.ACCEPT);
},
)
],
);
});
if (action == ConfirmAction.ACCEPT) {
Map<Permission, PermissionStatus> allStatus = await missed.request();
allGranted = true;
for (var status in allStatus.values) {
if (status != PermissionStatus.granted) {
allGranted = false;
}
}
}
} else {
Map<Permission, PermissionStatus> allStatus = await missed.request();
allGranted = true;
for (var status in allStatus.values) {
if (status != PermissionStatus.granted) {
allGranted = false;
}
}
}
}
if (!allGranted) {
openAppSettings();
} else {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => CallPage(
cid: _channelController.text,
uid: int.parse(_uidController.text),
)));
}
}
}
更多关于Flutter音视频通信插件nertc的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter音视频通信插件nertc的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
nertc
是网易云信提供的一个音视频通信 SDK,支持在 Flutter 应用中实现实时音视频通信。使用 nertc
插件,你可以轻松地在 Flutter 应用中集成音视频通话功能。以下是如何在 Flutter 项目中使用 nertc
插件的基本步骤。
1. 添加依赖
首先,你需要在 pubspec.yaml
文件中添加 nertc
插件的依赖。
dependencies:
flutter:
sdk: flutter
nertc: ^版本号 # 请使用最新版本
然后运行 flutter pub get
来获取依赖。
2. 初始化 SDK
在使用 nertc
之前,你需要初始化 SDK。通常,你可以在应用的 main
函数中进行初始化。
import 'package:nertc/nertc.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
// 初始化 NERTC SDK
await NERtcEngine.instance.init(
appKey: '你的AppKey',
logDirPath: '日志目录路径', // 可选
);
runApp(MyApp());
}
3. 加入房间
在初始化 SDK 之后,你可以调用 joinChannel
方法加入音视频房间。
void joinRoom() async {
try {
await NERtcEngine.instance.joinChannel(
token: '你的Token', // 如果需要鉴权
channelName: '房间名称',
uid: '用户ID', // 可选,如果不传,SDK 会自动生成
);
} catch (e) {
print('加入房间失败: $e');
}
}
4. 设置本地视频视图
在加入房间后,你可以设置本地视频视图,以便显示本地摄像头的画面。
void setupLocalVideo() async {
await NERtcEngine.instance.setupLocalVideo(
NERtcVideoView(
key: 'local_video',
width: 200,
height: 200,
),
);
}
5. 设置远程视频视图
当有远程用户加入房间时,你可以设置远程视频视图,以便显示远程用户的画面。
void setupRemoteVideo(int uid) async {
await NERtcEngine.instance.setupRemoteVideo(
NERtcVideoView(
key: 'remote_video_$uid',
width: 200,
height: 200,
),
uid: uid,
);
}
6. 处理事件
你可以监听 nertc
的事件,例如用户加入、离开、音视频状态变化等。
void setupEventListeners() {
NERtcEngine.instance.onUserJoined = (int uid) {
print('用户 $uid 加入房间');
setupRemoteVideo(uid);
};
NERtcEngine.instance.onUserLeft = (int uid) {
print('用户 $uid 离开房间');
};
NERtcEngine.instance.onUserVideoStart = (int uid) {
print('用户 $uid 开始视频');
};
NERtcEngine.instance.onUserVideoStop = (int uid) {
print('用户 $uid 停止视频');
};
}
7. 离开房间
当你想离开房间时,可以调用 leaveChannel
方法。
void leaveRoom() async {
try {
await NERtcEngine.instance.leaveChannel();
} catch (e) {
print('离开房间失败: $e');
}
}
8. 释放资源
在应用退出时,记得释放 nertc
的资源。
void dispose() async {
await NERtcEngine.instance.release();
}
9. 处理权限
在 Android 和 iOS 上,你需要确保应用有摄像头和麦克风的权限。你可以在 pubspec.yaml
中添加 permission_handler
插件来处理权限。
dependencies:
permission_handler: ^版本号
然后在代码中请求权限:
import 'package:permission_handler/permission_handler.dart';
void requestPermissions() async {
await [Permission.camera, Permission.microphone].request();
}
10. 完整示例
以下是一个简单的完整示例:
import 'package:flutter/material.dart';
import 'package:nertc/nertc.dart';
import 'package:permission_handler/permission_handler.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
// 初始化 NERTC SDK
await NERtcEngine.instance.init(
appKey: '你的AppKey',
logDirPath: '日志目录路径', // 可选
);
runApp(MyApp());
}
class MyApp extends StatelessWidget {
[@override](/user/override)
Widget build(BuildContext context) {
return MaterialApp(
home: VideoCallScreen(),
);
}
}
class VideoCallScreen extends StatefulWidget {
[@override](/user/override)
_VideoCallScreenState createState() => _VideoCallScreenState();
}
class _VideoCallScreenState extends State<VideoCallScreen> {
[@override](/user/override)
void initState() {
super.initState();
requestPermissions();
setupEventListeners();
joinRoom();
setupLocalVideo();
}
void requestPermissions() async {
await [Permission.camera, Permission.microphone].request();
}
void joinRoom() async {
try {
await NERtcEngine.instance.joinChannel(
token: '你的Token', // 如果需要鉴权
channelName: '房间名称',
uid: '用户ID', // 可选,如果不传,SDK 会自动生成
);
} catch (e) {
print('加入房间失败: $e');
}
}
void setupLocalVideo() async {
await NERtcEngine.instance.setupLocalVideo(
NERtcVideoView(
key: 'local_video',
width: 200,
height: 200,
),
);
}
void setupRemoteVideo(int uid) async {
await NERtcEngine.instance.setupRemoteVideo(
NERtcVideoView(
key: 'remote_video_$uid',
width: 200,
height: 200,
),
uid: uid,
);
}
void setupEventListeners() {
NERtcEngine.instance.onUserJoined = (int uid) {
print('用户 $uid 加入房间');
setupRemoteVideo(uid);
};
NERtcEngine.instance.onUserLeft = (int uid) {
print('用户 $uid 离开房间');
};
NERtcEngine.instance.onUserVideoStart = (int uid) {
print('用户 $uid 开始视频');
};
NERtcEngine.instance.onUserVideoStop = (int uid) {
print('用户 $uid 停止视频');
};
}
void leaveRoom() async {
try {
await NERtcEngine.instance.leaveChannel();
} catch (e) {
print('离开房间失败: $e');
}
}
[@override](/user/override)
void dispose() async {
await NERtcEngine.instance.release();
super.dispose();
}
[@override](/user/override)
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('视频通话'),
),
body: Center(
child: Column(
children: [
NERtcVideoView(
key: 'local_video',
width: 200,
height: 200,
),
Expanded(
child: ListView.builder(
itemCount: remoteUsers.length,
itemBuilder: (context, index) {
return NERtcVideoView(
key: 'remote_video_${remoteUsers[index]}',
width: 200,
height: 200,
);
},
),
),
ElevatedButton(
onPressed: leaveRoom,
child: Text('离开房间'),
),
],
),
),
);
}
}