Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(connectivity)!: support multiple ConnectivityResult values at the same time #2599

Merged

Conversation

suquant
Copy link
Contributor

@suquant suquant commented Feb 15, 2024

Description

This PR updates the connectivity_plus plugin to handle multiple connectivity types simultaneously. Previously, checkConnectivity and onConnectivityChanged methods returned a single ConnectivityResult type, which could be either wifi, cellular, ethernet, bluetooth, vpn, or none. Due to this, on iOS/macOS platforms, the types other & vpn were never returned because the presence of wifi or cellular took precedence. This update changes the return type of these methods to a list of ConnectivityResult, allowing for a more accurate representation of the device's connectivity status, especially in scenarios where multiple types of connections are available or in use simultaneously.

Related Issues

Checklist

  • I read the Contributor Guide and followed the process outlined there for submitting PRs.
  • I titled the PR using Conventional Commits.
  • I did not modify the CHANGELOG.md nor the plugin version in pubspec.yaml files.
  • All existing and new tests are passing.
  • The analyzer (flutter analyze) does not report any problems on my PR.

Breaking Change

Does your PR require plugin users to manually update their apps to accommodate your change?

  • Yes, this is a breaking change (please indicate that with a ! in the title as explained in Conventional Commits).
  • No, this is not a breaking change.

Users of the connectivity_plus plugin will need to update their apps to handle the new list of ConnectivityResult types returned by checkConnectivity and onConnectivityChanged methods. This change allows for a more comprehensive understanding of the device's connectivity status, particularly in environments where multiple connectivity options are available or in use.

@miquelbeltran miquelbeltran changed the title feat(connectivity): support multiple types feat(connectivity)!: support multiple types Feb 16, 2024
@suquant suquant force-pushed the feat/connectivity-multiple-types branch from 3785b4b to d59dcc4 Compare February 16, 2024 07:53
Copy link
Member

@miquelbeltran miquelbeltran left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks a lot for the contribution, I think this is a good start for a change that will fix several issues.

First, I'd like to ask you to properly fill the PR template, including the different checkboxes: https://github.com/fluttercommunity/plus_plugins/blob/main/.github/PULL_REQUEST_TEMPLATE.md

We can see CI issues (analytics and tests not building) and those should be fixed as well.

Regarding the code, and before I go and do a more deep review, is there any reason why is preferred to handle the list of connectivity items as a coma-separated string rather than a List of Strings? e.g. in Connectivity.java, the MethodChannel, etc.

@miquelbeltran miquelbeltran changed the title feat(connectivity)!: support multiple types feat(connectivity)!: support multiple ConnectivityResult values at the same time Feb 16, 2024
@suquant suquant force-pushed the feat/connectivity-multiple-types branch from d59dcc4 to 9e080b1 Compare February 16, 2024 08:11
@suquant suquant marked this pull request as draft February 16, 2024 08:13
@suquant suquant force-pushed the feat/connectivity-multiple-types branch 2 times, most recently from 5d3d371 to 6d6b11a Compare February 16, 2024 15:21
@suquant
Copy link
Contributor Author

suquant commented Feb 16, 2024

@miquelbeltran

Regarding the code, and before I go and do a more deep review, is there any reason why is preferred to handle the list of connectivity items as a coma-separated string rather than a List of Strings? e.g. in Connectivity.java, the MethodChannel, etc.

Fair note, agreed!

@suquant suquant force-pushed the feat/connectivity-multiple-types branch from 6d6b11a to 82d30e6 Compare February 16, 2024 15:35
@suquant suquant marked this pull request as ready for review February 16, 2024 15:37
@suquant suquant force-pushed the feat/connectivity-multiple-types branch from 82d30e6 to e654491 Compare February 16, 2024 15:43
Comment on lines 68 to 94
List<String> types = new ArrayList<>();
if (info == null || !info.isConnected()) {
return CONNECTIVITY_NONE;
types.add(CONNECTIVITY_NONE);
return types;
}
int type = info.getType();
switch (type) {
case ConnectivityManager.TYPE_BLUETOOTH:
return CONNECTIVITY_BLUETOOTH;
types.add(CONNECTIVITY_BLUETOOTH);
break;
case ConnectivityManager.TYPE_ETHERNET:
return CONNECTIVITY_ETHERNET;
types.add(CONNECTIVITY_ETHERNET);
break;
case ConnectivityManager.TYPE_WIFI:
case ConnectivityManager.TYPE_WIMAX:
return CONNECTIVITY_WIFI;
types.add(CONNECTIVITY_WIFI);
break;
case ConnectivityManager.TYPE_VPN:
return CONNECTIVITY_VPN;
types.add(CONNECTIVITY_VPN);
break;
case ConnectivityManager.TYPE_MOBILE:
case ConnectivityManager.TYPE_MOBILE_DUN:
case ConnectivityManager.TYPE_MOBILE_HIPRI:
return CONNECTIVITY_MOBILE;
types.add(CONNECTIVITY_MOBILE);
break;
default:
return CONNECTIVITY_NONE;
types.add(CONNECTIVITY_NONE);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it be possible to simplify this by returning a List.of(type)? For what I understand, the array will always have just one item.

I haven't done Java in a long time, so I don't remember if that was possible :)

