diff --git a/packages/connectivity_plus/connectivity_plus/lib/src/connectivity_plus_linux.dart b/packages/connectivity_plus/connectivity_plus/lib/src/connectivity_plus_linux.dart index 31b562aa24..8d676fb351 100644 --- a/packages/connectivity_plus/connectivity_plus/lib/src/connectivity_plus_linux.dart +++ b/packages/connectivity_plus/connectivity_plus/lib/src/connectivity_plus_linux.dart @@ -20,11 +20,19 @@ class ConnectivityPlusLinuxPlugin extends ConnectivityPlatform { /// Checks the connection status of the device. @override Future> checkConnectivity() async { - final client = createClient(); - await client.connect(); - final connectivity = _getConnectivity(client); - await client.close(); - return connectivity; + try { + final client = createClient(); + await client.connect(); + final connectivity = _getConnectivity(client); + await client.close(); + return connectivity; + } catch (e) { + // NetworkManager may not be installed or running on this Linux system. + // Rather than crashing, we gracefully degrade by treating this as + // no connectivity. This ensures the plugin works on all Linux distributions + // regardless of their network management infrastructure. + return [ConnectivityResult.none]; + } } NetworkManagerClient? _client; @@ -69,14 +77,21 @@ class ConnectivityPlusLinuxPlugin extends ConnectivityPlatform { } Future _startListenConnectivity() async { - _client ??= createClient(); - await _client!.connect(); - _addConnectivity(_client!); - _client!.propertiesChanged.listen((properties) { - if (properties.contains('Connectivity')) { - _addConnectivity(_client!); - } - }); + try { + _client ??= createClient(); + await _client!.connect(); + _addConnectivity(_client!); + _client!.propertiesChanged.listen((properties) { + if (properties.contains('Connectivity')) { + _addConnectivity(_client!); + } + }); + } catch (e) { + // NetworkManager may not be installed or running on this Linux system. + // We emit ConnectivityResult.none to the stream to indicate no connectivity + // can be determined, rather than crashing the application. + _controller?.add([ConnectivityResult.none]); + } } void _addConnectivity(NetworkManagerClient client) { diff --git a/packages/connectivity_plus/connectivity_plus/test/connectivity_plus_linux_test.dart b/packages/connectivity_plus/connectivity_plus/test/connectivity_plus_linux_test.dart index b7ecf03cab..6bed064515 100644 --- a/packages/connectivity_plus/connectivity_plus/test/connectivity_plus_linux_test.dart +++ b/packages/connectivity_plus/connectivity_plus/test/connectivity_plus_linux_test.dart @@ -18,8 +18,9 @@ void main() { final linux = ConnectivityPlusLinuxPlugin(); linux.createClient = () { final client = MockNetworkManagerClient(); - when(client.connectivity) - .thenReturn(NetworkManagerConnectivityState.full); + when( + client.connectivity, + ).thenReturn(NetworkManagerConnectivityState.full); when(client.primaryConnectionType).thenReturn('bluetooth'); return client; }; @@ -33,8 +34,9 @@ void main() { final linux = ConnectivityPlusLinuxPlugin(); linux.createClient = () { final client = MockNetworkManagerClient(); - when(client.connectivity) - .thenReturn(NetworkManagerConnectivityState.full); + when( + client.connectivity, + ).thenReturn(NetworkManagerConnectivityState.full); when(client.primaryConnectionType).thenReturn('ethernet'); return client; }; @@ -48,8 +50,9 @@ void main() { final linux = ConnectivityPlusLinuxPlugin(); linux.createClient = () { final client = MockNetworkManagerClient(); - when(client.connectivity) - .thenReturn(NetworkManagerConnectivityState.full); + when( + client.connectivity, + ).thenReturn(NetworkManagerConnectivityState.full); when(client.primaryConnectionType).thenReturn('wireless'); return client; }; @@ -63,8 +66,9 @@ void main() { final linux = ConnectivityPlusLinuxPlugin(); linux.createClient = () { final client = MockNetworkManagerClient(); - when(client.connectivity) - .thenReturn(NetworkManagerConnectivityState.full); + when( + client.connectivity, + ).thenReturn(NetworkManagerConnectivityState.full); when(client.primaryConnectionType).thenReturn('vpn'); return client; }; @@ -78,8 +82,9 @@ void main() { final linux = ConnectivityPlusLinuxPlugin(); linux.createClient = () { final client = MockNetworkManagerClient(); - when(client.connectivity) - .thenReturn(NetworkManagerConnectivityState.full); + when( + client.connectivity, + ).thenReturn(NetworkManagerConnectivityState.full); when(client.primaryConnectionType).thenReturn('wireless,vpn'); return client; }; @@ -93,33 +98,66 @@ void main() { final linux = ConnectivityPlusLinuxPlugin(); linux.createClient = () { final client = MockNetworkManagerClient(); - when(client.connectivity) - .thenReturn(NetworkManagerConnectivityState.none); + when( + client.connectivity, + ).thenReturn(NetworkManagerConnectivityState.none); return client; }; - expect(linux.checkConnectivity(), - completion(equals([ConnectivityResult.none]))); + expect( + linux.checkConnectivity(), + completion(equals([ConnectivityResult.none])), + ); }); test('connectivity changes', () { final linux = ConnectivityPlusLinuxPlugin(); linux.createClient = () { final client = MockNetworkManagerClient(); - when(client.connectivity) - .thenReturn(NetworkManagerConnectivityState.full); + when( + client.connectivity, + ).thenReturn(NetworkManagerConnectivityState.full); when(client.primaryConnectionType).thenReturn('wireless'); when(client.propertiesChanged).thenAnswer((_) { - when(client.connectivity) - .thenReturn(NetworkManagerConnectivityState.none); + when( + client.connectivity, + ).thenReturn(NetworkManagerConnectivityState.none); return Stream.value(['Connectivity']); }); return client; }; expect( - linux.onConnectivityChanged, - emitsInOrder([ - [ConnectivityResult.wifi], - [ConnectivityResult.none] - ])); + linux.onConnectivityChanged, + emitsInOrder([ + [ConnectivityResult.wifi], + [ConnectivityResult.none], + ]), + ); + }); + + test('NetworkManager unavailable - checkConnectivity', () async { + final linux = ConnectivityPlusLinuxPlugin(); + linux.createClient = () { + final client = MockNetworkManagerClient(); + when( + client.connect(), + ).thenThrow(Exception('NetworkManager not available')); + return client; + }; + expect( + linux.checkConnectivity(), + completion(equals([ConnectivityResult.none])), + ); + }); + + test('NetworkManager unavailable - onConnectivityChanged', () { + final linux = ConnectivityPlusLinuxPlugin(); + linux.createClient = () { + final client = MockNetworkManagerClient(); + when( + client.connect(), + ).thenThrow(Exception('NetworkManager not available')); + return client; + }; + expect(linux.onConnectivityChanged, emits([ConnectivityResult.none])); }); }