Flutter WebRTC通信插件flutter_webrtc_haoxin的使用

Flutter WebRTC 通信插件 flutter_webrtc_haoxin 的使用

功能性

功能 Android iOS Web macOS Windows Linux 嵌入式 Fuchsia
音频/视频 ✔️ ✔️ ✔️ ✔️ ✔️ ✔️ [WIP]
数据通道 ✔️ ✔️ ✔️ ✔️ ✔️ ✔️ [WIP]
屏幕捕获 ✔️ ✔️(*) ✔️ ✔️ ✔️ ✔️ [WIP]
统一计划 ✔️ ✔️ ✔️ ✔️ ✔️ ✔️ [WIP]
多流传输 ✔️ ✔️ ✔️ ✔️ ✔️ ✔️ [WIP]
媒体录制器 ⚠️ ⚠️ ✔️
插入流

使用

flutter_webrtc 作为依赖项添加到你的 pubspec.yaml 文件中。

iOS

<项目根目录>/ios/Runner/Info.plist 文件中添加以下条目:

<key>NSCameraUsageDescription</key>
<string>$(PRODUCT_NAME) Camera Usage!</string>
<key>NSMicrophoneUsageDescription</key>
<string>$(PRODUCT_NAME) Microphone Usage!</string>

此条目允许应用程序访问相机和麦克风。

iOS 注意事项

编译后 m104 版本的 WebRTC.xframework 不再支持 iOS arm 设备。因此,你需要在你的项目的 ios/Podfile 中添加以下行:

post_install do |installer|
  installer.pods_project.targets.each do |target|
    flutter_additional_ios_build_settings(target)
    target.build_configurations.each do |config|
      # 解决 https://github.com/flutter/flutter/issues/64502 的问题
      config.build_settings['ONLY_ACTIVE_ARCH'] = 'YES' # 这一行
    end
  end
end

Android

确保在 <项目根目录>/android/app/src/main/AndroidManifest.xml 文件中包含以下权限:

<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />

如果需要使用蓝牙设备,请添加以下权限:

<uses-permission android:name="android.permission.BLUETOOTH" android:maxSdkVersion="30" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" android:maxSdkVersion="30" />

默认情况下,Flutter 项目模板已经添加了这些权限,可能已经存在。

还需要将构建设置更改为 Java 8,因为官方 WebRTC jar 现在使用 EglBase 接口中的静态方法。只需在应用级 build.gradle 文件中添加以下内容:

android {
    //...
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
}

如果有必要,在同一个 build.gradle 文件中,你可能需要增加 defaultConfigminSdkVersion 到 23(当前默认的 Flutter 生成器设置为 16)。

重要提醒

当你编译发布 APK 时,需要添加以下操作:

设置 ProGuard 规则

贡献

该项目离不开社区贡献者的支持。

示例

更多示例请参见 flutter-webrtc-demo

示例代码

example/lib/main.dart

import 'dart:core';

import 'package:flutter/foundation.dart'
    show debugDefaultTargetPlatformOverride;
import 'package:flutter/material.dart';
import 'package:flutter_background/flutter_background.dart';
import 'package:flutter_webrtc_haoxin/flutter_webrtc_haoxin.dart';

import 'src/get_display_media_sample.dart';
import 'src/get_user_media_sample.dart'
    if (dart.library.html) 'src/get_user_media_sample_web.dart';
import 'src/loopback_data_channel_sample.dart';
import 'src/loopback_sample.dart';
import 'src/loopback_sample_unified_tracks.dart';
import 'src/route_item.dart';

void main() {
  WidgetsFlutterBinding.ensureInitialized();
  if (WebRTC.platformIsDesktop) {
    debugDefaultTargetPlatformOverride = TargetPlatform.fuchsia;
  } else if (WebRTC.platformIsAndroid) {
    startForegroundService();
  }
  runApp(MyApp());
}

Future<bool> startForegroundService() async {
  final androidConfig = FlutterBackgroundAndroidConfig(
    notificationTitle: 'Title of the notification',
    notificationText: 'Text of the notification',
    notificationImportance: AndroidNotificationImportance.Default,
    notificationIcon: AndroidResource(
        name: 'background_icon',
        defType: 'drawable'), // 默认是来自文件夹 mipmap 的 ic_launcher
  );
  await FlutterBackground.initialize(androidConfig: androidConfig);
  return FlutterBackground.enableBackgroundExecution();
}

class MyApp extends StatefulWidget {
  [@override](/user/override)
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  late List<RouteItem> items;

  [@override](/user/override)
  void initState() {
    super.initState();
    _initItems();
  }

  ListBody _buildRow(context, item) {
    return ListBody(children: <Widget>[
      ListTile(
        title: Text(item.title),
        onTap: () => item.push(context),
        trailing: Icon(Icons.arrow_right),
      ),
      Divider()
    ]);
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      home: Scaffold(
          appBar: AppBar(
            title: Text('Flutter-WebRTC 示例'),
          ),
          body: ListView.builder(
              shrinkWrap: true,
              padding: const EdgeInsets.all(0.0),
              itemCount: items.length,
              itemBuilder: (context, i) {
                return _buildRow(context, items[i]);
              })),
    );
  }

  void _initItems() {
    items = <RouteItem>[
      RouteItem(
          title: 'GetUserMedia',
          push: (BuildContext context) {
            Navigator.push(
                context,
                MaterialPageRoute(
                    builder: (BuildContext context) => GetUserMediaSample()));
          }),
      RouteItem(
          title: 'GetDisplayMedia',
          push: (BuildContext context) {
            Navigator.push(
                context,
                MaterialPageRoute(
                    builder: (BuildContext context) =>
                        GetDisplayMediaSample()));
          }),
      RouteItem(
          title: 'LoopBack Sample',
          push: (BuildContext context) {
            Navigator.push(
                context,
                MaterialPageRoute(
                    builder: (BuildContext context) => LoopBackSample()));
          }),
      RouteItem(
          title: 'LoopBack Sample (Unified Tracks)',
          push: (BuildContext context) {
            Navigator.push(
                context,
                MaterialPageRoute(
                    builder: (BuildContext context) =>
                        LoopBackSampleUnifiedTracks()));
          }),
      RouteItem(
          title: 'DataChannelLoopBackSample',
          push: (BuildContext context) {
            Navigator.push(
                context,
                MaterialPageRoute(
                    builder: (BuildContext context) =>
                        DataChannelLoopBackSample()));
          }),
    ];
  }
}

