Flutter 实战-快速实现音视频通话应用

Posted lcyw

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Flutter 实战-快速实现音视频通话应用相关的知识,希望对你有一定的参考价值。

CSDN摘要:本文将引导你如何使用ZEGO Flutter SDK 快速轻松的构建一个跨平台音视频聊天应用,减少开发成本。

前言

本文将引导你如何使用ZEGO Flutter SDK 快速轻松的构建一个跨平台音视频聊天应用,大大降低开发成本,适合想要快速完成多端共用音视频项目的开发者;

1 准备环境

在开始集成 ZEGO Express SDK 前,请确保开发环境满足以下要求:

  • Flutter 1.12 或以上版本。
  • ios 7.0 或以上版本,且支持音视频的 iOS 设备或模拟器(推荐使用真机)。
  • android 4.4 或以上版本,且支持音视频的 Android 设备或模拟器(推荐使用真机)。如果为真机,请开启“允许调试”选项。
  • iOS / Android 设备已经连接到 Internet。

请配置开发环境如下:

  • Android Studio:“Preferences > Plugins”,搜索 “Flutter” 插件进行下载,并在插件中配置已经下载好的 Flutter 的 SDK 路径。
  • VS Code: 在应用商店中搜索 “Flutter” 扩展并下载。

以上任一开发环境配置好 Flutter 环境后,在终端执行 flutter doctor,根据提示内容补全相关未下载的依赖项。

2 项目准备

2.1 创建项目

进入即构官网(ZEGO管理控制台),在【ZEGO控制台】(ZEGO管理控制台)创建项目,并申请有效的 AppID,这一步很关键,appid为应用的唯一标识,如身份证号,是应用的身份证明,用于明确你的项目及组织身份。zego提供的服务也是基于APP ID;

App ID的获取方式很简单,只需3~5分钟,在即构官网-我的项目-创建即可。创建的项目信息可用于SDK的集成和配置;

2.2 Token 鉴权

  • 登录房间时必须 使用 Token 鉴权 ,可参考 Token 鉴权教程 
  • 为了方便开发阶段的调试,开发者可直接在 ZEGO 控制台获取临时 Token(有效期为 24 小时) 来使用,详情请参考 控制台(新版) - 项目管理 中的 “项目信息”。

3 集成

3.1 项目设置

开始集成前,请参考 Flutter 文档 - Get Started 创建一个 Flutter 项目。

如已有项目,本步骤可忽略;

接下来我们需要对项目做一下简单的配置,便于导入和使用ZEGO Flutter SDK。

3.2 导入 SDK

  1. 打开 “pubspec.yaml” 文件,添加 “zego_express_engine” 依赖,有以下两种形式:
  • 以 “pub” 形式依赖(推荐):
dependencies:
flutter:
sdk: flutter

zego_express_engine: ^2.0.0
  • 以 “git” 形式依赖:
dependencies:
flutter:
sdk: flutter


zego_express_engine:
  git:
    url: git://github.com/zegoim/zego-express-flutter-sdk.git
    ref: master
  1. 添加完成并保存文件后,在终端执行 flutter pub get

4 设置权限

以上步骤集成已完成,为保证SDK运行效果更佳,需要在应用中根据实际应用需要,设置应用所需权限。步骤如下:

4.1 Android 添加权限

进入 “app/src/main” 目录,打开 “AndroidManifest.xml” 文件,添加权限。

<!-- Permissions required by the SDK -->
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<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.CAMERA" />
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />


<!-- Permissions required by the Demo App -->
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />


<uses-feature android:glEsVersion="0x00020000" android:required="true" />
<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus" />

因为 Android 6.0 在一些比较重要的权限上要求必须申请动态权限,不能只通过 “AndroidMainfest.xml” 文件申请静态权限。请在 Android 原生层参考执行如下代码,其中 “requestPermissions” 是 “Activity” 的方法。

String[] permissionNeeded = 
    "android.permission.CAMERA",
    "android.permission.RECORD_AUDIO";


if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) 
    if (ContextCompat.checkSelfPermission(this, "android.permission.CAMERA") != PackageManager.PERMISSION_GRANTED ||
        ContextCompat.checkSelfPermission(this, "android.permission.RECORD_AUDIO") != PackageManager.PERMISSION_GRANTED) 
        requestPermissions(permissionNeeded, 101);
    