Copy link
Contributor Author

@suquant suquant Feb 22, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thinks it's not so necessary cause return executes straight after switch statement.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what I mean is:

  • the code is creating an empty array on line 74
  • then adding a single item in the switch statement
  • then returning the array at the end after the switch.

And I'd prefer if the code could just call return inside the switch case with a List.of(item). It is less code, and less prone to returning an empty array in case of a future code refactor.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@miquelbeltran Thanks for the suggestion! I aimed to optimize by avoiding extra array creation, but I'm open to your perspective. If you think changing it is best, I'm on board.

Copy link
Member

@miquelbeltran miquelbeltran left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks again for the changes!

And btw, thanks for working on the Windows code as well, very few people want to touch that part of the project :)

I have left some comments, I need to also test this so it will take some time until we do the final approval, but so far it looks good.

I'd like to ask you too, that instead of force pushing changes, you can push new commits, so that I way I can track the PR changes since the last time I reviewed.

Thanks!

…e same time

BREAKING CHANGES: checkConnectivity and onConnectivityChanged returns list of connectivityResult. Users will need to update their apps to handle the new list of ConnectivityResult types returned by checkConnectivity and onConnectivityChanged methods.

Signed-off-by: George Kutsurua <[email protected]>
@suquant suquant force-pushed the feat/connectivity-multiple-types branch 2 times, most recently from 20b2450 to 2abc3b1 Compare February 22, 2024 10:24
@miquelbeltran miquelbeltran self-assigned this Feb 26, 2024
@miquelbeltran
Copy link
Member

I'll try to run some tests this week and do a deeper code review. Thanks!

@miquelbeltran
Copy link
Member

Tested Android (also with VPN), iOS, MacOS, Linux and Chrome. I could not test Windows. Seems to work as expected, except in Linux and Web it did not report VPN correctly, but that's another issue.

Copy link
Member

@miquelbeltran miquelbeltran left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good refactor unifying the iOS and MacOS codebases into a single one! We need to check if we can afford increasing the min-flutter sdk version.

I have added some other comments, otherwise it seems to be good.

Please, when you do updates, do not force-push, because if not I lose all the "viewed" history and need to review the whole PR again.

Comment on lines +10 to +12
# Flutter versions prior to 3.7 did not support the
# sharedDarwinSource option.
flutter: ">=3.7.0"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@vbuberen What do you think about increasing the min flutter version in order to share the macos and ios codebases? personally I am ok with it, but want to know your thoughts

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am Ok with that here, even though I don't like this merging of iOS and MacOS into one.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I opted to maintain a single codebase for both platforms, aligning with best practices for Apple's products.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am in favor of having a single code folder for both platform when possible, although it may not be the case for all plugins.

Copy link
Collaborator

@vbuberen vbuberen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the contribution, but I would ask to revert changes not related to the topic of the PR:

  1. Revert Gradle wrapper version.
  2. Revert naming changes for iOS/MacOS part.

Also, please address the review feedback comments provided by Miguel.

Comment on lines +10 to +12
# Flutter versions prior to 3.7 did not support the
# sharedDarwinSource option.
flutter: ">=3.7.0"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am Ok with that here, even though I don't like this merging of iOS and MacOS into one.

@suquant suquant force-pushed the feat/connectivity-multiple-types branch from 74cc9ac to b64f8b8 Compare March 4, 2024 11:07
@suquant suquant force-pushed the feat/connectivity-multiple-types branch from 474b154 to abb25ac Compare March 4, 2024 11:33
Copy link
Member

@miquelbeltran miquelbeltran left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, waiting for Volodymyr to comment

