# screen_mirroring
**Repository Path**: wangjunjx8868/screen_mirroring
## Basic Information
- **Project Name**: screen_mirroring
- **Description**: flutter 投屏插件
- **Primary Language**: Unknown
- **License**: MIT
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 1
- **Created**: 2026-04-13
- **Last Updated**: 2026-06-11
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# flutter_media_cast
一个支持 DLNA 投屏、Android Miracast 连接验证,以及 iOS AirPlay 媒体播放与系统投屏入口的 Flutter 插件,兼容 Android 与 iOS。
## 功能特性
- 在局域网内发现 DLNA 投屏设备(Android & iOS)
- 将视频、音频、图片投屏到 DLNA 设备
- Android 支持 Miracast 设备发现、连接验证和手动断开
- 实时推送投屏状态与播放进度事件
- 播放控制:播放、暂停、停止、跳转
- 音量控制,iOS 端自动同步系统音量
- iOS 支持拉起系统 AirPlay 设备选择器
- iOS 支持 AirPlay 媒体准备、播放、暂停、停止与状态监听
- Android 暂不支持 AirPlay
- 字幕支持(SRT、SSA/ASS、VTT、SMI)
- 根据 URL 后缀自动识别 MIME 类型
## 平台支持
| 功能 | Android | iOS |
|----------------------|---------|-----|
| DLNA 设备发现 | ✅ | ✅ |
| DLNA 投屏 | ✅ | ✅ |
| Miracast 设备发现 | ✅ | ❌ |
| Miracast 连接验证 | ✅ | ❌ |
| AirPlay 系统选择器 | ❌ | ✅ |
| AirPlay 媒体播放 | ❌ | ✅ |
| 音量同步 | ✅ | ✅ |
| 字幕支持 | ✅ | ✅ |
## 安装
在 `pubspec.yaml` 中添加依赖:
```yaml
dependencies:
flutter_media_cast:
git:
url: https://gitee.com/sirli369/screen_mirroring
```
### Android 配置
在 `android/app/src/main/AndroidManifest.xml` 中添加权限:
```xml
```
### iOS 配置
在 `ios/Runner/Info.plist` 中添加以下配置:
```xml
NSLocalNetworkUsageDescription
此应用需要访问本地网络以发现投屏设备
NSBonjourServices
_upnp._tcp.
NSAppTransportSecurity
NSAllowsLocalNetworking
```
## 快速上手
### 初始化
```dart
import 'package:flutter_media_cast/flutter_media_cast.dart';
await FlutterMediaCast.init();
```
### 发现设备
```dart
// 监听发现的设备列表
FlutterMediaCast.deviceStream.listen((List devices) {
print('发现 ${devices.length} 个设备');
});
// 开始搜索(超时后自动停止)
await FlutterMediaCast.startDiscovery(
timeout: const Duration(seconds: 15),
);
// 手动停止搜索
await FlutterMediaCast.stopDiscovery();
```
如需只搜索特定协议,可以传入 `protocols`:
```dart
await FlutterMediaCast.startDiscovery(
protocols: const [CastProtocol.dlna],
timeout: const Duration(seconds: 15),
);
```
### 连接并投屏
```dart
// 连接设备
final CastDevice device = devices.first;
final bool connected = await FlutterMediaCast.connect(device);
if (connected) {
// 开始投屏
final bool success = await FlutterMediaCast.castMedia(
MediaItem(
url: 'http://example.com/video.mp4',
title: '我的视频',
),
);
}
```
### Miracast 连接验证
```dart
final miracastDevices =
devices.where((device) => device.protocol == CastProtocol.miracast);
final connected = await FlutterMediaCast.connect(miracastDevices.first);
if (connected) {
print('Miracast 已连接,请手动控制投屏/镜像');
}
```
说明:
- Miracast 在当前版本中用于设备发现、连接验证和手动断开
- Miracast 不等同于 DLNA,当前版本不承诺媒体 URL 直投
- 若要停止 Miracast 连接,调用 `FlutterMediaCast.disconnect()`
### AirPlay 快速接入
```dart
final media = MediaItem(
url: 'https://example.com/video.mp4',
title: 'AirPlay 测试视频',
);
final prepared = await FlutterMediaCast.prepareAirPlayMedia(media);
if (!prepared) {
print('AirPlay 媒体准备失败');
return;
}
final opened = await FlutterMediaCast.showAirPlayRoutePicker();
if (!opened) {
print('当前平台不支持,或未能拉起 AirPlay 设备选择器');
return;
}
await FlutterMediaCast.playAirPlay();
```
说明:
- AirPlay 当前仅支持 iOS 真机,模拟器通常无法拉起系统路由选择器
- 推荐先调用 `prepareAirPlayMedia()`,再调用 `showAirPlayRoutePicker()`
- 选择外放设备后,可通过 `playAirPlay()` / `pauseAirPlay()` / `stopAirPlay()` 控制播放
### 监听 AirPlay 状态
```dart
FlutterMediaCast.airPlayStateStream.listen((AirPlayState state) {
print('AirPlay 状态: ${state.name}');
});
```
### 投屏带字幕的视频
```dart
await FlutterMediaCast.castMedia(
MediaItem(
url: 'http://example.com/video.mp4',
title: '我的视频',
subtitleUrl: 'http://example.com/subtitle.srt',
),
);
```
### 监听投屏状态
```dart
FlutterMediaCast.castStateStream.listen((CastState state) {
switch (state) {
case CastState.idle: print('空闲');
case CastState.discovering: print('搜索中...');
case CastState.connecting: print('连接中...');
case CastState.connected: print('已连接');
case CastState.casting: print('投屏中');
case CastState.error: print('发生错误');
}
});
```
### 监听播放进度
```dart
FlutterMediaCast.positionStream.listen((MediaPosition pos) {
print('${pos.position}ms / ${pos.duration}ms(${(pos.progress * 100).toStringAsFixed(1)}%)');
});
// 监听播放完成
FlutterMediaCast.playbackCompletedStream.listen((_) {
print('播放完成');
});
```
### 播放控制
```dart
await FlutterMediaCast.play(); // 播放
await FlutterMediaCast.pause(); // 暂停
await FlutterMediaCast.stop(); // 停止
await FlutterMediaCast.seekTo(30000); // 跳转到 30 秒(毫秒)
await FlutterMediaCast.setVolume(0.8); // 设置音量(0.0 ~ 1.0)
```
### 断开连接与释放资源
```dart
await FlutterMediaCast.disconnect();
// 不再使用插件时调用
await FlutterMediaCast.dispose();
```
## API 参考
### FlutterMediaCast
| 方法 / 属性 | 说明 |
|----------------------------------------|-------------------------------------------------|
| `init()` | 初始化插件 |
| `startDiscovery({protocols, timeout})` | 开始搜索投屏设备 |
| `stopDiscovery()` | 停止搜索设备 |
| `deviceStream` | 已发现设备列表的事件流 |
| `castStateStream` | 投屏状态的事件流 |
| `positionStream` | 播放进度的事件流(每秒更新一次) |
| `playbackCompletedStream` | 播放进度达到 99% 时触发的事件流 |
| `connect(device)` | 连接到指定设备,返回 `bool` |
| `disconnect()` | 断开当前连接 |
| `castMedia(media)` | 投屏媒体资源,返回 `bool` |
| `play()` | 恢复播放 |
| `pause()` | 暂停播放 |
| `stop()` | 停止播放 |
| `seekTo(positionMs)` | 跳转到指定位置(毫秒) |
| `setVolume(volume)` | 设置音量(0.0 ~ 1.0) |
| `getConnectedDevice()` | 获取当前连接的设备,未连接时返回 `null` |
| `getCastState()` | 获取当前投屏状态 |
| `getAvailableProtocols()` | 获取支持的协议列表 |
| `showAirPlayRoutePicker()` | 拉起 iOS 系统 AirPlay 设备选择器,Android 返回 `false` |
| `prepareAirPlayMedia(media)` | 为 AirPlay 准备媒体资源,返回 `bool` |
| `airPlayStateStream` | AirPlay 状态事件流 |
| `playAirPlay()` | 开始或恢复 AirPlay 播放 |
| `pauseAirPlay()` | 暂停 AirPlay 播放 |
| `stopAirPlay()` | 停止 AirPlay 播放 |
| `dispose()` | 释放所有资源 |
### CastDevice
| 属性 | 类型 | 说明 |
|----------------|----------------|-----------------------|
| `id` | `String` | 设备唯一标识 |
| `name` | `String` | 设备名称 |
| `protocol` | `CastProtocol` | 投屏协议(`airplay`、`dlna`、`miracast`) |
| `ipAddress` | `String?` | 设备 IP 地址 |
| `port` | `int?` | 设备端口号 |
| `manufacturer` | `String?` | 设备制造商 |
| `model` | `String?` | 设备型号 |
| `location` | `String?` | UPnP 设备描述文件地址 |
### MediaItem
| 属性 | 类型 | 说明 |
|--------------------|-------------|--------------------------------------|
| `url` | `String` | 媒体地址(HTTP/HTTPS) |
| `title` | `String` | 媒体标题 |
| `mediaType` | `MediaType` | 媒体类型:`video`、`audio`、`image` |
| `mimeType` | `String?` | MIME 类型(不填则根据 URL 自动识别) |
| `thumbnailUrl` | `String?` | 缩略图地址 |
| `artist` | `String?` | 艺术家 / 作者 |
| `album` | `String?` | 专辑名称 |
| `subtitleUrl` | `String?` | 字幕文件地址 |
| `subtitleMimeType` | `String?` | 字幕 MIME 类型(不填则自动识别) |
### 枚举类型
```dart
// 投屏协议
enum CastProtocol { airplay, dlna, miracast }
// 投屏状态
enum CastState { idle, discovering, connecting, connected, casting, error }
// AirPlay 状态
enum AirPlayState { idle, preparing, ready, playing, paused, stopped, error }
// 媒体类型
enum MediaType { video, audio, image }
```
## 环境要求
- Flutter `>=3.3.0`
- Dart `^3.7.2`
- Android:minSdkVersion 21+
- iOS:13.0+