You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Flutter的flutter_inappwebview中添加UC浏览器式内嵌视频播放器?

基于flutter_inappwebview实现UC风格内嵌视频播放器

下面是具体的实现步骤,覆盖核心功能点:

1. 配置WebView支持内嵌媒体播放

首先在InAppWebView的初始化配置中开启内嵌播放权限,避免视频跳转到系统播放器:

InAppWebViewGroupOptions(
  crossPlatform: InAppWebViewOptions(
    allowsInlineMediaPlayback: true, // 强制内嵌播放
    mediaPlaybackRequiresUserGesture: false, // 可选:允许自动播放
  ),
  android: AndroidInAppWebViewOptions(
    useHybridComposition: true, // 提升Android端播放性能
    mediaPlaybackRequiresUserGesture: false,
  ),
  ios: IOSInAppWebViewOptions(
    allowsInlineMediaPlayback: true,
  ),
)

2. 监听网页中的视频元素

通过注入JavaScript捕获页面内的<video>元素状态,同步到Flutter端:
在onWebViewCreated回调中添加JS监听和处理逻辑:

// 注册Flutter与JS的通信 handler
controller.addJavaScriptHandler(
  handlerName: 'videoStatus',
  callback: (args) {
    final videoUrl = args[0] as String;
    final isPlaying = args[1] as bool;
    // 这里触发自定义播放器的显示/隐藏逻辑
    if (isPlaying) {
      // 显示自定义内嵌播放器
      showCustomVideoPlayer(context, videoUrl);
    }
  },
);

// 注入监听视频播放的JS代码
controller.evaluateJavascript(source: """
document.addEventListener('DOMContentLoaded', () => {
  document.querySelectorAll('video').forEach(video => {
    video.addEventListener('play', () => {
      window.flutter_inappwebview.callHandler('videoStatus', video.currentSrc, true);
    });
    // 可选:监听暂停事件隐藏播放器
    video.addEventListener('pause', () => {
      window.flutter_inappwebview.callHandler('videoStatus', video.currentSrc, false);
    });
  });
});
""");

3. 实现自定义内嵌/悬浮播放器

用Flutter原生组件或第三方播放器库(如chewie、video_player)打造UC风格的播放器,支持小窗悬浮、拖拽:

// 示例:基于chewie的自定义播放器
class UCVideoPlayer extends StatefulWidget {
  final String videoUrl;
  const UCVideoPlayer({super.key, required this.videoUrl});

  @override
  State<UCVideoPlayer> createState() => _UCVideoPlayerState();
}

class _UCVideoPlayerState extends State<UCVideoPlayer> {
  late VideoPlayerController _videoController;
  late ChewieController _chewieController;

  @override
  void initState() {
    super.initState();
    _videoController = VideoPlayerController.network(widget.videoUrl);
    _chewieController = ChewieController(
      videoPlayerController: _videoController,
      autoPlay: true,
      looping: false,
      customControls: const UCVideoControls(), // 自定义播放控件栏
    );
  }

  @override
  void dispose() {
    _videoController.dispose();
    _chewieController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    // 用Draggable实现悬浮拖拽
    return Draggable(
      feedback: _buildPlayer(),
      childWhenDragging: const SizedBox.shrink(),
      child: _buildPlayer(),
    );
  }

  Widget _buildPlayer() {
    return Container(
      width: 320,
      height: 180,
      decoration: BoxDecoration(borderRadius: BorderRadius.circular(8)),
      child: Chewie(controller: _chewieController),
    );
  }
}

// 自定义控件栏,模拟UC的样式
class UCVideoControls extends StatelessWidget {
  const UCVideoControls({super.key});

  @override
  Widget build(BuildContext context) {
    return Stack(
      children: [
        // 播放/暂停按钮、进度条、全屏按钮等
        // 这里根据需求自定义UI
      ],
    );
  }
}

4. 拦截系统播放器跳转

部分网页会强制唤起系统播放器,需要在shouldOverrideUrlLoading中拦截视频链接:

shouldOverrideUrlLoading: (controller, navigationAction) async {
  final uri = navigationAction.request.url;
  if (uri != null && ['mp4', 'm3u8', 'webm'].any(ext => uri.path.endsWith('.$ext'))) {
    // 拦截视频链接,用自定义播放器打开
    showCustomVideoPlayer(context, uri.toString());
    return NavigationActionPolicy.CANCEL;
  }
  return NavigationActionPolicy.ALLOW;
},

5. 移动端权限与配置

  • Android:在AndroidManifest.xml添加权限
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WAKE_LOCK" /> <!-- 保持屏幕常亮 -->
  • iOS:在Info.plist中允许非HTTPS媒体加载(如果需要)
<key>NSAppTransportSecurity</key>
<dict>
  <key>NSAllowsArbitraryLoads</key>
  <true/>
</dict>

内容的提问来源于stack exchange,提问作者Hamza Kaleem

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 01:06:20