Flutter屏幕流媒体插件screen_streamer的使用

Flutter屏幕流媒体插件screen_streamer的使用

简介

screen_streamer 是一个利用 flutter_webrtc 包实现屏幕共享的 Flutter 插件。该插件的灵感来源于一个已关闭的 Flutter Issue

该插件支持所有 Flutter 平台,包括 Web,但目前仅在 Android、iOS、MacOS 和 Web 上进行了测试。

该插件提供了两个示例:一个用于发送屏幕(发送示例),另一个用于接收屏幕(接收示例)。

请注意,此库在模拟器或模拟设备上无法工作,因为底层框架不存在。必须使用物理设备来使用此框架。

配置

Android

在 Android 上,您必须添加三个权限:

  1. android.permission.ACCESS_NETWORK_STATE
  2. android.permission.FOREGROUND_SERVICE
  3. android.permission.SCHEDULE_EXACT_ALARM

接下来,在 <application> 标签内,您必须添加以下服务:

<service android:name="id.flutter.flutter_background_service.BackgroundService"
    android:foregroundServiceType="mediaProjection"
    android:enabled="true"
    android:exported="false"
    tools:replace="android:exported" />

您的 AndroidManifest.xml 文件现在将类似于:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    package="com.example.sender">

    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
    <uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM" />

    <application
        android:label="sender"
        android:name="${applicationName}"
        android:icon="@mipmap/ic_launcher">
        <activity
            android:name=".MainActivity"
            android:exported="true"
            android:launchMode="singleTop"
            android:theme="@style/LaunchTheme"
            android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
            android:hardwareAccelerated="true"
            android:windowSoftInputMode="adjustResize">
            <meta-data
                android:name="io.flutter.embedding.android.NormalTheme"
                android:resource="@style/NormalTheme"
            />
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <!-- Don't delete the meta-data below.
             This is used by the Flutter tool to
        generate GeneratedPluginRegistrant.java -->
        <meta-data
            android:name="flutterEmbedding"
            android:value="2" />

        <service android:name="id.flutter.flutter_background_service.BackgroundService"
            android:foregroundServiceType="mediaProjection"
            android:enabled="true"
            android:exported="false"
            tools:replace="android:exported" />

    </application>
</manifest>

iOS

对于 iOS,无需进行特殊配置。

MacOS

在 Xcode 中打开您的 macOS 工作区,并为所有构建模式启用网络权限:

  • Incoming Connections (Server)
  • Outgoing Connections (Client)

Linux

对于 Linux,没有已知的特殊配置需求。

Web

对于 Web,没有已知的特殊配置需求。

Windows

对于 Windows,没有已知的特殊配置需求。

使用

发送

要将屏幕发送到远程接收者,您可以使用 ScreenSender 类。

final sender = ScreenSender();
await sender.connect(
  Uri.parse(_controller.text),
  context: context,
);

接收

要接收远程发送的屏幕,您可以使用 ScreenReceiver 类以及 RemoteScreenRenderer

import 'package:flutter/material.dart';
import 'package:logging/logging.dart';
import 'package:screen_streamer/screen_streamer.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Receiver',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({
    super.key,
  });

  [@override](/user/override)
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  final ScreenReceiver _receiver = ScreenReceiver();

  bool _connected = false;

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

    _receiver.listen().then((value) {
      _connected = true;
      if (mounted) {
        setState(() {});
      }
    });
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(_connected ? 'Connected' : 'Waiting'),
      ),
      body: _connected
          ? RemoteScreenRenderer(receiver: _receiver)
          : Center(
              child: Column(
                crossAxisAlignment: CrossAxisAlignment.center,
                mainAxisAlignment: MainAxisAlignment.center,
                mainAxisSize: MainAxisSize.max,
                children: [
                  const CircularProgressIndicator(),
                  FutureBuilder(
                    builder: (context, snapshot) => snapshot.hasData
                        ? Padding(
                            padding: const EdgeInsets.only(top: 8.0),
                            child: Text(snapshot.data.toString()),
                          )
                        : const SizedBox(),
                    future: _receiver.uri,
                  ),
                ],
              ),
            ),
    );
  }
}

