diff --git a/packages/connectivity_plus/connectivity_plus/android/src/main/java/dev/fluttercommunity/plus/connectivity/Connectivity.java b/packages/connectivity_plus/connectivity_plus/android/src/main/java/dev/fluttercommunity/plus/connectivity/Connectivity.java index d5e5cbbde2..7a2a34bd80 100644 --- a/packages/connectivity_plus/connectivity_plus/android/src/main/java/dev/fluttercommunity/plus/connectivity/Connectivity.java +++ b/packages/connectivity_plus/connectivity_plus/android/src/main/java/dev/fluttercommunity/plus/connectivity/Connectivity.java @@ -21,6 +21,7 @@ public class Connectivity { static final String CONNECTIVITY_ETHERNET = "ethernet"; static final String CONNECTIVITY_BLUETOOTH = "bluetooth"; static final String CONNECTIVITY_VPN = "vpn"; + static final String CONNECTIVITY_SATELLITE = "satellite"; static final String CONNECTIVITY_OTHER = "other"; private final ConnectivityManager connectivityManager; @@ -70,6 +71,10 @@ List getCapabilitiesList(NetworkCapabilities capabilities) { if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_BLUETOOTH)) { types.add(CONNECTIVITY_BLUETOOTH); } + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE + && capabilities.hasTransport(NetworkCapabilities.TRANSPORT_SATELLITE)) { + types.add(CONNECTIVITY_SATELLITE); + } if (types.isEmpty() && capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)) { types.add(CONNECTIVITY_OTHER); diff --git a/packages/connectivity_plus/connectivity_plus/ios/connectivity_plus/Sources/connectivity_plus/ConnectivityPlusPlugin.swift b/packages/connectivity_plus/connectivity_plus/ios/connectivity_plus/Sources/connectivity_plus/ConnectivityPlusPlugin.swift index b5d1211508..83fd7e59e0 100644 --- a/packages/connectivity_plus/connectivity_plus/ios/connectivity_plus/Sources/connectivity_plus/ConnectivityPlusPlugin.swift +++ b/packages/connectivity_plus/connectivity_plus/ios/connectivity_plus/Sources/connectivity_plus/ConnectivityPlusPlugin.swift @@ -54,6 +54,8 @@ public class ConnectivityPlusPlugin: NSObject, FlutterPlugin, FlutterStreamHandl return "mobile" case .wiredEthernet: return "ethernet" + case .constrained: + return "satellite" case .other: return "other" case .none: diff --git a/packages/connectivity_plus/connectivity_plus/ios/connectivity_plus/Sources/connectivity_plus/ConnectivityProvider.swift b/packages/connectivity_plus/connectivity_plus/ios/connectivity_plus/Sources/connectivity_plus/ConnectivityProvider.swift index ad2cbc1e16..ff553037a1 100644 --- a/packages/connectivity_plus/connectivity_plus/ios/connectivity_plus/Sources/connectivity_plus/ConnectivityProvider.swift +++ b/packages/connectivity_plus/connectivity_plus/ios/connectivity_plus/Sources/connectivity_plus/ConnectivityProvider.swift @@ -5,6 +5,7 @@ public enum ConnectivityType { case wiredEthernet case wifi case cellular + case constrained case other } diff --git a/packages/connectivity_plus/connectivity_plus/ios/connectivity_plus/Sources/connectivity_plus/PathMonitorConnectivityProvider.swift b/packages/connectivity_plus/connectivity_plus/ios/connectivity_plus/Sources/connectivity_plus/PathMonitorConnectivityProvider.swift index d7a8252b04..3ec78c08c0 100644 --- a/packages/connectivity_plus/connectivity_plus/ios/connectivity_plus/Sources/connectivity_plus/PathMonitorConnectivityProvider.swift +++ b/packages/connectivity_plus/connectivity_plus/ios/connectivity_plus/Sources/connectivity_plus/PathMonitorConnectivityProvider.swift @@ -26,6 +26,9 @@ public class PathMonitorConnectivityProvider: NSObject, ConnectivityProvider { if path.usesInterfaceType(.other) { types.append(.other) } + if path.isConstrained { + types.append(.constrained) + } } return types.isEmpty ? [.none] : types diff --git a/packages/connectivity_plus/connectivity_plus/macos/connectivity_plus/Sources/connectivity_plus/ConnectivityPlusPlugin.swift b/packages/connectivity_plus/connectivity_plus/macos/connectivity_plus/Sources/connectivity_plus/ConnectivityPlusPlugin.swift index 536f47ba3c..26b7c209d6 100644 --- a/packages/connectivity_plus/connectivity_plus/macos/connectivity_plus/Sources/connectivity_plus/ConnectivityPlusPlugin.swift +++ b/packages/connectivity_plus/connectivity_plus/macos/connectivity_plus/Sources/connectivity_plus/ConnectivityPlusPlugin.swift @@ -55,6 +55,8 @@ public class ConnectivityPlusPlugin: NSObject, FlutterPlugin, FlutterStreamHandl return "mobile" case .wiredEthernet: return "ethernet" + case .constrained: + return "satellite" case .other: return "other" case .none: diff --git a/packages/connectivity_plus/connectivity_plus/macos/connectivity_plus/Sources/connectivity_plus/ConnectivityProvider.swift b/packages/connectivity_plus/connectivity_plus/macos/connectivity_plus/Sources/connectivity_plus/ConnectivityProvider.swift index ad2cbc1e16..ff553037a1 100644 --- a/packages/connectivity_plus/connectivity_plus/macos/connectivity_plus/Sources/connectivity_plus/ConnectivityProvider.swift +++ b/packages/connectivity_plus/connectivity_plus/macos/connectivity_plus/Sources/connectivity_plus/ConnectivityProvider.swift @@ -5,6 +5,7 @@ public enum ConnectivityType { case wiredEthernet case wifi case cellular + case constrained case other } diff --git a/packages/connectivity_plus/connectivity_plus/macos/connectivity_plus/Sources/connectivity_plus/PathMonitorConnectivityProvider.swift b/packages/connectivity_plus/connectivity_plus/macos/connectivity_plus/Sources/connectivity_plus/PathMonitorConnectivityProvider.swift index d7a8252b04..3ec78c08c0 100644 --- a/packages/connectivity_plus/connectivity_plus/macos/connectivity_plus/Sources/connectivity_plus/PathMonitorConnectivityProvider.swift +++ b/packages/connectivity_plus/connectivity_plus/macos/connectivity_plus/Sources/connectivity_plus/PathMonitorConnectivityProvider.swift @@ -26,6 +26,9 @@ public class PathMonitorConnectivityProvider: NSObject, ConnectivityProvider { if path.usesInterfaceType(.other) { types.append(.other) } + if path.isConstrained { + types.append(.constrained) + } } return types.isEmpty ? [.none] : types diff --git a/packages/connectivity_plus/connectivity_plus/test/connectivity_test.dart b/packages/connectivity_plus/connectivity_plus/test/connectivity_test.dart index 4f177c0f31..02e30c6049 100644 --- a/packages/connectivity_plus/connectivity_plus/test/connectivity_test.dart +++ b/packages/connectivity_plus/connectivity_plus/test/connectivity_test.dart @@ -12,6 +12,11 @@ const List kCheckConnectivityResult = [ ConnectivityResult.wifi ]; +const List kCheckConnectivitySatelliteResult = [ + ConnectivityResult.mobile, + ConnectivityResult.satellite, +]; + void main() { group('Connectivity', () { late Connectivity connectivity; @@ -26,6 +31,17 @@ void main() { final result = await connectivity.checkConnectivity(); expect(result, kCheckConnectivityResult); }); + + test('checkConnectivity passes through satellite', () async { + final satellitePlatform = MockSatelliteConnectivityPlatform(); + ConnectivityPlatform.instance = satellitePlatform; + connectivity = Connectivity(); + final result = await connectivity.checkConnectivity(); + expect( + result, + containsAll(kCheckConnectivitySatelliteResult), + ); + }); }); } @@ -37,3 +53,12 @@ class MockConnectivityPlatform extends Mock return kCheckConnectivityResult; } } + +class MockSatelliteConnectivityPlatform extends Mock + with MockPlatformInterfaceMixin + implements ConnectivityPlatform { + @override + Future> checkConnectivity() async { + return kCheckConnectivitySatelliteResult; + } +} diff --git a/packages/connectivity_plus/connectivity_plus_platform_interface/lib/src/enums.dart b/packages/connectivity_plus/connectivity_plus_platform_interface/lib/src/enums.dart index 7f586995ab..7e2c92c073 100644 --- a/packages/connectivity_plus/connectivity_plus_platform_interface/lib/src/enums.dart +++ b/packages/connectivity_plus/connectivity_plus_platform_interface/lib/src/enums.dart @@ -22,6 +22,18 @@ enum ConnectivityResult { /// It returns [other] on any device (also simulator). vpn, + /// Satellite: Device is connected via a highly constrained satellite link. + /// + /// On iOS and macOS, reported when [NWPath.isConstrained] is true. This + /// covers both satellite connections and Low Data Mode enabled by the user. + /// Appears alongside [mobile] (e.g. `[mobile, satellite]`). + /// + /// On Android 14+ (API 34), reported when [TRANSPORT_SATELLITE] capability + /// is present. Appears as a standalone result. + /// + /// Not reported on other platforms. + satellite, + /// Other: Device is connected to an unknown network other } diff --git a/packages/connectivity_plus/connectivity_plus_platform_interface/lib/src/utils.dart b/packages/connectivity_plus/connectivity_plus_platform_interface/lib/src/utils.dart index 786c7b9175..7155a562ae 100644 --- a/packages/connectivity_plus/connectivity_plus_platform_interface/lib/src/utils.dart +++ b/packages/connectivity_plus/connectivity_plus_platform_interface/lib/src/utils.dart @@ -14,6 +14,8 @@ List parseConnectivityResults(List states) { return ConnectivityResult.mobile; case 'vpn': return ConnectivityResult.vpn; + case 'satellite': + return ConnectivityResult.satellite; case 'other': return ConnectivityResult.other; default: diff --git a/packages/connectivity_plus/connectivity_plus_platform_interface/test/method_channel_connectivity_test.dart b/packages/connectivity_plus/connectivity_plus_platform_interface/test/method_channel_connectivity_test.dart index 244ffd9852..25579b3077 100644 --- a/packages/connectivity_plus/connectivity_plus_platform_interface/test/method_channel_connectivity_test.dart +++ b/packages/connectivity_plus/connectivity_plus_platform_interface/test/method_channel_connectivity_test.dart @@ -58,6 +58,26 @@ void main() { ); }); + test('checkConnectivity with satellite', () async { + TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger + .setMockMethodCallHandler( + methodChannelConnectivity.methodChannel, + (MethodCall methodCall) async { + switch (methodCall.method) { + case 'check': + return ['mobile', 'satellite']; + default: + return null; + } + }, + ); + final result = await methodChannelConnectivity.checkConnectivity(); + expect( + result, + containsAll([ConnectivityResult.mobile, ConnectivityResult.satellite]), + ); + }); + // Test adjusted to handle multiple connectivity types test('onConnectivityChanged', () async { final result =