具体的权限说明如下:

必要性

权限

权限说明

申请原因

必要权限

INTERNET

访问网络权限。

SDK 基本功能都需要在联网的情况下才可以使用。

ACCESS_WIFI_STATE

获取当前 WiFi 状态权限。

SDK 会根据网络状态的改变执行不同的操作。例如当网络重连的时候,SDK 内部会将网络断开时的状态都恢复,用户不需做额外的操作。

ACCESS_NETWORK_STATE

获取当前网络状态权限。

CAMERA

访问相机权限。

预览和发送视频的时候需要使用该权限。

RECORD_AUDIO

录制音频权限。

发送音频的时候需要使用该权限。

BLUETOOTH

连接蓝牙设备权限。

连接蓝牙设备时需要使用该权限。

MODIFY_AUDIO_SETTINGS

修改音频配置权限。

修改音频设备配置时需要使用该权限。

WRITE_EXTERNAL_STORAGE

内置 SDK 写权限。

SDK 会将日志和相关配置文件保存在内置 SDK 内。

非必要权限

READ_PHONE_STATE

允许以只读方式访问电话状态,包括当前的呼叫状态。

SDK 会根据当前的呼叫状态,启停音频设备。如监听到当前为呼叫状态,则 SDK 会自动停止使用音频设备,直到通话结束。

4.2 iOS 添加权限

打开项目,选择菜单 “TARGETS > Info > Custom iOS Target Properties”。

单击 “+” 按钮,添加摄像头和麦克风权限。

  • Privacy - Camera Usage Description
  • Privacy - Microphone Usage Description

权限添加完成后,如图所示:

5 实现流程

如以下流程图,用户A与B通过 ZEGO Express SDK 进行视频通话,以用户 A 拉取用户 B 的流为例:

为保证实时音视频的通话质量,推拉流关键流程需按照API的正确调用时序进行,完整时序如下图:

5.1 创建引擎

1. 引入 SDK

在项目中引入 SDK。

1import 'package:zego_express_engine/zego_express_engine.dart';

2. 创建引擎

2. 创建引擎

调用 createEngineWithProfile 接口,将申请到的 AppID 传入参数 “appID”。

ZegoEngineProfile profile = ZegoEngineProfile(
    appID, // 请通过官网注册获取,格式为:1234567890
    ZegoScenario.General, // 通用场景接入
    enablePlatformView: true);
// 创建引擎
ZegoExpressEngine.createEngineWithProfile(profile);


5.2 登录房间


1. 登录

传入用户 ID 参数 “userID” 创建 ZegoUser 用户对象后,调用 loginRoom 接口,传入房间 ID 参数 “roomID” 和用户参数 “user”,登录房间。

同一个 AppID 内,需保证 “roomID” 信息的全局唯一。
同一个 AppID 内,需保证 “userID”全局唯一,建议开发者将其设置成一个有意义的值,可将 “userID” 与自己业务账号系统进行关联。
“ZegoUser” 的构造方法ZegoUser.id 会将 “userName” 设为与传的参数 “userID” 一样。“userID” 与 “userName”不能为 “null”,否则会导致登录房间失败。

// 创建用户对象
ZegoUser user = ZegoUser.id('user1');
// 只有传入 “isUserStatusNotify” 参数取值为 “true” 的 ZegoRoomConfig,才能收到 onRoomUserUpdate 回调。
ZegoRoomConfig config = ZegoRoomConfig.defaultConfig();
config.isUserStatusNotify = true;
// token 由用户自己的服务端生成,为了更快跑通流程,也可以通过即构控制台获取临时的音视频 token
config.token = "xxxx";
// 开始登录房间
ZegoExpressEngine.instance.loginRoom('room1', user, config: config);

2. 监听登录房间后的事件回调


根据实际应用需要,在登录房间后监听想要关注的事件通知,比如房间状态更新、用户状态更新、流状态更新等。