更多关于Flutter屏幕流媒体插件screen_streamer的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter屏幕流媒体插件screen_streamer的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,下面是一个关于如何在Flutter项目中使用screen_streamer插件来实现屏幕流媒体功能的代码示例。screen_streamer插件允许你将Flutter应用的屏幕内容实时流式传输到其他设备或平台。

首先,确保你的Flutter环境已经正确设置,并且你的项目已经创建。然后,你需要添加screen_streamer依赖到你的pubspec.yaml文件中:

dependencies:
  flutter:
    sdk: flutter
  screen_streamer: ^最新版本号  # 请替换为实际的最新版本号

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

接下来,你需要请求必要的权限(如录音和显示覆盖权限),并初始化ScreenStreamer。以下是一个完整的示例代码,展示了如何使用screen_streamer插件:

import 'package:flutter/material.dart';
import 'package:screen_streamer/screen_streamer.dart';
import 'package:permission_handler/permission_handler.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  late ScreenStreamer _screenStreamer;
  bool _isStreaming = false;

  @override
  void initState() {
    super.initState();
    _screenStreamer = ScreenStreamer();
    _initPermissions();
  }

  Future<void> _initPermissions() async {
    // 请求录音权限(如果需要音频流)
    var status = await Permission.microphone.status;
    if (!status.isGranted) {
      Map<Permission, PermissionStatus> statuses = await [
        Permission.microphone,
        Permission.overlayWindow, // 请求显示覆盖权限
      ].request();

      status = statuses[Permission.microphone]!;
    }

    if (status.isGranted) {
      // 权限已授予,可以开始初始化屏幕流媒体
      _initScreenStreamer();
    } else {
      // 处理权限被拒绝的情况
      print('Microphone permission is denied');
    }
  }

  Future<void> _initScreenStreamer() async {
    try {
      // 配置屏幕流媒体(例如,设置流媒体URL)
      String rtmpUrl = 'rtmp://your.streaming.server/live/streamkey'; // 替换为你的RTMP服务器URL
      await _screenStreamer.initialize(
        rtmpUrl: rtmpUrl,
        audioEnabled: true, // 是否启用音频
        videoBitrate: 2000000, // 视频比特率
        videoResolution: Size(1280, 720), // 视频分辨率
      );
      print('Screen streamer initialized');
    } catch (e) {
      print('Error initializing screen streamer: $e');
    }
  }

  void _startStreaming() async {
    if (!_isStreaming) {
      try {
        await _screenStreamer.start();
        setState(() {
          _isStreaming = true;
        });
        print('Streaming started');
      } catch (e) {
        print('Error starting streaming: $e');
      }
    }
  }

  void _stopStreaming() async {
    if (_isStreaming) {
      await _screenStreamer.stop();
      setState(() {
        _isStreaming = false;
      });
      print('Streaming stopped');
    }
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Screen Streamer Example'),
        ),
        body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              ElevatedButton(
                onPressed: _isStreaming ? _stopStreaming : _startStreaming,
                child: Text(_isStreaming ? 'Stop Streaming' : 'Start Streaming'),
              ),
            ],
          ),
        ),
      ),
    );
  }

  @override
  void dispose() {
    _screenStreamer.dispose();
    super.dispose();
  }
}

说明:

  1. 权限请求:使用permission_handler插件请求必要的权限(录音和显示覆盖权限)。
  2. 初始化ScreenStreamer:在权限被授予后,初始化ScreenStreamer实例,并配置RTMP URL、音频启用状态、视频比特率和视频分辨率等参数。
  3. 开始/停止流媒体:提供开始和停止屏幕流媒体的功能。
  4. UI:一个简单的UI,包含一个按钮来开始或停止流媒体。

注意:

  • 请确保你有一个RTMP服务器来接收流媒体数据。
  • screen_streamer插件可能有一些特定的配置要求,请查阅其官方文档以获取更多信息。
  • 在实际使用中,可能还需要处理更多的错误和状态管理。

这个示例提供了一个基本的框架,你可以根据需要进行扩展和自定义。

回到顶部