Flutter视频投射插件flutter_video_cast_v2的使用

Flutter视频投射插件flutter_video_cast_v2的使用

flutter_video_cast_v2 是一个用于在 Flutter 应用程序中连接到 Chromecast 和 Apple TV 等投射设备的插件。以下是如何在你的 Flutter 应用程序中使用这个插件的详细步骤。

安装

首先,在 pubspec.yaml 文件中添加 flutter_video_cast_v2 作为依赖项:

dependencies:
  flutter_video_cast_v2: ^版本号

然后运行 flutter pub get 来获取新的依赖项。

iOS 配置

  1. 将项目的最低操作系统目标设置为 iOS 11.0。
  2. ios/Runner/AppDelegate.m 中初始化 Cast 上下文:
import UIKit
import Flutter
import GoogleCast

@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate, GCKLoggerDelegate {
    let kReceiverAppID = kGCKDefaultMediaReceiverApplicationID
    let kDebugLoggingEnabled = true

    override func application(
        _ application: UIApplication,
        didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
    ) -> Bool {
        GeneratedPluginRegistrant.register(with: self)
        let criteria = GCKDiscoveryCriteria(applicationID: kReceiverAppID)
        let options = GCKCastOptions(discoveryCriteria: criteria)
        GCKCastContext.setSharedInstanceWith(options)
        GCKCastContext.sharedInstance().useDefaultExpandedMediaControls = true
        GCKLogger.sharedInstance().delegate = self
        return super.application(application, didFinishLaunchingWithOptions: launchOptions)
    }
}
  1. 为了允许嵌入视图预览,在应用的 Info.plist 文件中添加一个布尔属性,键为 io.flutter.embedded_views_preview,值为 YES

Android 配置

  1. 在模块(应用级别)的 Gradle 文件(通常为 android/app/build.gradle)中添加依赖项:
implementation 'com.google.android.gms:play-services-cast-framework:19.0.0'
implementation 'com.google.android.exoplayer:extension-cast:2.11.5'
  1. 在应用的 AndroidManifest.xml 文件中将 MainActivity 的主题设置为 @style/Theme.AppCompat.NoActionBar
<manifest ...>
  <application ...
    <meta-data android:name="com.google.android.gms.cast.framework.OPTIONS_PROVIDER_CLASS_NAME"
               android:value="com.google.android.exoplayer2.ext.cast.DefaultCastOptionsProvider"/>
    ...
    <activity android:theme="@style/Theme.AppCompat.NoActionBar" ...
  1. MainActivity 继承 FlutterFragmentActivity 并初始化 Cast 上下文:
CastContext.getSharedInstance(applicationContext)

通用配置

现在,你可以在你的小部件树中添加一个 ChromeCastButton 小部件。按钮可以通过 ChromeCastController 控制,该控制器通过 ChromeCastButtononButtonCreated 回调传递。

以下是完整的示例代码:

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

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

class MyApp extends StatelessWidget {
  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      home: CastSample(),
    );
  }
}

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

class _CastSampleState extends State<CastSample> {
  ChromeCastController? _controller;

  [@override](/user/override)
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Cast Sample'),
        actions: [
          ChromeCastButton(
            onButtonCreated: (controller) {
              setState(() => _controller = controller);
              _controller?.addSessionListener();
            },
            onSessionStarted: () {
              _controller?.loadMedia('https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4');
            },
          ),
        ],
      ),
    );
  }
}

完整示例代码

以下是完整的示例代码,展示了如何在 Flutter 应用程序中使用 flutter_video_cast_v2 插件:

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

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

class MyApp extends StatelessWidget {
  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(home: CastSample());
  }
}

class CastSample extends StatefulWidget {
  static const _iconSize = 50.0;

  [@override](/user/override)
  _CastSampleState createState() => _CastSampleState();
}

class _CastSampleState extends State<CastSample> {
  late ChromeCastController _controller;
  AppState _state = AppState.idle;
  bool? _playing = false;

  [@override](/user/override)
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Plugin example app'),
        actions: [
          AirPlayButton(
            size: CastSample._iconSize,
            color: Colors.white,
            activeColor: Colors.amber,
            onRoutesOpening: () => print('opening'),
            onRoutesClosed: () => print('closed'),
          ),
          ChromeCastButton(
            size: CastSample._iconSize,
            color: Colors.black,
            onButtonCreated: _onButtonCreated,
            onSessionStarted: _onSessionStarted,
            onSessionEnded: () => setState(() => _state = AppState.idle),
            onRequestCompleted: _onRequestCompleted,
            onRequestFailed: _onRequestFailed,
          ),
        ],
      ),
      body: Center(child: _handleState()),
    );
  }

  Widget _handleState() {
    switch (_state) {
      case AppState.idle:
        return Text('ChromeCast not connected');
      case AppState.connected:
        return Text('No media loaded');
      case AppState.mediaLoaded:
        return _mediaControls();
      case AppState.error:
        return Text('An error has occurred');
      default:
        return Container();
    }
  }

  Widget _mediaControls() {
    return Row(
      mainAxisAlignment: MainAxisAlignment.center,
      children: [
        _RoundIconButton(
          icon: Icons.replay_10,
          onPressed: () => _controller.seek(relative: true, interval: -10.0),
        ),
        _RoundIconButton(
            icon: _playing! ? Icons.pause : Icons.play_arrow,
            onPressed: _playPause),
        _RoundIconButton(
          icon: Icons.forward_10,
          onPressed: () => _controller.seek(relative: true, interval: 10.0),
        )
      ],
    );
  }

  Future<void> _playPause() async {
    final playing = await (_controller.isPlaying() as Future<bool>);
    if (playing) {
      await _controller.pause();
    } else {
      await _controller.play();
    }
    setState(() => _playing = !playing);
  }

  Future<void> _onButtonCreated(ChromeCastController controller) async {
    _controller = controller;
    print('Button Made');
    await _controller.addSessionListener();
  }

  Future<void> _onSessionStarted() async {
    setState(() => _state = AppState.connected);
    await _controller.loadMedia(
        'https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4');
  }

  Future<void> _onRequestCompleted() async {
    final playing = await _controller.isPlaying();
    setState(() {
      _state = AppState.mediaLoaded;
      _playing = playing;
    });
  }

  Future<void> _onRequestFailed(String? error) async {
    setState(() => _state = AppState.error);
    print(error);
  }
}

