测试开源视频播放器在RN webview中的运行方式

核心播放器 没有测试过

npm install react-native-video

该库的设计理念是「提供底层播放能力,上层 UI 完全交给开发者自定义」,因此内置控制器仅作为基础兜底,高级自定义(如滑块图标、分集、弹幕)需要开发者基于其 API 封装。

弹幕扩展(可选,npm可安装)

npm install react-native-barrage 没有测试过

tmd好烦人啊

xgplayer 下载后进过测试发送弹幕的输入框和按钮 显示不出来

Dplayer 弹幕好用 但是无法自定义进度条滑块 笔者测试通过 全屏 横屏 需要手动打开手机的自动旋转设置

Nplayer 不好用

RN使用webView 加载 vsCode 运行的 Dplayer

npm install Dplayer

index.html

html 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
    <title>DPlayer 本地版(node_modules)</title>
    <!-- 引用 node_modules 里的 DPlayer CSS -->
    <link rel="stylesheet" href="./node_modules/dplayer/dist/DPlayer.min.css">
    <style>
        * { margin: 0; padding: 0; box-sizing: border-box; }
        body, html { width: 100%; height: 100%; background: #000; }
        #dplayer { width: 100%; height: 100%; }

        /* 自定义滑块(必生效) */
        .dplayer-bar-thumb { display: none !important; }
        #custom-thumb {
            position: absolute;
            width: 16px;
            height: 16px;
            border-radius: 50%;
            background: #409eff;
            box-shadow: 0 0 4px rgba(64,158,255,0.8);
            z-index: 9999;
            display: none;
            cursor: pointer;
            touch-action: manipulation;
        }
    </style>
</head>
<body>
    <div id="dplayer"></div>
    <div id="custom-thumb"></div>

    <!-- 引用 node_modules 里的 DPlayer JS -->
    <script src="./node_modules/dplayer/dist/DPlayer.min.js"></script>
    <script>
        const dp = new DPlayer({
            container: document.getElementById('dplayer'),
            video: {
                url: 'https://www.w3schools.com/html/mov_bbb.mp4', // 稳定视频源
                inline: true,
                autoplay: false
            },
            danmaku: {
                enable: true,
                pool: [
                    { text: '本地 node_modules 测试', color: '#ff0000', time: 1 },
                    { text: '弹幕输入框正常', color: '#00ff00', time: 3 }
                ],
                speed: 5,
                opacity: 0.8,
                unlimited: true
            },
            volume: 0.7,
            loop: true,
            hotkey: true
        });

        // 自定义滑块逻辑
        const customThumb = document.getElementById('custom-thumb');
        const bar = document.querySelector('.dplayer-bar');
        let barRect = null;

        dp.on('ready', () => {
            customThumb.style.display = 'block';
            barRect = bar.getBoundingClientRect();
            bar.addEventListener('click', updateThumb);
            bar.addEventListener('touchstart', updateThumb);
            bar.addEventListener('touchmove', updateThumb);
            dp.on('timeupdate', updateThumb);
            dp.on('seek', updateThumb);
        });

        window.addEventListener('resize', () => {
            barRect = bar.getBoundingClientRect();
            updateThumb();
        });

        function updateThumb() {
            if (!barRect || !dp.video.duration) return;
            const progress = dp.video.currentTime / dp.video.duration;
            const left = barRect.left + progress * barRect.width - 8 + 'px';
            const top = barRect.top + (barRect.height - 16)/2 + 'px';
            customThumb.style.left = left;
            customThumb.style.top = top;
        }

        // 弹幕发送同步到RN
        dp.on('danmaku_send', (data) => {
            if (window.ReactNativeWebView) {
                window.ReactNativeWebView.postMessage(JSON.stringify({
                    type: 'danmaku_send',
                    data: data
                }));
            }
        });

        // 接收RN控制指令
        window.addEventListener('message', (e) => {
            const msg = JSON.parse(e.data);
            switch(msg.type) {
                case 'play': dp.play(); break;
                case 'pause': dp.pause(); break;
                case 'fullscreen': dp.fullscreen.toggle(); break;
            }
        });
    </script>
</body>
</html>

npm install -g serve

