今天收到反馈,Flutter库 CachedNetworkImage[3.2.3] 在华为早期安卓版本7.0系统中加载某些https网站的图像时会出现类似这样的错误:
I/flutter: The following HandshakeException was thrown resolving an image codec: Handshake error in client (OS Error: CERTIFICATE_VERIFY_FAILED: self signed certificate(handshake.cc:352)) 08-05 16:27:56.673 13676-13696/com.example.flutter_module.host I/flutter: When the exception was thrown, this was the stack: 08-05 16:27:56.688 13676-13696/com.example.flutter_module.host I/flutter: #0 NetworkImage._loadAsync (package:flutter/src/painting/image_provider.dart:490:39)
这就是证书问题了。
解决方案:
CachedNetworkImage 提供了一个参数 cacheManager , 一般我们都不会指定,那么它会使用 DefaultCacheManager 。DefaultCacheManager 中会使用一个 FileService 来下载图像。那么,我们只需要做一个 CacheManager ,并自定义一个 FileService 就可以解决此问题了。具体代码如下:
import 'dart:async';
import 'package:flutter_cache_manager/flutter_cache_manager.dart';
import 'package:http/http.dart' as http;
import 'dart:io';
/// 缓存管理
class EsoImageCacheManager extends CacheManager {
static const key = 'libEsoCachedImageData';
static EsoImageCacheManager? _instance;
factory EsoImageCacheManager() {
_instance ??= EsoImageCacheManager._();
return _instance!;
}
EsoImageCacheManager._()
: super(Config(key, fileService: EsoHttpFileService()));
}
class EsoHttpFileService extends FileService {
late HttpClient _httpClient;
EsoHttpFileService({HttpClient? httpClient}) {
_httpClient = httpClient ?? HttpClient();
//证书校验失败问题
_httpClient.badCertificateCallback = (cert, host, port) => true;
}
@override
Future<FileServiceResponse> get(String url,
{Map<String, String>? headers}) async {
final Uri resolved = Uri.base.resolve(url);
final HttpClientRequest req = await _httpClient.getUrl(resolved);
headers?.forEach((key, value) {
req.headers.add(key, value);
});
final HttpClientResponse httpResponse = await req.close();
final http.StreamedResponse response = http.StreamedResponse(
httpResponse.timeout(const Duration(seconds: 20)),
httpResponse.statusCode,
contentLength: httpResponse.contentLength,
reasonPhrase: httpResponse.reasonPhrase,
isRedirect: httpResponse.isRedirect,
);
return HttpGetResponse(response);
}
}
使用方法:
CachedNetworkImage(
imageUrl: url,
fit: BoxFit.cover,
cacheManager: EsoImageCacheManager()
)
然后运行,问题解决。
更推荐方式
同样如果是系统的image.network()方法,怎么解决呢?
下面有一个简单的设置方案,可以全工程设置,不用单独去一个一个设置image.network、dio、cachenetworkimage等一系列网络访问证书校验问题,而且对原有项目的侵入性较少。更好一些
//创建一个HttpOverrids的复写类,重写HttpClient的参数配置,这里我就全部通过,返回true。具体项目可以自行添加if
class StarkidsHttpOverrides extends HttpOverrides {
@override
HttpClient createHttpClient(SecurityContext? context) {
return super.createHttpClient(context)
..badCertificateCallback =
(X509Certificate cert, String host, int port) => true;
}
}
使用:
// 在main.dart中runApp前面设置global overrids
HttpOverrides.global = StarkidsHttpOverrides();
runApp(const MyApp());
然后就可以了。