Comment on lines 26 to 31
s.platform = {
:ios => '12.0',
:osx => '10.14'
}
s.ios.deployment_target = '12.0'
s.osx.deployment_target = '10.14'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you know if it is necessary to define both platform and deployment_target? The docs only mention deployment_target: https://docs.flutter.dev/packages-and-plugins/developing-packages#shared-ios-and-macos-implementations

Comment on lines +10 to +12
# Flutter versions prior to 3.7 did not support the
# sharedDarwinSource option.
flutter: ">=3.7.0"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am in favor of having a single code folder for both platform when possible, although it may not be the case for all plugins.

@vbuberen
Copy link
Collaborator

vbuberen commented Mar 6, 2024

I see that the latest podspec comment is addressed as well.
So with that change all looks good to me. Let's merge it.

Thanks a lot for this contribution, George.

We will need to do some updates to our docs, I believe, but let's do not in this PR.

@suquant
Copy link
Contributor Author

suquant commented Mar 6, 2024

If all is good, I'm gonna squash all commits into a single one for better tracking and well organized. Thanks for review guys @miquelbeltran @vbuberen

@vbuberen
Copy link
Collaborator

vbuberen commented Mar 6, 2024

If all is good, I'm gonna squash all commits into a single one for better tracking and well organized. Thanks for review guys @miquelbeltran @vbuberen

Don't do it. We squash it ourselves.

@vbuberen vbuberen merged commit 5b47746 into fluttercommunity:main Mar 6, 2024
18 of 19 checks passed
@pamafe1976
Copy link

pamafe1976 commented Mar 21, 2024

Hi, I just tested this update in Android, and the behavior does not seem to be as intended.
I always receive a List with 1 ConnectivityResult.

If there is neither wifi or mobile I get [ConnectivityResult.none]
Then I turn on mobile and I get [ConnectivityResult.mobile] =>OnConnectionChanged called 3 times
Then I turn on wifi and I get [ConnectivityResult.wifi] =>OnConnectionChanged called 4 times
If at this point I turn off mobile, onConnectionChanged is not called.
Then I turn on wifi and I get [ConnectivityResult.none] =>OnConnectionChanged called 1 time

What I expected was

If there is neither wifi or mobile I get [ConnectivityResult.none]
Then I turn on mobile and I get [ConnectivityResult.mobile]
Then I turn on wifi and I get [ConnectivityResult.wifi, ConnectivityResult.mobile]
Then turn off mobile and get [ConnectivityResult.wifi]
Then turn off wifiand get [ConnectivityResult.none]

Of course the callback should be called only 1 time on each change

@vbuberen
Copy link
Collaborator

You are on Android, right?

If so, check the API documentation as it is documented that on Android having both wifi and mobile returns only wifi (or, to be correct, the one that is used for network activity). For example, if you do the same test with VPN turned on you would see 2 results instead.

As to number of times you get the event - on Android we listen to onCapabilitiesChanged callback from NetworkManager as well to catch all events from network state changes. So it is how this callback works. It is up to you to distinct changes in the stream.

With that being said feel free to open a new issue instead of discussing here, but from what you described it is expected behavior from the plugin and part about currently active states on Android is described in the API documentation as well.

@janniklind
Copy link

janniklind commented Apr 15, 2024

Is there some documentation around for why CONNECTIVITY_NONE is returned in the list?

I would prefer that in case of CONNECTIVITY_NONE then an empty list is returned, i.e. no available connections. It would be a cleaner API, that is more explicit.

Today when CONNECTIVITY_NONE is returned in the list, is it then guaranteed that it will always be the only item in the list?

I am using it like the following now, and I think many users would probably do the same:

bool _isConnected(List<ConnectivityResult> result) {
    return result.where((e) => e != ConnectivityResult.none).isNotEmpty;
}

@miquelbeltran
Copy link
Member

Today when CONNECTIVITY_NONE is returned in the list, is it then guaranteed that it will always be the only item in the list?

Yes, and that is documented (not sure if this has been published, but it is in main)

/// The returned list is never empty. In case of no connectivity, the list contains
/// a single element of [ConnectivityResult.none]. Note also that this is the only
/// case where [ConnectivityResult.none] is present.

You should be able to safely do result.first != ConnectivityResult.none or similar.

@janniklind
Copy link

Thanks for pointing to the documentation :)
May I ask what is the reasoning behind never returning an empty list?

@miquelbeltran
Copy link
Member

Since the plugin returned a ConnectivityResult.none originally, we kept that.

We could add a convenience extension method that returns a single value and wraps the response with a .first, and/or one that just tells if there's connectivity or not.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants