From ceb058658fb22f6189c96074f4ac62ae1d37f007 Mon Sep 17 00:00:00 2001 From: Mohammad Salameh Date: Thu, 8 Jan 2026 16:34:25 +0300 Subject: [PATCH] fix(native_dio_adapter): gracefully fall back when Cronet unavailable Fixes #2444 When Google Play Services is unavailable, CronetEngine initialization throws a JniException. This change catches the exception and falls back to the standard HttpClientAdapter using dart:io. Also adds an optional onCronetUnavailable callback for developers who want to be notified when the fallback occurs. --- plugins/native_dio_adapter/CHANGELOG.md | 2 ++ .../lib/src/native_adapter.dart | 18 +++++++++++++++--- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/plugins/native_dio_adapter/CHANGELOG.md b/plugins/native_dio_adapter/CHANGELOG.md index 6a2fd8e5a..7ac26c578 100644 --- a/plugins/native_dio_adapter/CHANGELOG.md +++ b/plugins/native_dio_adapter/CHANGELOG.md @@ -4,6 +4,8 @@ - Support request cancellation for native HTTP clients via use of `AbortableRequest` (introduced in http package from version 1.5.0) - Add timeout handling for `sendTimeout`, `connectTimeout`, and `receiveTimeout` in `ConversionLayerAdapter` +- Gracefully fall back to `HttpClientAdapter` when Cronet is unavailable on Android (e.g., devices without Google Play Services) +- Add `onCronetUnavailable` callback to `NativeAdapter` for notification when fallback occurs ## 1.5.0 diff --git a/plugins/native_dio_adapter/lib/src/native_adapter.dart b/plugins/native_dio_adapter/lib/src/native_adapter.dart index 3ff8527f1..3649f6ae4 100644 --- a/plugins/native_dio_adapter/lib/src/native_adapter.dart +++ b/plugins/native_dio_adapter/lib/src/native_adapter.dart @@ -16,6 +16,9 @@ import 'cupertino_adapter.dart'; /// /// On Android this uses [cronet_http](https://pub.dev/packages/cronet_http) to /// make HTTP requests. +/// +/// If Cronet is unavailable (e.g., Google Play Services not installed), +/// falls back to the default [HttpClientAdapter] using dart:io. class NativeAdapter implements HttpClientAdapter { NativeAdapter({ CronetEngine Function()? createCronetEngine, @@ -32,11 +35,20 @@ class NativeAdapter implements HttpClientAdapter { 'This will be removed in v2.0.0', ) URLSessionConfiguration? cupertinoConfiguration, + void Function(Object error)? onCronetUnavailable, }) { if (Platform.isAndroid) { - _adapter = CronetAdapter( - createCronetEngine?.call() ?? androidCronetEngine, - ); + try { + _adapter = CronetAdapter( + createCronetEngine?.call() ?? androidCronetEngine, + ); + } catch (e) { + // Cronet requires Google Play Services. Fall back to dart:io + // HttpClient when unavailable (e.g., on emulators without Google APIs + // or devices without Google Play Services). + onCronetUnavailable?.call(e); + _adapter = HttpClientAdapter(); + } } else if (Platform.isIOS || Platform.isMacOS) { _adapter = CupertinoAdapter( createCupertinoConfiguration?.call() ??