Skip to content

Commit

Permalink
feat(connectivity): support multiple types
Browse files Browse the repository at this point in the history
BREAKING CHANGES: checkConnectivity and onConnectivityChanged returns list of connectivityResult

Signed-off-by: George Kutsurua <[email protected]>
  • Loading branch information
suquant committed Feb 16, 2024
1 parent 707fab7 commit 9e080b1
Show file tree
Hide file tree
Showing 27 changed files with 294 additions and 208 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -22,59 +22,80 @@ public class Connectivity {
public Connectivity(ConnectivityManager connectivityManager) {
this.connectivityManager = connectivityManager;
}
private void appendType(StringBuilder types, String type) {
if (types.length() > 0) {
types.append(", ");
}
types.append(type);
}

String getNetworkType() {
String getNetworkTypes() {
StringBuilder types = new StringBuilder();
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
Network network = connectivityManager.getActiveNetwork();
NetworkCapabilities capabilities = connectivityManager.getNetworkCapabilities(network);
if (capabilities == null) {
return CONNECTIVITY_NONE;
}
if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) {
return CONNECTIVITY_WIFI;
appendType(types, CONNECTIVITY_WIFI);
}
if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET)) {
return CONNECTIVITY_ETHERNET;
appendType(types, CONNECTIVITY_ETHERNET);
}
if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_VPN)) {
return CONNECTIVITY_VPN;
appendType(types, CONNECTIVITY_VPN);
}
if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) {
return CONNECTIVITY_MOBILE;
appendType(types, CONNECTIVITY_MOBILE);
}
if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_BLUETOOTH)) {
return CONNECTIVITY_BLUETOOTH;
appendType(types, CONNECTIVITY_BLUETOOTH);
}
if (types.length() == 0) {
return CONNECTIVITY_NONE;
}
} else {
// For legacy versions, return a single type as before or adapt similarly if multiple types need to be supported
return getNetworkTypesLegacy();
}

return getNetworkTypeLegacy();
// Remove the last comma
return types.toString();
}

