npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

expo-dlna-player

v0.7.0

Published

A React Native/Expo module for DLNA/AirPlay media casting to smart TVs and streaming devices

Downloads

50

Readme

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功能,需要注意以下几点:

  1. 使用AirPlayButton组件(推荐方式): 由于iOS的限制,不能通过代码直接触发AirPlay选择器。必须使用AirPlayButton组件在UI中提供一个用户可以点击的元素:

    import { AirPlayButton } from 'expo-dlna-player';
       
    // 在您的渲染函数中
    return (
      <View>
        {/* 其他UI元素 */}
        <AirPlayButton style={styles.airplayButton} />
      </View>
    );

    用户点击此按钮时,iOS将显示系统AirPlay设备选择器。这是苹果推荐的方式,符合iOS的设计规范。

  2. 使用发现和连接API(适用于DLNA和其他设备)

    // 通过设备发现和连接API
    await startDiscovery();
    // 获取设备列表并在UI中展示
    const devices = await getDevices();
    // 用户选择设备后...
    await connectToDevice(deviceId);

虽然showAirPlayPicker()方法在API中存在,但由于iOS的限制,它在大多数情况下无法按预期工作。请始终使用AirPlayButton组件提供用户交互界面。

AirPlay使用方式

对于iOS设备上的AirPlay功能,您必须使用AirPlayButton组件:

  1. 使用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目录获取完整的示例应用。

贡献

欢迎贡献!请参考贡献指南中描述的准则。