expo-dlna-player
一个用于React Native和Expo应用的DLNA/AirPlay/Miracast投屏播放组件,支持发现和连接媒体设备进行多媒体投屏播放。
功能特点
- 支持DLNA、AirPlay和Miracast设备的发现和连接
- 多媒体投屏播放(视频/音频/图片)
- 全面的播放控制(播放、暂停、恢复、停止、进度控制)
- 高级媒体控制(播放速率调整、静音、缓冲状态监控)
- 音量控制和状态监控
- 专为iOS优化的AirPlay原生体验
- Android平台的Miracast屏幕镜像支持
- 完整的事件系统,实时反馈设备和播放状态
- 跨平台支持(iOS和Android)
API文档
安装(Expo托管项目)
对于托管Expo项目,请按照最新稳定版本的API文档中的安装说明进行操作。如果您点击链接但没有可用的文档,那么此库尚不能在托管项目中使用 — 它可能会在即将发布的Expo SDK版本中包含。
安装(裸React Native项目)
对于裸React Native项目,您必须确保已经安装并配置了expo
包。
添加依赖包
npm install expo-dlna-player
# 或者
yarn add expo-dlna-player
Android配置
在android/app/src/main/AndroidManifest.xml
中添加以下权限:
<!-- DLNA/UPnP相关权限 -->
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE" />
<!-- Miracast相关权限(如需使用) -->
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
iOS配置
运行npx pod-install
安装原生依赖。
在Info.plist
中添加以下服务描述:
<key>NSLocalNetworkUsageDescription</key>
<string>需要使用本地网络来发现并连接到DLNA/AirPlay设备</string>
<key>NSBonjourServices</key>
<array>
<string>_airplay._tcp</string>
<string>_raop._tcp</string>
</array>
基本用法
import ExpoDlnaPlayer, {
DeviceInfo,
PlaybackStatus,
startDiscovery,
connectToDevice,
play,
pause,
resume,
stop,
seek,
setVolume,
setPlaybackRate,
setMuted,
getBufferingStatus
} from 'expo-dlna-player';
import { useState, useEffect } from 'react';
function App() {
const [devices, setDevices] = useState([]);
const [playbackStatus, setPlaybackStatus] = useState(null);
// 开始搜索设备
const startDeviceDiscovery = async () => {
try {
// 可以直接使用模块方法
await ExpoDlnaPlayer.startDiscovery();
// 或使用辅助函数
// await startDiscovery();
} catch (error) {
console.error("搜索设备失败:", error);
}
};
// 设备发现事件监听
useEffect(() => {
// 注册设备发现监听器
const deviceFoundSubscription = ExpoDlnaPlayer.addListener('onDeviceFound', (device) => {
console.log('发现设备:', device.name, device.type);
setDevices(prev => [...prev.filter(d => d.id !== device.id), device]);
});
// 注册播放状态监听器
const playbackSubscription = ExpoDlnaPlayer.addListener('onPlaybackStatusChanged', (status) => {
setPlaybackStatus(status);
});
// 开始搜索
startDeviceDiscovery();
// 清理
return () => {
deviceFoundSubscription.remove();
playbackSubscription.remove();
ExpoDlnaPlayer.stopDiscovery();
};
}, []);
// 连接设备并播放媒体
const playMedia = async (deviceId) => {
try {
// 连接到设备
const connected = await connectToDevice(deviceId);
if (connected) {
// 播放媒体
await play(
"https://example.com/video.mp4",
"测试视频",
"video/mp4"
);
// 两秒后调整播放速率
setTimeout(async () => {
await setPlaybackRate(1.5);
console.log('播放速率已设置为1.5倍');
}, 2000);
}
} catch (error) {
console.error("播放失败:", error);
}
};
// 播放控制示例
const controlPlayback = async () => {
if (!playbackStatus) return;
if (playbackStatus.isPlaying) {
await pause();
} else {
await resume();
}
};
// 跳转到30秒位置
const seekToPosition = async () => {
await seek(30);
};
return (
// 渲染UI...
);
}
API参考
设备发现
startDiscovery()
- 开始搜索媒体设备stopDiscovery()
- 停止搜索getDevices()
- 获取已发现的设备列表
连接与控制
connectToDevice(deviceId)
- 连接到指定设备disconnectFromDevice()
- 断开当前连接isConnected()
- 检查是否已连接getConnectedDevice()
- 获取当前连接的设备
基本媒体控制
play(url, title, mimeType)
- 播放媒体pause()
- 暂停播放resume()
- 恢复播放stop()
- 停止播放seek(position)
- 定位到指定位置(单位:秒)setVolume(volume)
- 设置音量(范围:0-100)getPlaybackStatus()
- 获取当前播放状态
高级媒体控制
setPlaybackRate(rate)
- 设置播放速率(范围:0.5-2.0)setMuted(muted)
- 设置静音状态getBufferingStatus()
- 获取媒体缓冲状态
Android特定功能 (Miracast)
startProjection(deviceId, mode)
- 开始投屏(模式:"SCREEN_MIRRORING"或"VIDEO_ONLY")stopProjection()
- 停止投屏isProjectionSupported()
- 检查设备是否支持投屏
事件
可以通过ExpoDlnaPlayer.addListener
方法订阅以下事件:
事件名 | 描述 | 参数 |
---|---|---|
onDeviceFound |
发现新设备 | DeviceInfo |
onDeviceDisappeared |
设备离线 | deviceId: string |
onConnectionChanged |
连接状态变化 | { deviceId: string, connected: boolean } |
onPlaybackStatusChanged |
播放状态更新 | PlaybackStatus |
onError |
发生错误 | { code: string, message: string, deviceId?: string } |
onPermissionStatus |
权限状态变更 | { permission: string, status: string } |
PlaybackStatus 对象
播放状态对象包含以下属性:
{
isPlaying: boolean; // 是否正在播放
duration: number; // 总时长(秒)
position: number; // 当前位置(秒)
volume: number; // 音量(0-100)
rate?: number; // 播放速率
isMuted?: boolean; // 是否静音
isBuffering?: boolean; // 是否正在缓冲
isCompleted?: boolean; // 是否播放完成
error?: string; // 错误信息
}
使用提示
AirPlay使用方式
对于iOS设备上的AirPlay功能,需要注意以下几点:
使用AirPlayButton组件(推荐方式): 由于iOS的限制,不能通过代码直接触发AirPlay选择器。必须使用AirPlayButton组件在UI中提供一个用户可以点击的元素:
import { AirPlayButton } from 'expo-dlna-player'; // 在您的渲染函数中 return ( <View> {/* 其他UI元素 */} <AirPlayButton style={styles.airplayButton} /> </View> );
用户点击此按钮时,iOS将显示系统AirPlay设备选择器。这是苹果推荐的方式,符合iOS的设计规范。
使用发现和连接API(适用于DLNA和其他设备):
// 通过设备发现和连接API await startDiscovery(); // 获取设备列表并在UI中展示 const devices = await getDevices(); // 用户选择设备后... await connectToDevice(deviceId);
虽然showAirPlayPicker()
方法在API中存在,但由于iOS的限制,它在大多数情况下无法按预期工作。请始终使用AirPlayButton组件提供用户交互界面。
AirPlay使用方式
对于iOS设备上的AirPlay功能,您必须使用AirPlayButton组件:
使用AirPlayButton组件: 为了符合Apple的应用商店指南,必须使用AirPlayButton组件在UI中提供用户可点击的元素:
import { AirPlayButton } from 'expo-dlna-player'; // 在您的渲染函数中 return ( <View> {/* 其他UI元素 */} <AirPlayButton style={styles.airplayButton} /> </View> );
用户点击此按钮时,iOS将显示系统AirPlay设备选择器。这是苹果唯一允许的方式,完全符合iOS的设计规范。
DLNA设备最佳实践
DLNA设备需要确保拥有有效的控制URL:
// 确保DLNA设备有控制URL
const devices = await getDevices();
const dlnaDevices = devices.filter(d =>
d.type === 'dlna' && d.controlURL
);
完整示例
查看example目录获取完整的示例应用。
贡献
欢迎贡献!请参考贡献指南中描述的准则。