onRoomStateUpdate:房间状态更新回调。登录房间后,当房间连接状态发生变更(如出现房间断开,登录认证失败等情况),SDK会通过该回调通知。 onRoomUserUpdate:用户状态更新回调。登录房间后,当房间内有用户新增或删除时,SDK 会通过该回调通知。
只有调用 loginRoom 接口登录房间时传入 ZegoRoomConfig 配置,且 “isUserStatusNotify”参数取值为 “true” 时,用户才能收到 onRoomUserUpdate 回调。
onRoomStreamUpdate:流状态更新回调。登录房间后,当房间内有用户新推送或删除音视频流时,SDK 会通过该回调通知。 

// 以下为常用的房间相关回调
// 房间状态更新回调
ZegoExpressEngine.onRoomStateUpdate = (String roomID, ZegoRoomState state, int errorCode, Map<String, dynamic> extendedData) 
    // 根据需要实现事件回调
;

// 用户状态更新
ZegoExpressEngine.onRoomUserUpdate = (String roomID, ZegoUpdateType updateType, List<ZegoUser> userList) 
    // 根据需要实现事件回调
;

// 流状态更新
ZegoExpressEngine.onRoomStreamUpdate = (String roomID, ZegoUpdateType updateType, List<ZegoStream> streamList) 
    // 根据需要实现事件回调
;


5.3 推流


1. 开始推流


调用 startPublishingStream 接口,传入流 ID 参数 “streamID”,向远端用户发送本端的音视频流。
同一个 AppID 内,需保证 “streamID” 全局唯一。如果同一个 AppID 内,不同用户各推了一条 “streamID” 相同的流,会导致后推流的用户推流失败。

// 开始推流
ZegoExpressEngine.instance.startPublishingStream("streamID");
1
2
2. 启用本地渲染和预览
如果希望看到本端的画面,可将画面渲染后,调用 startPreview 接口启动本地预览。
Flutter 的渲染方式有两种:PlatformView 与 TextureRenderer。与 TextureRenderer 相比,PlatformView占用资源稍高,且稳定性偏低,但随着 Flutter 版本迭代,鲁棒性不断提高。开发者可根据实际情况通过任意一种方式实现渲染。

使用 TextureRenderer 方式渲染

开启 TextureRenderer 后,在销毁引擎之前,只能使用 TextureRenderer 而不能使用 PlatformView。
(1)创建预览用的 “TextureRenderer”(外接纹理)。 

void createPreviewRenderer() 
    ZegoExpressEngine.instance.createTextureRenderer(widget.screenWidthPx, widget.screenHeightPx).then((textureID) 

        _previewViewID = textureID;

        setState(() 
            // Create a Texture Widget
            Widget previewViewWidget = Texture(textureId: textureID);
            // 将此 Widget 加入到页面的渲染树中以显示预览画面
            _previewViewWidget = previewViewWidget;
        );

        // Start preview using texture renderer
        _startPreview(textureID);
    );

(2)使用 TextureRenderer 的 “textureID” 作为 “viewID” 创建一个 ZegoCanvas 对象,开始预览。 

  // Set the preview canvas
    ZegoCanvas previewCanvas = ZegoCanvas.view(viewID);

    // Start preview
    ZegoExpressEngine.instance.startPreview(canvas: previewCanvas);

3. 监听推流后的事件回调

根据实际应用需要,在推流后监听想要关注的事件通知,比如推流状态更新等。
onPublisherStateUpdate:推流状态更新回调。调用推流接口成功后,当推流状态发生变更(如出现网络中断导致推流异常等情况),SDK 在重试推流的同时,会通过该回调通知。

// 常用的推流相关回调
// 推流状态更新回调
ZegoExpressEngine.onPublisherStateUpdate = (String streamID, ZegoPublisherState state, int errorCode, Map<String, dynamic> extendedData) 
    // 根据需要实现事件回调
;


5.4 拉流


调用 startPlayingStream 接口,根据传入的流 ID 参数 “streamID”,拉取远端推送的音视频流,并根据需要渲染拉流画面。

若仅需拉音频流,不需要显示拉流画面,可直接调用 startPlayingStream 接口。
ZegoExpressEngine.instance.startPlayingStream(streamID);
若需要在拉流的同时,渲染拉流画面,Flutter 的渲染方式有两种:PlatformView 与 TextureRenderer。与 TextureRenderer 相比,PlatformView占用资源稍高,且稳定性偏低,但随着 Flutter 版本迭代,鲁棒性不断提高。开发者可根据实际情况通过任意一种方式实现渲染。
使用 TextureRenderer 方式渲染