@SuppressWarnings("deprecation")
private String getNetworkTypeLegacy() {
private String getNetworkTypesLegacy() {
// handle type for Android versions less than Android 6
android.net.NetworkInfo info = connectivityManager.getActiveNetworkInfo();
if (info == null || !info.isConnected()) {
return CONNECTIVITY_NONE;
}
int type = info.getType();
StringBuilder types = new StringBuilder();
switch (type) {
case ConnectivityManager.TYPE_BLUETOOTH:
return CONNECTIVITY_BLUETOOTH;
appendType(types, CONNECTIVITY_BLUETOOTH);
break;
case ConnectivityManager.TYPE_ETHERNET:
return CONNECTIVITY_ETHERNET;
appendType(types, CONNECTIVITY_ETHERNET);
break;
case ConnectivityManager.TYPE_WIFI:
case ConnectivityManager.TYPE_WIMAX:
return CONNECTIVITY_WIFI;
appendType(types, CONNECTIVITY_WIFI);
break;
case ConnectivityManager.TYPE_VPN:
return CONNECTIVITY_VPN;
appendType(types, CONNECTIVITY_VPN);
break;
case ConnectivityManager.TYPE_MOBILE:
case ConnectivityManager.TYPE_MOBILE_DUN:
case ConnectivityManager.TYPE_MOBILE_HIPRI:
return CONNECTIVITY_MOBILE;
appendType(types, CONNECTIVITY_MOBILE);
break;
default:
return CONNECTIVITY_NONE;
}
return types.toString();
}

public ConnectivityManager getConnectivityManager() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,12 +78,12 @@ public void onCancel(Object arguments) {
@Override
public void onReceive(Context context, Intent intent) {
if (events != null) {
events.success(connectivity.getNetworkType());
events.success(connectivity.getNetworkTypes());
}
}

private void sendEvent() {
Runnable runnable = () -> events.success(connectivity.getNetworkType());
Runnable runnable = () -> events.success(connectivity.getNetworkTypes());
mainHandler.post(runnable);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ class ConnectivityMethodChannelHandler implements MethodChannel.MethodCallHandle
@Override
public void onMethodCall(MethodCall call, @NonNull MethodChannel.Result result) {
if ("check".equals(call.method)) {
result.success(connectivity.getNetworkType());
result.success(connectivity.getNetworkTypes());
} else {
result.notImplemented();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,17 +42,16 @@ class MyHomePage extends StatefulWidget {
}

class _MyHomePageState extends State<MyHomePage> {
ConnectivityResult _connectionStatus = ConnectivityResult.none;
List<ConnectivityResult> _connectionStatus = [ConnectivityResult.none];
final Connectivity _connectivity = Connectivity();
late StreamSubscription<ConnectivityResult> _connectivitySubscription;
late StreamSubscription<List<ConnectivityResult>> _connectivitySubscription;

@override
void initState() {
super.initState();
initConnectivity();

_connectivitySubscription =
_connectivity.onConnectivityChanged.listen(_updateConnectionStatus);
_connectivitySubscription = _connectivity.onConnectivityChanged.listen(_updateConnectionStatus);
}

@override
Expand All @@ -63,7 +62,7 @@ class _MyHomePageState extends State<MyHomePage> {

// Platform messages are asynchronous, so we initialize in an async method.
Future<void> initConnectivity() async {
late ConnectivityResult result;
late List<ConnectivityResult> result;
// Platform messages may fail, so we use a try/catch PlatformException.
try {
result = await _connectivity.checkConnectivity();
Expand All @@ -82,7 +81,7 @@ class _MyHomePageState extends State<MyHomePage> {
return _updateConnectionStatus(result);
}

Future<void> _updateConnectionStatus(ConnectivityResult result) async {
Future<void> _updateConnectionStatus(List<ConnectivityResult> result) async {
setState(() {
_connectionStatus = result;
});
Expand All @@ -95,8 +94,7 @@ class _MyHomePageState extends State<MyHomePage> {
title: const Text('Connectivity example app'),
elevation: 4,
),
body: Center(
child: Text('Connection Status: ${_connectionStatus.toString()}')),
body: Center(child: Text('Connection Status: ${_connectionStatus.toString()}')),
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@ environment:
dependencies:
flutter:
sdk: flutter
connectivity_plus: ^5.0.2
# connectivity_plus: ^5.0.2
connectivity_plus:
path: ../

dev_dependencies:
flutter_driver:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@ public enum ConnectivityType {
}

public protocol ConnectivityProvider: NSObjectProtocol {
typealias ConnectivityUpdateHandler = (ConnectivityType) -> Void

var currentConnectivityType: ConnectivityType { get }

typealias ConnectivityUpdateHandler = ([ConnectivityType]) -> Void
var currentConnectivityTypes: [ConnectivityType] { get }
var connectivityUpdateHandler: ConnectivityUpdateHandler? { get set }

func start()

func stop()
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,23 +8,27 @@ public class PathMonitorConnectivityProvider: NSObject, ConnectivityProvider {

private var _pathMonitor: NWPathMonitor?

public var currentConnectivityType: ConnectivityType {
public var currentConnectivityTypes: [ConnectivityType] {
let path = ensurePathMonitor().currentPath
// .satisfied means that the network is available
var types: [ConnectivityType] = []

// Check for connectivity and append to types array as necessary
if path.status == .satisfied {
if path.usesInterfaceType(.wifi) {
return .wifi
} else if path.usesInterfaceType(.cellular) {
return .cellular
} else if path.usesInterfaceType(.wiredEthernet) {
// .wiredEthernet is available in simulator
// but for consistency it is probably correct to report .wifi
return .wifi
} else if path.usesInterfaceType(.other) {
return .other
types.append(.wifi)
}
if path.usesInterfaceType(.cellular) {
types.append(.cellular)
}
if path.usesInterfaceType(.wiredEthernet) {
types.append(.wiredEthernet)
}
if path.usesInterfaceType(.other) {
types.append(.other)
}
}
return .none

return types.isEmpty ? [.none] : types
}

public var connectivityUpdateHandler: ConnectivityUpdateHandler?
Expand Down Expand Up @@ -55,6 +59,6 @@ public class PathMonitorConnectivityProvider: NSObject, ConnectivityProvider {
}

private func pathUpdateHandler(path: NWPath) {
connectivityUpdateHandler?(currentConnectivityType)
connectivityUpdateHandler?(currentConnectivityTypes)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,18 @@ import Reachability
public class ReachabilityConnectivityProvider: NSObject, ConnectivityProvider {
private var _reachability: Reachability?

public var currentConnectivityType: ConnectivityType {
let reachability = ensureReachability()
public var currentConnectivityTypes: [ConnectivityType] {
guard let reachability = _reachability else {
return [.none]
}

switch reachability.connection {
case .wifi:
return .wifi
return [.wifi]
case .cellular:
return .cellular
return [.cellular]
default:
return .none
return [.none]
}
}

Expand Down Expand Up @@ -54,6 +57,9 @@ public class ReachabilityConnectivityProvider: NSObject, ConnectivityProvider {
}

@objc private func reachabilityChanged(notification: NSNotification) {
connectivityUpdateHandler?(currentConnectivityType)
if let reachability = notification.object as? Reachability {
_reachability = reachability
connectivityUpdateHandler?(currentConnectivityTypes)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ public class SwiftConnectivityPlusPlugin: NSObject, FlutterPlugin, FlutterStream
public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
switch call.method {
case "check":
result(statusFrom(connectivityType: connectivityProvider.currentConnectivityType))
result(statusFrom(connectivityTypes: connectivityProvider.currentConnectivityTypes))
default:
result(FlutterMethodNotImplemented)
}
Expand All @@ -64,20 +64,27 @@ public class SwiftConnectivityPlusPlugin: NSObject, FlutterPlugin, FlutterStream
return "none"
}
}

private func statusFrom(connectivityTypes: [ConnectivityType]) -> String {
return connectivityTypes.map {
self.statusFrom(connectivityType: $0)
}.joined(separator: ",")
}

public func onListen(
withArguments _: Any?,
eventSink events: @escaping FlutterEventSink
) -> FlutterError? {
eventSink = events
connectivityProvider.start()
connectivityUpdateHandler(connectivityType: connectivityProvider.currentConnectivityType)
// Update this to handle a list
connectivityUpdateHandler(connectivityTypes: connectivityProvider.currentConnectivityTypes)
return nil
}

private func connectivityUpdateHandler(connectivityType: ConnectivityType) {
private func connectivityUpdateHandler(connectivityTypes: [ConnectivityType]) {
DispatchQueue.main.async {
self.eventSink?(self.statusFrom(connectivityType: connectivityType))
self.eventSink?(self.statusFrom(connectivityTypes: connectivityTypes))
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,7 @@ import 'package:connectivity_plus_platform_interface/connectivity_plus_platform_
export 'package:connectivity_plus_platform_interface/connectivity_plus_platform_interface.dart'
show ConnectivityResult;

export 'src/connectivity_plus_linux.dart'
if (dart.library.html) 'src/connectivity_plus_web.dart';
export 'src/connectivity_plus_linux.dart' if (dart.library.html) 'src/connectivity_plus_web.dart';

/// Discover network connectivity configurations: Distinguish between WI-FI and cellular, check WI-FI status and more.
class Connectivity {
Expand Down Expand Up @@ -39,7 +38,7 @@ class Connectivity {
/// On iOS, the connectivity status might not update when WiFi
/// status changes, this is a known issue that only affects simulators.
/// For details see https://github.com/fluttercommunity/plus_plugins/issues/479.
Stream<ConnectivityResult> get onConnectivityChanged {
Stream<List<ConnectivityResult>> get onConnectivityChanged {
return _platform.onConnectivityChanged;
}

Expand All @@ -49,7 +48,7 @@ class Connectivity {
/// make a network request. It only gives you the radio status.
///
/// Instead listen for connectivity changes via [onConnectivityChanged] stream.
Future<ConnectivityResult> checkConnectivity() {
Future<List<ConnectivityResult>> checkConnectivity() {
return _platform.checkConnectivity();
}
}
Loading

0 comments on commit 9e080b1

Please sign in to comment.