serve -p 3000

RN中页面

html 复制代码
import { StatusBar } from "expo-status-bar";
import React, { useRef } from "react";
import { Alert, StyleSheet, View } from "react-native";
import { SafeAreaView } from "react-native-safe-area-context";
import WebView from "react-native-webview";

// **************************
// 关键:替换成你的本地服务器地址
// 电脑局域网 IP + 端口(比如 http://192.168.31.105:3000)
// **************************
const LOCAL_DPLAYER_URL = "http://192.168.0.102:3000";

// 类型定义
type WebViewMessage = {
  type: "danmaku_send";
  data: { text: string; color?: string; time: number };
};
type PlayerAction = "play" | "pause" | "fullscreen";

const DPlayerScreen = () => {
  const webViewRef = useRef<WebView>(null);

  const onMessage = (event: { nativeEvent: { data: string } }) => {
    try {
      const data = JSON.parse(event.nativeEvent.data) as WebViewMessage;
      if (data.type === "danmaku_send") {
        Alert.alert("弹幕发送成功", `内容:${data.data.text}`);
        console.log("接收到弹幕数据:", data.data);
      }
    } catch (e) {
      console.error("解析弹幕消息失败:", e);
    }
  };

  const controlPlayer = (action: PlayerAction) => {
    if (webViewRef.current) {
      webViewRef.current.postMessage(JSON.stringify({ type: action }));
    }
  };

  return (
    <SafeAreaView style={styles.container}>
      <View style={styles.webViewContainer}>
        <WebView
          ref={webViewRef}
          source={{ uri: LOCAL_DPLAYER_URL }}
          javaScriptEnabled={true}
          domStorageEnabled={true}
          allowsInlineMediaPlayback={true}
          mediaPlaybackRequiresUserAction={false}
          scalesPageToFit={false}
          allowsFullscreenVideo={true}
          androidLayerType="hardware"
          allowFileAccess={true}
          allowUniversalAccessFromFileURLs={true}
          allowFileAccessFromFileURLs={true}
          onMessage={onMessage}
          // 简化:不再依赖 statusCode,直接打印日志
          onLoadEnd={() => {
            console.log("✅ WebView 页面加载完成(忽略状态码)");
          }}
          onLoadStart={() => {
            console.log("🔄 WebView 开始加载页面...");
          }}
          // 兜底:如果确实加载失败,会有其他日志提示
          onError={(syntheticEvent) => {
            const { nativeEvent } = syntheticEvent;
            console.error("❌ WebView 加载失败:", nativeEvent);
            Alert.alert("WebView 错误", "页面加载失败,请检查网络和服务器状态");
          }}
          style={styles.webView}
        />
      </View>
      <StatusBar style="light" backgroundColor="#000" />
    </SafeAreaView>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: "#000",
  },
  webViewContainer: {
    flex: 1,
  },
  webView: {
    flex: 1,
  },
});

export default DPlayerScreen;
相关推荐
anyup_前端梦工厂2 小时前
开源半年,每月 8K+ 下载,uView Pro 让跨端应用开发提效 10 倍
前端·uni-app·开源
天空属于哈夫克32 小时前
OpenClaw 开发者进阶:如何通过 API 实现更稳定的企微自动化?
开源·自动化·企业微信
奔跑吧 android2 小时前
【车载audio】【AudioService 01】【Android 音频子系统分析:按键音(Sound Effects)开启与关闭机制深度解析】
android·音视频·audioflinger·audioservice·audiohal
a1117762 小时前
Face 3D v1.1.4 插件资源
3d·开源
大雷神2 小时前
HarmonyOS APP<玩转React>开源教程二:ArkTS 语言基础
react.js·开源·harmonyos
却道天凉_好个秋2 小时前
WebRTC(十四):Candidate
音视频·webrtc·candidate
冬奇Lab4 小时前
一天一个开源项目(第47篇):Cursor Chat Browser - 浏览和管理 Cursor AI 聊天历史的 Web 应用
人工智能·开源·资讯
IvorySQL7 小时前
PostgreSQL 技术日报 (3月11日)|4库合一性能提升350倍与内核新讨论
数据库·postgresql·开源