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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 15:40:38