Flutter中带特殊字符的HLS视频无法在iOS Safari播放
解决Flutter better_player iOS端因特殊字符播放失败的问题
以下是几个无需修改AWS上所有URL的Flutter端解决方案:
1. 拦截并修改m3u8内容
核心思路是先获取原始m3u8文件内容,正则匹配其中的.ts片段链接,对包含特殊字符的链接进行URI编码后,再将修改后的内容作为数据源传入better_player。
示例代码:
import 'dart:convert'; import 'package:http/http.dart' as http; import 'package:better_player/better_player.dart'; Future<BetterPlayerDataSource> getEncodedM3u8DataSource(String originalUrl) async { final response = await http.get(Uri.parse(originalUrl)); if (response.statusCode != 200) { throw Exception('Failed to load m3u8'); } String modifiedM3u8Content = response.body; final baseUri = Uri.parse(originalUrl); // 匹配所有.ts链接(支持绝对路径和相对路径) modifiedM3u8Content = modifiedM3u8Content.replaceAllMapped( RegExp(r'(https?://[^\s#]+?\.ts|/[^\s#]+?\.ts)'), (match) { final tsUrl = match.group(0)!; Uri tsUri; if (tsUrl.startsWith('http')) { tsUri = Uri.parse(tsUrl); } else { tsUri = baseUri.resolve(tsUrl); } // 对URL进行全编码(保留路径分隔符,仅编码特殊字符) final encodedTsUrl = Uri.encodeFull(tsUri.toString()); // 如果是相对路径,转回相对格式(可选,也可以直接用绝对路径) return tsUrl.startsWith('http') ? encodedTsUrl : encodedTsUrl.replaceFirst(baseUri.origin, ''); }, ); return BetterPlayerDataSource( BetterPlayerDataSourceType.memory, modifiedM3u8Content, headers: response.headers, ); } // 使用方式 final dataSource = await getEncodedM3u8DataSource('你的原m3u8 URL'); final controller = BetterPlayerController( BetterPlayerConfiguration(), betterPlayerDataSource: dataSource, );
2. 自定义HttpClient拦截请求
如果better_player版本支持自定义HttpClient,可以通过替换默认客户端,在请求.ts片段时自动编码URL路径。
示例代码:
import 'dart:io'; import 'package:better_player/better_player.dart'; final customHttpClient = HttpClient() ..open = (String method, String host, int port, String path) { // 编码路径中的特殊字符 final encodedPath = Uri.encodeFull(path); return super.open(method, host, port, encodedPath); }; // 配置better_player使用自定义客户端 final playerConfig = BetterPlayerConfiguration( httpClient: customHttpClient, ); final dataSource = BetterPlayerDataSource( BetterPlayerDataSourceType.network, '你的原m3u8 URL', ); final controller = BetterPlayerController( playerConfig, betterPlayerDataSource: dataSource, );
注意:部分旧版本better_player可能没有
httpClient配置项,需确认版本兼容性。
3. 本地HTTP代理转发请求
启动一个轻量本地HTTP服务器,将所有视频请求通过代理转发,代理层负责对URL进行编码处理。可以使用package:http_server实现:
示例代码(简化版):
import 'package:http_server/http_server.dart'; import 'package:http/http.dart' as http; void startLocalProxy() async { final server = await HttpServer.bind('localhost', 8080); await for (final request in server) { // 提取原URL(假设请求路径包含目标URL,或通过参数传递) final targetUrl = request.requestedUri.queryParameters['url']!; // 编码目标URL final encodedUrl = Uri.encodeFull(targetUrl); // 转发请求 final response = await http.get(Uri.parse(encodedUrl)); // 返回响应给播放器 request.response ..statusCode = response.statusCode ..headers.addAll(response.headers) ..write(response.body) ..close(); } } // 使用时将m3u8 URL替换为本地代理地址,例如: // http://localhost:8080/?url=你的原m3u8 URL
内容的提问来源于stack exchange,提问作者Tiagocf2
相关产品推荐
相关产品推荐