更多关于Flutter WebRTC通信插件flutter_webrtc_haoxin的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter WebRTC通信插件flutter_webrtc_haoxin的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


flutter_webrtc_haoxin 是一个基于 WebRTC 的 Flutter 插件,用于在 Flutter 应用中实现实时音视频通信。它是对官方 flutter_webrtc 插件的一个扩展或优化版本,提供了更多的功能或更好的性能。

以下是如何在 Flutter 项目中使用 flutter_webrtc_haoxin 插件的基本步骤:

1. 添加依赖

首先,在 pubspec.yaml 文件中添加 flutter_webrtc_haoxin 插件的依赖:

dependencies:
  flutter:
    sdk: flutter
  flutter_webrtc_haoxin: ^0.9.0  # 请检查最新版本

然后运行 flutter pub get 来下载并安装依赖。

2. 配置项目

根据目标平台(Android、iOS、Web),你可能需要进行一些额外的配置。

Android

确保在 android/app/build.gradle 文件中设置了正确的 minSdkVersion

android {
    defaultConfig {
        minSdkVersion 21
    }
}

iOS

确保在 ios/Podfile 中设置了正确的平台版本:

platform :ios, '10.0'

Web

对于 Web 平台,确保在 index.html 中添加了 WebRTC 相关的脚本:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <title>Flutter WebRTC</title>
    <script src="https://cdn.jsdelivr.net/npm/webrtc-adapter@latest"></script>
  </head>
  <body>
    <script src="main.dart.js"></script>
  </body>
</html>

3. 初始化 WebRTC

在你的 Dart 代码中,导入 flutter_webrtc_haoxin 插件并初始化 WebRTC:

import 'package:flutter_webrtc_haoxin/flutter_webrtc_haoxin.dart';

void initWebRTC() async {
  // 初始化 WebRTC
  await WebRTC.initialize();
}

4. 创建本地和远程视频轨道

使用 RTCPeerConnection 来创建本地和远程视频轨道,并显示视频流。

import 'package:flutter/material.dart';
import 'package:flutter_webrtc_haoxin/flutter_webrtc_haoxin.dart';

class VideoCallScreen extends StatefulWidget {
  @override
  _VideoCallScreenState createState() => _VideoCallScreenState();
}

class _VideoCallScreenState extends State<VideoCallScreen> {
  RTCPeerConnection? _peerConnection;
  MediaStream? _localStream;
  MediaStream? _remoteStream;
  RTCVideoRenderer _localRenderer = RTCVideoRenderer();
  RTCVideoRenderer _remoteRenderer = RTCVideoRenderer();

  @override
  void initState() {
    super.initState();
    initRenderers();
    createPeerConnection();
  }

  Future<void> initRenderers() async {
    await _localRenderer.initialize();
    await _remoteRenderer.initialize();
  }

  Future<void> createPeerConnection() async {
    _peerConnection = await createPeerConnection({
      'iceServers': [
        {'urls': 'stun:stun.l.google.com:19302'},
      ],
    });

    _peerConnection!.onIceCandidate = (RTCIceCandidate candidate) {
      // 处理 ICE 候选
    };

    _peerConnection!.onAddStream = (MediaStream stream) {
      setState(() {
        _remoteStream = stream;
        _remoteRenderer.srcObject = _remoteStream;
      });
    };

    _localStream = await navigator.mediaDevices.getUserMedia({
      'audio': true,
      'video': true,
    });

    _localRenderer.srcObject = _localStream;
    _peerConnection!.addStream(_localStream!);
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('WebRTC Video Call'),
      ),
      body: Column(
        children: [
          Expanded(
            child: RTCVideoView(_localRenderer),
          ),
          Expanded(
            child: RTCVideoView(_remoteRenderer),
          ),
        ],
      ),
    );
  }

  @override
  void dispose() {
    _localRenderer.dispose();
    _remoteRenderer.dispose();
    super.dispose();
  }
}

5. 处理信令

WebRTC 需要信令服务器来交换 SDP 和 ICE 候选。你可以使用 WebSocket 或其他信令机制来实现。

void handleOffer(RTCSessionDescription offer) async {
  await _peerConnection!.setRemoteDescription(offer);
  RTCSessionDescription answer = await _peerConnection!.createAnswer();
  await _peerConnection!.setLocalDescription(answer);
  // 发送 answer 到对方
}

void handleAnswer(RTCSessionDescription answer) async {
  await _peerConnection!.setRemoteDescription(answer);
}

void handleIceCandidate(RTCIceCandidate candidate) async {
  await _peerConnection!.addIceCandidate(candidate);
}

6. 启动应用

最后,启动你的 Flutter 应用并测试 WebRTC 功能。

void main() {
  runApp(MaterialApp(
    home: VideoCallScreen(),
  ));
}
回到顶部