Android 7.0 will have a certificate verification error OS Error (handshake.cc:) solution when loading some https resources

I received feedback today that the Flutter library CachedNetworkImage[3.2.3] will cause an error similar to this when loading images from certain https websites in Huawei's early Android version 7.0 system:

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)

This is a certificate issue.

solution:

CachedNetworkImage provides a parameter cacheManager, generally we will not specify it, then it will use DefaultCacheManager. A FileService is used in DefaultCacheManager to download images. Then, we only need to make a CacheManager and customize a FileService to solve this problem. The specific code is as follows:

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);
  }
}

Instructions:

CachedNetworkImage(
    imageUrl: url, 
    fit: BoxFit.cover,
    cacheManager: EsoImageCacheManager()
)

Then run it and the problem is solved.

More recommended way

Similarly, if it is the system's image.network() method, how to solve it?

There is a simple setting plan below, which can be set for the entire project. There is no need to set up a series of network access certificate verification issues such as image.network, dio, cachenetworkimage, etc. one by one, and it is less intrusive to the original project. better

//Create a copy class of HttpOverrids and rewrite the parameter configuration of HttpClient. Here I will pass everything and return true. You can add if for specific projects


class StarkidsHttpOverrides extends HttpOverrides {
  @override
  HttpClient createHttpClient(SecurityContext? context) {
    return super.createHttpClient(context)
      ..badCertificateCallback =
          (X509Certificate cert, String host, int port) => true;
  }
}

use:

// 在main.dart中runApp前面设置global overrids
HttpOverrides.global = StarkidsHttpOverrides();
runApp(const MyApp());

Then it's ok.

Guess you like

Origin blog.csdn.net/BUG_delete/article/details/130597217