|
|
|
@ -1,10 +1,6 @@ |
|
|
|
import 'package:dio/dio.dart'; |
|
|
|
import 'package:dio/io.dart'; |
|
|
|
import 'package:flutter_dotenv/flutter_dotenv.dart'; |
|
|
|
import 'package:get/get.dart' hide Response; |
|
|
|
import 'package:flutter/foundation.dart'; |
|
|
|
import 'dart:io'; |
|
|
|
import 'package:path/path.dart' as p; |
|
|
|
|
|
|
|
import 'auth_interceptor.dart'; |
|
|
|
import 'nw_method.dart'; |
|
|
|
@ -58,100 +54,4 @@ class DioManager { |
|
|
|
); |
|
|
|
return response.data; |
|
|
|
} |
|
|
|
|
|
|
|
/// 下载二进制字节(支持可选忽略证书,仅限移动/桌面端) |
|
|
|
Future<List<int>> downloadBytes(String url, {bool allowInsecure = false}) async { |
|
|
|
// 使用独立 Dio,避免全局适配器被修改 |
|
|
|
final client = Dio(BaseOptions( |
|
|
|
responseType: ResponseType.bytes, |
|
|
|
followRedirects: true, |
|
|
|
receiveTimeout: const Duration(seconds: 60), |
|
|
|
connectTimeout: const Duration(seconds: 60), |
|
|
|
)); |
|
|
|
client.interceptors.add(AuthInterceptor()); |
|
|
|
|
|
|
|
// 仅在非Web端尝试忽略证书 |
|
|
|
if (allowInsecure && !kIsWeb) { |
|
|
|
client.httpClientAdapter = IOHttpClientAdapter(createHttpClient: () { |
|
|
|
// ignore: unnecessary_new |
|
|
|
final ioClient = new HttpClient(); |
|
|
|
ioClient.badCertificateCallback = (cert, host, port) => true; |
|
|
|
return ioClient; |
|
|
|
}); |
|
|
|
} |
|
|
|
|
|
|
|
final resp = await client.get(url); |
|
|
|
final status = resp.statusCode ?? 0; |
|
|
|
if (status >= 200 && status < 300) { |
|
|
|
// Dio v5 将 bytes 直接作为 List<int> 返回 |
|
|
|
final data = resp.data; |
|
|
|
if (data is List<int>) return data; |
|
|
|
// 某些平台可能返回 Uint8List |
|
|
|
if (data is List) { |
|
|
|
return List<int>.from(data); |
|
|
|
} |
|
|
|
throw Exception('下载返回格式异常'); |
|
|
|
} |
|
|
|
throw Exception('下载失败($status)'); |
|
|
|
} |
|
|
|
|
|
|
|
/// 按 .env 配置决定是否允许忽略证书 |
|
|
|
Future<List<int>> downloadBytesWithEnv(String url) async { |
|
|
|
final allow = (dotenv.env['ALLOW_INSECURE_SSL'] ?? 'false').toLowerCase() == 'true'; |
|
|
|
return downloadBytes(url, allowInsecure: allow); |
|
|
|
} |
|
|
|
|
|
|
|
/// 使用 Dio 的 download API 下载到临时文件并读出字节 |
|
|
|
Future<List<int>> downloadBytesUsingDownload(String url, {bool allowInsecure = false}) async { |
|
|
|
final client = Dio(BaseOptions( |
|
|
|
followRedirects: true, |
|
|
|
receiveTimeout: const Duration(seconds: 120), |
|
|
|
connectTimeout: const Duration(seconds: 60), |
|
|
|
)); |
|
|
|
client.interceptors.add(AuthInterceptor()); |
|
|
|
|
|
|
|
if (allowInsecure && !kIsWeb) { |
|
|
|
client.httpClientAdapter = IOHttpClientAdapter(createHttpClient: () { |
|
|
|
final ioClient = HttpClient(); |
|
|
|
ioClient.badCertificateCallback = (cert, host, port) => true; |
|
|
|
return ioClient; |
|
|
|
}); |
|
|
|
} |
|
|
|
|
|
|
|
final tmpDir = await Directory.systemTemp.createTemp('voice_pkg_'); |
|
|
|
final baseName = _fileNameFromUrl(url); |
|
|
|
final savePath = p.join(tmpDir.path, baseName); |
|
|
|
|
|
|
|
await client.download( |
|
|
|
url, |
|
|
|
savePath, |
|
|
|
options: Options(responseType: ResponseType.bytes), |
|
|
|
); |
|
|
|
|
|
|
|
final file = File(savePath); |
|
|
|
final bytes = await file.readAsBytes(); |
|
|
|
// 清理临时文件 |
|
|
|
try { |
|
|
|
await file.delete(); |
|
|
|
await tmpDir.delete(recursive: true); |
|
|
|
} catch (_) {} |
|
|
|
return bytes; |
|
|
|
} |
|
|
|
|
|
|
|
/// 读取 .env 决定是否忽略证书,使用 download API |
|
|
|
Future<List<int>> downloadBytesUsingDownloadWithEnv(String url) async { |
|
|
|
final allow = (dotenv.env['ALLOW_INSECURE_SSL'] ?? 'false').toLowerCase() == 'true'; |
|
|
|
return downloadBytesUsingDownload(url, allowInsecure: allow); |
|
|
|
} |
|
|
|
|
|
|
|
String _fileNameFromUrl(String url) { |
|
|
|
try { |
|
|
|
final clean = url.split('?').first; |
|
|
|
final last = clean.split('/').last; |
|
|
|
if (last.isEmpty) return 'voice.pkg'; |
|
|
|
return last; |
|
|
|
} catch (_) { |
|
|
|
return 'voice.pkg'; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|