class _RoundIconButton extends StatelessWidget {
  final IconData icon;
  final VoidCallback onPressed;

  _RoundIconButton({required this.icon, required this.onPressed});

  [@override](/user/override)
  Widget build(BuildContext context) {
    return RaisedButton(
        child: Icon(icon, color: Colors.white),
        padding: EdgeInsets.all(16.0),
        color: Colors.blue,
        shape: CircleBorder(),
        onPressed: onPressed);
  }
}

enum AppState { idle, connected, mediaLoaded, error }

更多关于Flutter视频投射插件flutter_video_cast_v2的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter视频投射插件flutter_video_cast_v2的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,以下是一个关于如何使用 flutter_video_cast_v2 插件的示例代码。这个插件允许你将 Flutter 应用中的视频投射到支持 DLNA 或 Chromecast 的设备上。

首先,确保你已经在 pubspec.yaml 文件中添加了依赖:

dependencies:
  flutter:
    sdk: flutter
  flutter_video_cast_v2: ^x.y.z  # 请替换为最新版本号

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

接下来,你需要进行一些初始化设置,并在你的应用中实现视频投射功能。以下是一个简单的示例:

主应用代码 (main.dart)

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

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Video Cast Example',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: VideoCastScreen(),
    );
  }
}

class VideoCastScreen extends StatefulWidget {
  @override
  _VideoCastScreenState createState() => _VideoCastScreenState();
}

class _VideoCastScreenState extends State<VideoCastScreen> {
  late VideoCastManager _castManager;
  late bool _isCasting;

  @override
  void initState() {
    super.initState();
    _castManager = VideoCastManager();
    _isCasting = false;

    // 监听连接状态变化
    _castManager.deviceManager.addListener(() {
      setState(() {});
    });

    // 初始化设备扫描
    _castManager.initialize();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Flutter Video Cast Example'),
      ),
      body: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Text(
              'Casting Status: $_isCasting',
              style: TextStyle(fontSize: 18),
            ),
            SizedBox(height: 20),
            ElevatedButton(
              onPressed: () async {
                // 扫描可用设备
                await _castManager.deviceManager.scanForDevices();
                final devices = _castManager.deviceManager.devices;
                if (devices.isNotEmpty) {
                  // 选择第一个设备
                  final device = devices.first;
                  // 连接到设备
                  await _castManager.connectToDevice(device);
                  // 开始投射视频
                  await _castManager.loadMedia(
                    'https://www.example.com/path/to/your/video.mp4',
                    metaData: MediaMetadata(
                      title: 'Video Title',
                      subtitle: 'Video Subtitle',
                      images: [
                        MediaImage(
                          url: 'https://www.example.com/path/to/your/thumbnail.jpg',
                        ),
                      ],
                    ),
                  );
                  setState(() {
                    _isCasting = true;
                  });
                } else {
                  ScaffoldMessenger.of(context).showSnackBar(
                    SnackBar(content: Text('No devices found')),
                  );
                }
              },
              child: Text('Start Casting'),
            ),
            SizedBox(height: 20),
            if (_isCasting)
              ElevatedButton(
                onPressed: () async {
                  await _castManager.disconnect();
                  setState(() {
                    _isCasting = false;
                  });
                },
                child: Text('Stop Casting'),
              ),
          ],
        ),
      ),
    );
  }

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

说明

  1. 初始化 VideoCastManager:在 initState 方法中初始化 VideoCastManager 并开始扫描设备。
  2. 监听设备变化:通过监听 deviceManager 的变化来更新 UI。
  3. 扫描设备:使用 scanForDevices 方法扫描可用的投射设备。
  4. 连接到设备:选择设备并使用 connectToDevice 方法连接到该设备。
  5. 加载媒体:使用 loadMedia 方法加载视频 URL 和元数据。
  6. 停止投射:在投射状态下,提供一个按钮来调用 disconnect 方法停止投射。

请确保替换示例中的视频 URL 和缩略图 URL 为实际有效的资源。这个示例代码展示了基本的视频投射流程,包括初始化、扫描设备、连接到设备、加载媒体和停止投射。

希望这对你有所帮助!如果有其他问题,请随时询问。

回到顶部