import 'dart:io'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_inappwebview/flutter_inappwebview.dart'; import 'package:maibu_satabot_v2/core/domain/entities/user_entity.dart'; import 'package:maibu_satabot_v2/features/devices/domain/entities/device_entity.dart'; class MyVideoPlayer extends StatefulWidget { final String deviceIp; final DeviceEntity device; final UserEntity user; const MyVideoPlayer({ Key? key, required this.deviceIp, required this.device, required this.user, }) : super(key: key); @override State createState() => _MyVideoPlayerState(); } class _MyVideoPlayerState extends State { InAppLocalhostServer? _localServer; InAppWebViewController? _webViewController; bool _isServerRunning = false; int? actualPort; @override void initState() { super.initState(); _startServer(); } Future _startServer() async { int availablePort = 0; try { var socket = await ServerSocket.bind(InternetAddress.loopbackIPv4, 0); availablePort = socket.port; await socket.close(); } catch (e) { availablePort = 8080; } _localServer = InAppLocalhostServer(port: availablePort); await _localServer!.start(); actualPort = availablePort; if (mounted) { setState(() { _isServerRunning = true; }); } } @override void dispose() { _localServer?.close(); super.dispose(); } @override Widget build(BuildContext context) { // 防止父级因其他状态 setState 导致视频闪烁 if (!_isServerRunning) { return const Center(child: CircularProgressIndicator(color: Colors.white)); } // [性能关键] RepaintBoundary 必须包裹渲染密集型的 WebView return RepaintBoundary( child: InAppWebView( initialUrlRequest: URLRequest( url: WebUri("http://localhost:$actualPort/assets/www/webrtc/playwebrtc.html"), ), initialSettings: InAppWebViewSettings( javaScriptEnabled: true, mediaPlaybackRequiresUserGesture: false, allowsInlineMediaPlayback: true, preferredContentMode: UserPreferredContentMode.MOBILE, // 优化性能:禁用滚动,开启硬件加速 supportZoom: false, disableHorizontalScroll: true, disableVerticalScroll: true, hardwareAcceleration: true, ), onWebViewCreated: (controller) => _webViewController = controller, onPermissionRequest: (controller, request) async { return PermissionResponse( resources: request.resources, action: PermissionResponseAction.GRANT, ); }, onLoadStop: (controller, url) { _initWebRTC(widget.deviceIp, widget.device.deviceName, widget.user.token); }, ), ); } void _initWebRTC(String deviceIp, String deviceId, String token) { final streamUrl = "webrtc://$deviceIp/live/livestream/$deviceId?token=$token"; _webViewController?.evaluateJavascript(source: "setStreamUrl('$streamUrl')"); } }