(1)创建预览用的 “TextureRenderer”(外接纹理)。

ZegoExpressEngine.instance.createTextureRenderer(width.toInt(), height.toInt()).then((viewID) 
    _playViewID = viewID;
    // 将得到的 Widget 加入到页面的渲染树中以显示拉流画面
    setState(() => _playViewWidget = Texture(textureId: viewID));
    _startPlayingStream(viewID, streamID);
);


(2)使用 TextureRenderer 的 “textureID” 作为 “viewID” 创建一个 ZegoCanvas 对象,开始拉流并渲染拉流画面。

void _startPlayingStream(int viewID, String streamID) 
    ZegoCanvas canvas = ZegoCanvas.view(viewID);
    ZegoExpressEngine.instance.startPlayingStream(streamID, canvas: canvas);


5.5 体验实时音视频功能


在真机中运行项目,运行成功后,可以看到本端视频画面。
为方便体验,ZEGO 提供了一个 Web 端调试示例,在该页面下,输入相同的 AppID、RoomID、Server 地址和 Token,即可加入同一房间与真机设备互通。当成功开始音视频通话时,可以听到远端的音频,看到远端的视频画面。

5.6 停止推拉流


1. 停止推流/预览/渲染
调用 stopPublishingStream 接口停止向远端用户发送本端的音视频流。

// 停止推流
ZegoExpressEngine.instance.stopPublishingStream();



如果启用了本地预览,调用 stopPreview 接口停止预览。

// 停止预览
ZegoExpressEngine.instance.stopPreview();
1
2
如果预览时创建了 TextureRenderer,需要调用 destroyTextureRenderer 接口销毁 TextureRenderer。

// _previewViewID 为调用 createTextureRenderer 时得到的 viewID
ZegoExpressEngine.instance.destroyTextureRenderer(_previewViewID);
1
2
如果预览时创建了 PlatformView,需要调用 destroyPlatformView 接口销毁 PlatformView。

// _previewViewID 为调用 [createPlatformView] 时得到的 viewID
ZegoExpressEngine.instance.destroyPlatformView(_previewViewID);
 


2. 停止拉流/渲染

调用 stopPlayingStream 接口停止拉取远端推送的音视频流。

// 停止拉流
ZegoExpressEngine.instance.stopPlayingStream(streamID, canvas: _playCanvas);
1
2
如果拉流时创建了 TextureRenderer,需要调用 destroyTextureRenderer 接口销毁 TextureRenderer。

// _playViewID 为调用 [createTextureRenderer] 时得到的 viewID
ZegoExpressEngine.instance.destroyTextureRenderer(_playViewID);
 
如果拉流时创建了 PlatformView,需要调用 destroyPlatformView 接口销毁 PlatformView。

// _playViewID 为调用 [createPlatformView] 时得到的 viewID
ZegoExpressEngine.instance.destroyPlatformView(_playViewID);


5.7 退出房间


调用 logoutRoom 接口退出房间。

// 退出房间
ZegoExpressEngine.instance.logoutRoom('room1');


5.8 销毁引擎

调用 destroyEngine 接口销毁引擎,用于释放 SDK 使用的资源。

// 销毁引擎
ZegoExpressEngine.destroyEngine();


结尾
 

恭喜,你已经通过ZEGO Flutter SDK完成了自己的实时音视频通话应用,Flutter为应用开发带来了革新,带着学习交流的态度,希望对于想要学习应用Flutter的同学有所帮助。

注册即构ZEGO开发者帐号,快速开始。(ZEGO管理控制台

开发者涨薪指南 48位大咖的思考法则、工作方式、逻辑体系

以上是关于Flutter 实战-快速实现音视频通话应用的主要内容,如果未能解决你的问题,请参考以下文章

Flutter 实战-快速实现音视频通话应用

如何基于 React Native 快速实现一个视频通话应用

Unity实战篇 | 接入 声网SDK 实现 视频通话——自己动手做一个 视频通话

如何在uni-app 平台快速实现一对一音视频通话应用

基于声网 Flutter SDK 实现多人视频通话

如何通过 Flutter 应用启动 whatsapp 视频通话?