Merge pull request 'detectNetwork' (#670) from detectNetwork into trunk
continuous-integration/drone/push Build is passing Details

Reviewed-on: #670
This commit is contained in:
Sarah Jamie Lewis 2023-05-15 16:06:25 +00:00
commit 0b0a5095f1
55 changed files with 3251 additions and 9 deletions

View File

@ -1 +1 @@
2023-05-09-13-30-v0.0.3-24-g5b2f3cf
2023-05-09-13-30-v0.0.3-24-g5b2f3cf

View File

@ -1,5 +1,7 @@
#Mon Jun 20 10:33:21 PDT 2022
distributionBase=GRADLE_USER_HOME
# third party plugin connectivity_plus should match, so when updating, also update
# lib/third_party/connectivity_plus/connectivity_plus/android/gradle/wrapper/gradle-wrapper.properties
distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-bin.zip
distributionPath=wrapper/dists
zipStorePath=wrapper/dists

View File

@ -139,6 +139,416 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.''');
yield LicenseEntryWithLineBreaks(["connectivity_plus", "connectivity_plus_platform_interface"], '''
Copyright 2017 The Chromium Authors. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''');
yield LicenseEntryWithLineBreaks(["connectivity_plus"], '''
* Copyright (c) 2013-2020, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
* See full license text in LICENSE file at top of project tree''');
yield LicenseEntryWithLineBreaks(["nm"], '''Mozilla Public License Version 2.0
==================================
1. Definitions
--------------
1.1. "Contributor"
means each individual or legal entity that creates, contributes to
the creation of, or owns Covered Software.
1.2. "Contributor Version"
means the combination of the Contributions of others (if any) used
by a Contributor and that particular Contributor's Contribution.
1.3. "Contribution"
means Covered Software of a particular Contributor.
1.4. "Covered Software"
means Source Code Form to which the initial Contributor has attached
the notice in Exhibit A, the Executable Form of such Source Code
Form, and Modifications of such Source Code Form, in each case
including portions thereof.
1.5. "Incompatible With Secondary Licenses"
means
(a) that the initial Contributor has attached the notice described
in Exhibit B to the Covered Software; or
(b) that the Covered Software was made available under the terms of
version 1.1 or earlier of the License, but not also under the
terms of a Secondary License.
1.6. "Executable Form"
means any form of the work other than Source Code Form.
1.7. "Larger Work"
means a work that combines Covered Software with other material, in
a separate file or files, that is not Covered Software.
1.8. "License"
means this document.
1.9. "Licensable"
means having the right to grant, to the maximum extent possible,
whether at the time of the initial grant or subsequently, any and
all of the rights conveyed by this License.
1.10. "Modifications"
means any of the following:
(a) any file in Source Code Form that results from an addition to,
deletion from, or modification of the contents of Covered
Software; or
(b) any new file in Source Code Form that contains any Covered
Software.
1.11. "Patent Claims" of a Contributor
means any patent claim(s), including without limitation, method,
process, and apparatus claims, in any patent Licensable by such
Contributor that would be infringed, but for the grant of the
License, by the making, using, selling, offering for sale, having
made, import, or transfer of either its Contributions or its
Contributor Version.
1.12. "Secondary License"
means either the GNU General Public License, Version 2.0, the GNU
Lesser General Public License, Version 2.1, the GNU Affero General
Public License, Version 3.0, or any later versions of those
licenses.
1.13. "Source Code Form"
means the form of the work preferred for making modifications.
1.14. "You" (or "Your")
means an individual or a legal entity exercising rights under this
License. For legal entities, "You" includes any entity that
controls, is controlled by, or is under common control with You. For
purposes of this definition, "control" means (a) the power, direct
or indirect, to cause the direction or management of such entity,
whether by contract or otherwise, or (b) ownership of more than
fifty percent (50%) of the outstanding shares or beneficial
ownership of such entity.
2. License Grants and Conditions
--------------------------------
2.1. Grants
Each Contributor hereby grants You a world-wide, royalty-free,
non-exclusive license:
(a) under intellectual property rights (other than patent or trademark)
Licensable by such Contributor to use, reproduce, make available,
modify, display, perform, distribute, and otherwise exploit its
Contributions, either on an unmodified basis, with Modifications, or
as part of a Larger Work; and
(b) under Patent Claims of such Contributor to make, use, sell, offer
for sale, have made, import, and otherwise transfer either its
Contributions or its Contributor Version.
2.2. Effective Date
The licenses granted in Section 2.1 with respect to any Contribution
become effective for each Contribution on the date the Contributor first
distributes such Contribution.
2.3. Limitations on Grant Scope
The licenses granted in this Section 2 are the only rights granted under
this License. No additional rights or licenses will be implied from the
distribution or licensing of Covered Software under this License.
Notwithstanding Section 2.1(b) above, no patent license is granted by a
Contributor:
(a) for any code that a Contributor has removed from Covered Software;
or
(b) for infringements caused by: (i) Your and any other third party's
modifications of Covered Software, or (ii) the combination of its
Contributions with other software (except as part of its Contributor
Version); or
(c) under Patent Claims infringed by Covered Software in the absence of
its Contributions.
This License does not grant any rights in the trademarks, service marks,
or logos of any Contributor (except as may be necessary to comply with
the notice requirements in Section 3.4).
2.4. Subsequent Licenses
No Contributor makes additional grants as a result of Your choice to
distribute the Covered Software under a subsequent version of this
License (see Section 10.2) or under the terms of a Secondary License (if
permitted under the terms of Section 3.3).
2.5. Representation
Each Contributor represents that the Contributor believes its
Contributions are its original creation(s) or it has sufficient rights
to grant the rights to its Contributions conveyed by this License.
2.6. Fair Use
This License is not intended to limit any rights You have under
applicable copyright doctrines of fair use, fair dealing, or other
equivalents.
2.7. Conditions
Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
in Section 2.1.
3. Responsibilities
-------------------
3.1. Distribution of Source Form
All distribution of Covered Software in Source Code Form, including any
Modifications that You create or to which You contribute, must be under
the terms of this License. You must inform recipients that the Source
Code Form of the Covered Software is governed by the terms of this
License, and how they can obtain a copy of this License. You may not
attempt to alter or restrict the recipients' rights in the Source Code
Form.
3.2. Distribution of Executable Form
If You distribute Covered Software in Executable Form then:
(a) such Covered Software must also be made available in Source Code
Form, as described in Section 3.1, and You must inform recipients of
the Executable Form how they can obtain a copy of such Source Code
Form by reasonable means in a timely manner, at a charge no more
than the cost of distribution to the recipient; and
(b) You may distribute such Executable Form under the terms of this
License, or sublicense it under different terms, provided that the
license for the Executable Form does not attempt to limit or alter
the recipients' rights in the Source Code Form under this License.
3.3. Distribution of a Larger Work
You may create and distribute a Larger Work under terms of Your choice,
provided that You also comply with the requirements of this License for
the Covered Software. If the Larger Work is a combination of Covered
Software with a work governed by one or more Secondary Licenses, and the
Covered Software is not Incompatible With Secondary Licenses, this
License permits You to additionally distribute such Covered Software
under the terms of such Secondary License(s), so that the recipient of
the Larger Work may, at their option, further distribute the Covered
Software under the terms of either this License or such Secondary
License(s).
3.4. Notices
You may not remove or alter the substance of any license notices
(including copyright notices, patent notices, disclaimers of warranty,
or limitations of liability) contained within the Source Code Form of
the Covered Software, except that You may alter any license notices to
the extent required to remedy known factual inaccuracies.
3.5. Application of Additional Terms
You may choose to offer, and to charge a fee for, warranty, support,
indemnity or liability obligations to one or more recipients of Covered
Software. However, You may do so only on Your own behalf, and not on
behalf of any Contributor. You must make it absolutely clear that any
such warranty, support, indemnity, or liability obligation is offered by
You alone, and You hereby agree to indemnify every Contributor for any
liability incurred by such Contributor as a result of warranty, support,
indemnity or liability terms You offer. You may include additional
disclaimers of warranty and limitations of liability specific to any
jurisdiction.
4. Inability to Comply Due to Statute or Regulation
---------------------------------------------------
If it is impossible for You to comply with any of the terms of this
License with respect to some or all of the Covered Software due to
statute, judicial order, or regulation then You must: (a) comply with
the terms of this License to the maximum extent possible; and (b)
describe the limitations and the code they affect. Such description must
be placed in a text file included with all distributions of the Covered
Software under this License. Except to the extent prohibited by statute
or regulation, such description must be sufficiently detailed for a
recipient of ordinary skill to be able to understand it.
5. Termination
--------------
5.1. The rights granted under this License will terminate automatically
if You fail to comply with any of its terms. However, if You become
compliant, then the rights granted under this License from a particular
Contributor are reinstated (a) provisionally, unless and until such
Contributor explicitly and finally terminates Your grants, and (b) on an
ongoing basis, if such Contributor fails to notify You of the
non-compliance by some reasonable means prior to 60 days after You have
come back into compliance. Moreover, Your grants from a particular
Contributor are reinstated on an ongoing basis if such Contributor
notifies You of the non-compliance by some reasonable means, this is the
first time You have received notice of non-compliance with this License
from such Contributor, and You become compliant prior to 30 days after
Your receipt of the notice.
5.2. If You initiate litigation against any entity by asserting a patent
infringement claim (excluding declaratory judgment actions,
counter-claims, and cross-claims) alleging that a Contributor Version
directly or indirectly infringes any patent, then the rights granted to
You by any and all Contributors for the Covered Software under Section
2.1 of this License shall terminate.
5.3. In the event of termination under Sections 5.1 or 5.2 above, all
end user license agreements (excluding distributors and resellers) which
have been validly granted by You or Your distributors under this License
prior to termination shall survive termination.
************************************************************************
* *
* 6. Disclaimer of Warranty *
* ------------------------- *
* *
* Covered Software is provided under this License on an "as is" *
* basis, without warranty of any kind, either expressed, implied, or *
* statutory, including, without limitation, warranties that the *
* Covered Software is free of defects, merchantable, fit for a *
* particular purpose or non-infringing. The entire risk as to the *
* quality and performance of the Covered Software is with You. *
* Should any Covered Software prove defective in any respect, You *
* (not any Contributor) assume the cost of any necessary servicing, *
* repair, or correction. This disclaimer of warranty constitutes an *
* essential part of this License. No use of any Covered Software is *
* authorized under this License except under this disclaimer. *
* *
************************************************************************
************************************************************************
* *
* 7. Limitation of Liability *
* -------------------------- *
* *
* Under no circumstances and under no legal theory, whether tort *
* (including negligence), contract, or otherwise, shall any *
* Contributor, or anyone who distributes Covered Software as *
* permitted above, be liable to You for any direct, indirect, *
* special, incidental, or consequential damages of any character *
* including, without limitation, damages for lost profits, loss of *
* goodwill, work stoppage, computer failure or malfunction, or any *
* and all other commercial damages or losses, even if such party *
* shall have been informed of the possibility of such damages. This *
* limitation of liability shall not apply to liability for death or *
* personal injury resulting from such party's negligence to the *
* extent applicable law prohibits such limitation. Some *
* jurisdictions do not allow the exclusion or limitation of *
* incidental or consequential damages, so this exclusion and *
* limitation may not apply to You. *
* *
************************************************************************
8. Litigation
-------------
Any litigation relating to this License may be brought only in the
courts of a jurisdiction where the defendant maintains its principal
place of business and such litigation shall be governed by laws of that
jurisdiction, without reference to its conflict-of-law provisions.
Nothing in this Section shall prevent a party's ability to bring
cross-claims or counter-claims.
9. Miscellaneous
----------------
This License represents the complete agreement concerning the subject
matter hereof. If any provision of this License is held to be
unenforceable, such provision shall be reformed only to the extent
necessary to make it enforceable. Any law or regulation which provides
that the language of a contract shall be construed against the drafter
shall not be used to construe this License against a Contributor.
10. Versions of the License
---------------------------
10.1. New Versions
Mozilla Foundation is the license steward. Except as provided in Section
10.3, no one other than the license steward has the right to modify or
publish new versions of this License. Each version will be given a
distinguishing version number.
10.2. Effect of New Versions
You may distribute the Covered Software under the terms of the version
of the License under which You originally received the Covered Software,
or under the terms of any subsequent version published by the license
steward.
10.3. Modified Versions
If you create software not governed by this License, and you want to
create a new license for such software, you may create and use a
modified version of this License if you rename the license and remove
any references to the name of the license steward (except to note that
such modified license differs from this License).
10.4. Distributing Source Code Form that is Incompatible With Secondary
Licenses
If You choose to distribute Source Code Form that is Incompatible With
Secondary Licenses under the terms of this version of the License, the
notice described in Exhibit B of this License must be attached.
Exhibit A - Source Code Form License Notice
-------------------------------------------
This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this
file, You can obtain one at http://mozilla.org/MPL/2.0/.
If it is not possible or desirable to put the notice in a particular
file, then You may include the notice in a location (such as a LICENSE
file in a relevant directory) where a recipient would be likely to look
for such a notice.
You may add additional accurate notices of copyright ownership.
Exhibit B - "Incompatible With Secondary Licenses" Notice
---------------------------------------------------------
This Source Code Form is "Incompatible With Secondary Licenses", as
defined by the Mozilla Public License, v. 2.0.''');
yield LicenseEntryWithLineBreaks(["Roboto fonts"], '''
Apache License

View File

@ -1,3 +1,4 @@
import 'dart:async';
import 'dart:convert';
import 'package:cwtch/config.dart';
import 'package:cwtch/notification_manager.dart';
@ -29,6 +30,8 @@ import 'views/splashView.dart';
import 'dart:io' show Platform, exit;
import 'themes/opaque.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:connectivity_plus/connectivity_plus.dart';
import 'package:intl/intl.dart' as intl;
@ -53,6 +56,8 @@ class Flwtch extends StatefulWidget {
FlwtchState createState() => FlwtchState();
}
enum ConnectivityState { assumed_online, confirmed_offline, confirmed_online }
class FlwtchState extends State<Flwtch> with WindowListener {
final TextStyle biggerFont = const TextStyle(fontSize: 18);
late Cwtch cwtch;
@ -60,6 +65,8 @@ class FlwtchState extends State<Flwtch> with WindowListener {
final MethodChannel notificationClickChannel = MethodChannel('im.cwtch.flwtch/notificationClickHandler');
final MethodChannel shutdownMethodChannel = MethodChannel('im.cwtch.flwtch/shutdownClickHandler');
final MethodChannel shutdownLinuxMethodChannel = MethodChannel('im.cwtch.linux.shutdown');
late StreamSubscription? connectivityStream;
ConnectivityState connectivityState = ConnectivityState.assumed_online;
final GlobalKey<NavigatorState> navKey = GlobalKey<NavigatorState>();
@ -88,22 +95,74 @@ class FlwtchState extends State<Flwtch> with WindowListener {
shutdownLinuxMethodChannel.setMethodCallHandler(shutdownDirect);
print("initState: creating cwtchnotifier, ffi");
if (Platform.isAndroid) {
var cwtchNotifier = new CwtchNotifier(profs, globalSettings, globalErrorHandler, globalTorStatus, NullNotificationsManager(), globalAppState, globalServersList, this);
var cwtchNotifier = new CwtchNotifier(
profs,
globalSettings,
globalErrorHandler,
globalTorStatus,
NullNotificationsManager(),
globalAppState,
globalServersList,
this);
cwtch = CwtchGomobile(cwtchNotifier);
} else if (Platform.isLinux) {
var cwtchNotifier =
new CwtchNotifier(profs, globalSettings, globalErrorHandler, globalTorStatus, newDesktopNotificationsManager(_notificationSelectConvo), globalAppState, globalServersList, this);
new CwtchNotifier(
profs,
globalSettings,
globalErrorHandler,
globalTorStatus,
newDesktopNotificationsManager(_notificationSelectConvo),
globalAppState,
globalServersList,
this);
cwtch = CwtchFfi(cwtchNotifier);
} else {
var cwtchNotifier =
new CwtchNotifier(profs, globalSettings, globalErrorHandler, globalTorStatus, newDesktopNotificationsManager(_notificationSelectConvo), globalAppState, globalServersList, this);
new CwtchNotifier(
profs,
globalSettings,
globalErrorHandler,
globalTorStatus,
newDesktopNotificationsManager(_notificationSelectConvo),
globalAppState,
globalServersList,
this);
cwtch = CwtchFfi(cwtchNotifier);
}
startConnectivityListener();
print("initState: invoking cwtch.Start()");
cwtch.Start();
print("initState: done!");
}
// connectivity listening is an optional enhancement feature that tries to listen for OS events about the network
// and if it detects coming back online, restarts the ACN/tor
// gracefully fails and NOPs, as it's not a required functionality
startConnectivityListener() async {
try {
connectivityStream = await Connectivity().onConnectivityChanged.listen((ConnectivityResult result) {
// Got a new connectivity status!
if (result == ConnectivityResult.none) {
connectivityState = ConnectivityState.confirmed_offline;
} else {
// were we offline?
if (connectivityState == ConnectivityState.confirmed_offline) {
EnvironmentConfig.debugLog("Network appears to have come back online, restarting Tor");
cwtch.ResetTor();
}
connectivityState = ConnectivityState.confirmed_online;
}
}, onError: (Object error) {
print("Error listening to connectivity for network state: {$error}");
return null;
}, cancelOnError: true);
} catch (e) {
print("Warning: Unable to open connectivity for listening to network state: {$e}");
connectivityStream = null;
}
}
ChangeNotifierProvider<TorStatus> getTorStatusProvider() => ChangeNotifierProvider.value(value: globalTorStatus);
ChangeNotifierProvider<ErrorHandler> getErrorHandlerProvider() => ChangeNotifierProvider.value(value: globalErrorHandler);
ChangeNotifierProvider<Settings> getSettingsProvider() => ChangeNotifierProvider.value(value: globalSettings);
@ -275,6 +334,7 @@ class FlwtchState extends State<Flwtch> with WindowListener {
cwtch.Shutdown();
windowManager.removeListener(this);
cwtch.dispose();
connectivityStream?.cancel();
super.dispose();
}
}

View File

@ -0,0 +1,27 @@
Copyright 2017 The Chromium Authors. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@ -0,0 +1,27 @@
Copyright 2017 The Chromium Authors. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@ -0,0 +1,108 @@
# connectivity_plus
- Open Privacy has updated this package to use local and stripped down version of `nm` package
[![Flutter Community: connectivity_plus](https://fluttercommunity.dev/_github/header/connectivity_plus)](https://github.com/fluttercommunity/community)
[![pub package](https://img.shields.io/pub/v/connectivity_plus.svg)](https://pub.dev/packages/connectivity_plus)
[![pub points](https://img.shields.io/pub/points/connectivity_plus?color=2E8B57&label=pub%20points)](https://pub.dev/packages/connectivity_plus/score)
[![connectivity_plus](https://github.com/fluttercommunity/plus_plugins/actions/workflows/connectivity_plus.yaml/badge.svg)](https://github.com/fluttercommunity/plus_plugins/actions/workflows/connectivity_plus.yaml)
<p class="center">
<center><a href="https://flutter.dev/docs/development/packages-and-plugins/favorites" target="_blank" rel="noreferrer noopener"><img src="../../../website/static/img/flutter-favorite-badge.png" width="100" alt="build"></a></center>
</p>
This plugin allows Flutter apps to discover network connectivity and configure
themselves accordingly. It can distinguish between cellular vs WiFi connection.
> **Note**
>
> On Android, this does not guarantee connection to Internet. For instance, the app might have wifi access but it might be a VPN or a hotel WiFi > with no access.
## Platform Support
| Android | iOS | MacOS | Web | Linux | Windows |
| :-----: | :-: | :---: | :-: | :---: | :-----: |
| ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ |
## Usage
Sample usage to check current status:
```dart
import 'package:connectivity_plus/connectivity_plus.dart';
final connectivityResult = await (Connectivity().checkConnectivity());
if (connectivityResult == ConnectivityResult.mobile) {
// I am connected to a mobile network.
} else if (connectivityResult == ConnectivityResult.wifi) {
// I am connected to a wifi network.
} else if (connectivityResult == ConnectivityResult.ethernet) {
// I am connected to a ethernet network.
} else if (connectivityResult == ConnectivityResult.vpn) {
// I am connected to a vpn network.
// Note for iOS and macOS:
// There is no separate network interface type for [vpn].
// It returns [other] on any device (also simulator)
} else if (connectivityResult == ConnectivityResult.bluetooth) {
// I am connected to a bluetooth.
} else if (connectivityResult == ConnectivityResult.other) {
// I am connected to a network which is not in the above mentioned networks.
} else if (connectivityResult == ConnectivityResult.none) {
// I am not connected to any network.
}
```
> **Note**
>
> You should not be using the current network status for deciding whether you can reliably make a network connection. Always guard your app code against timeouts and errors that might come from the network layer.
You can also listen for network state changes by subscribing to the stream
exposed by connectivity plugin:
```dart
import 'package:connectivity_plus/connectivity_plus.dart';
@override
initState() {
super.initState();
subscription = Connectivity().onConnectivityChanged.listen((ConnectivityResult result) {
// Got a new connectivity status!
});
}
// Be sure to cancel subscription after you are done
@override
dispose() {
subscription.cancel();
super.dispose();
}
```
> **Note**
>
> Connectivity changes are no longer communicated to Android apps in the background starting with Android O (8.0). _You should always check for connectivity status when your app is resumed._ The broadcast is only useful when your application is in the foreground.
## Limitations on the web platform
In order to retrieve information about the quality/speed of a browser's connection, the web implementation of the `connectivity` plugin uses the browser's [**NetworkInformation** Web API](https://developer.mozilla.org/en-US/docs/Web/API/NetworkInformation), which as of this writing (June 2020) is still "experimental", and not available in all browsers:
![Data on support for the netinfo feature across the major browsers from caniuse.com](https://caniuse.bitsofco.de/image/netinfo.png)
On desktop browsers, this API only returns a very broad set of connectivity statuses (One of `'slow-2g', '2g', '3g', or '4g'`), and may _not_ provide a Stream of changes. Firefox still hasn't enabled this feature by default.
**Fallback to `navigator.onLine`**
For those browsers where the NetworkInformation Web API is not available, the plugin falls back to the [**NavigatorOnLine** Web API](https://developer.mozilla.org/en-US/docs/Web/API/NavigatorOnLine), which is more broadly supported:
![Data on support for the online-status feature across the major browsers from caniuse.com](https://caniuse.bitsofco.de/image/online-status.png)
The NavigatorOnLine API is [provided by `dart:html`](https://api.dart.dev/stable/2.7.2/dart-html/Navigator/onLine.html), and only supports a boolean connectivity status (either online or offline), with no network speed information. In those cases the plugin will return either `wifi` (when the browser is online) or `none` (when it's not).
Other than the approximate "downlink" speed, where available, and due to security and privacy concerns, **no Web browser will provide** any specific information about the actual network your users' device is connected to, like **the SSID on a Wi-Fi, or the MAC address of their device.**
## Learn more
- [API Documentation](https://pub.dev/documentation/connectivity_plus/latest/connectivity_plus/connectivity_plus-library.html)
- [Plugin documentation website](https://plus.fluttercommunity.dev/docs/connectivity_plus/overview)

View File

@ -0,0 +1,47 @@
group 'io.flutter.plugins.connectivity'
version '1.0-SNAPSHOT'
buildscript {
repositories {
google()
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:4.1.0'
}
}
rootProject.allprojects {
repositories {
google()
mavenCentral()
}
}
apply plugin: 'com.android.library'
android {
compileSdkVersion 31
// as third_party include, don't need seperate namespace
//namespace 'dev.fluttercommunity.plus.connectivity'
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
defaultConfig {
minSdkVersion 16
targetSdkVersion 31
//testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
lintOptions {
disable 'InvalidPackage'
abortOnError false
}
}

View File

@ -0,0 +1 @@
org.gradle.jvmargs=-Xmx1536M

View File

@ -0,0 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-bin.zip
distributionPath=wrapper/dists
zipStorePath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME

View File

@ -0,0 +1 @@
rootProject.name = 'connectivity'

View File

@ -0,0 +1,4 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="dev.fluttercommunity.plus.connectivity">
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
</manifest>

View File

@ -0,0 +1,62 @@
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package dev.fluttercommunity.plus.connectivity;
import android.net.ConnectivityManager;
import android.net.Network;
import android.net.NetworkCapabilities;
import android.os.Build;
/** Reports connectivity related information such as connectivity type and wifi information. */
public class Connectivity {
static final String CONNECTIVITY_NONE = "none";
static final String CONNECTIVITY_MOBILE = "mobile";
private final ConnectivityManager connectivityManager;
public Connectivity(ConnectivityManager connectivityManager) {
this.connectivityManager = connectivityManager;
}
String getNetworkType() {
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;
}
// Cwtch UI only needs to know if online or offline, not type
return CONNECTIVITY_MOBILE;
}
return getNetworkTypeLegacy();
}
@SuppressWarnings("deprecation")
private String getNetworkTypeLegacy() {
// 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();
switch (type) {
case ConnectivityManager.TYPE_BLUETOOTH:
case ConnectivityManager.TYPE_ETHERNET:
case ConnectivityManager.TYPE_WIFI:
case ConnectivityManager.TYPE_WIMAX:
case ConnectivityManager.TYPE_VPN:
case ConnectivityManager.TYPE_MOBILE:
case ConnectivityManager.TYPE_MOBILE_DUN:
case ConnectivityManager.TYPE_MOBILE_HIPRI:
return CONNECTIVITY_MOBILE;
default:
return CONNECTIVITY_NONE;
}
}
public ConnectivityManager getConnectivityManager() {
return connectivityManager;
}
}

View File

@ -0,0 +1,94 @@
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package dev.fluttercommunity.plus.connectivity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.ConnectivityManager;
import android.net.Network;
import android.os.Build;
import android.os.Handler;
import android.os.Looper;
import io.flutter.plugin.common.EventChannel;
/**
* The ConnectivityBroadcastReceiver receives the connectivity updates and send them to the UIThread
* through an {@link EventChannel.EventSink}
*
* <p>Use {@link
* io.flutter.plugin.common.EventChannel#setStreamHandler(io.flutter.plugin.common.EventChannel.StreamHandler)}
* to set up the receiver.
*/
public class ConnectivityBroadcastReceiver extends BroadcastReceiver
implements EventChannel.StreamHandler {
private final Context context;
private final Connectivity connectivity;
private EventChannel.EventSink events;
private final Handler mainHandler = new Handler(Looper.getMainLooper());
private ConnectivityManager.NetworkCallback networkCallback;
public static final String CONNECTIVITY_ACTION = "android.net.conn.CONNECTIVITY_CHANGE";
public ConnectivityBroadcastReceiver(Context context, Connectivity connectivity) {
this.context = context;
this.connectivity = connectivity;
}
@Override
public void onListen(Object arguments, EventChannel.EventSink events) {
this.events = events;
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
networkCallback =
new ConnectivityManager.NetworkCallback() {
@Override
public void onAvailable(Network network) {
sendEvent();
}
@Override
public void onLost(Network network) {
sendEvent(Connectivity.CONNECTIVITY_NONE);
}
};
connectivity.getConnectivityManager().registerDefaultNetworkCallback(networkCallback);
} else {
context.registerReceiver(this, new IntentFilter(CONNECTIVITY_ACTION));
}
}
@Override
public void onCancel(Object arguments) {
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
if (networkCallback != null) {
connectivity.getConnectivityManager().unregisterNetworkCallback(networkCallback);
networkCallback = null;
}
} else {
try {
context.unregisterReceiver(this);
} catch (Exception e) {
//listen never called, ignore the error
}
}
}
@Override
public void onReceive(Context context, Intent intent) {
if (events != null) {
events.success(connectivity.getNetworkType());
}
}
private void sendEvent() {
Runnable runnable = () -> events.success(connectivity.getNetworkType());
mainHandler.post(runnable);
}
private void sendEvent(final String networkType) {
Runnable runnable = () -> events.success(networkType);
mainHandler.post(runnable);
}
}

View File

@ -0,0 +1,37 @@
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package dev.fluttercommunity.plus.connectivity;
import androidx.annotation.NonNull;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;
/**
* The handler receives {@link MethodCall}s from the UIThread, gets the related information from
* a @{@link Connectivity}, and then send the result back to the UIThread through the {@link
* MethodChannel.Result}.
*/
class ConnectivityMethodChannelHandler implements MethodChannel.MethodCallHandler {
private final Connectivity connectivity;
/**
* Construct the ConnectivityMethodChannelHandler with a {@code connectivity}. The {@code
* connectivity} must not be null.
*/
ConnectivityMethodChannelHandler(Connectivity connectivity) {
assert (connectivity != null);
this.connectivity = connectivity;
}
@Override
public void onMethodCall(MethodCall call, @NonNull MethodChannel.Result result) {
if ("check".equals(call.method)) {
result.success(connectivity.getNetworkType());
} else {
result.notImplemented();
}
}
}

View File

@ -0,0 +1,56 @@
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package dev.fluttercommunity.plus.connectivity;
import android.content.Context;
import android.net.ConnectivityManager;
import androidx.annotation.NonNull;
import io.flutter.embedding.engine.plugins.FlutterPlugin;
import io.flutter.plugin.common.BinaryMessenger;
import io.flutter.plugin.common.EventChannel;
import io.flutter.plugin.common.MethodChannel;
/** ConnectivityPlugin */
public class ConnectivityPlugin implements FlutterPlugin {
private MethodChannel methodChannel;
private EventChannel eventChannel;
private ConnectivityBroadcastReceiver receiver;
@Override
public void onAttachedToEngine(FlutterPluginBinding binding) {
setupChannels(binding.getBinaryMessenger(), binding.getApplicationContext());
}
@Override
public void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) {
teardownChannels();
}
private void setupChannels(BinaryMessenger messenger, Context context) {
methodChannel = new MethodChannel(messenger, "dev.fluttercommunity.plus/connectivity");
eventChannel = new EventChannel(messenger, "dev.fluttercommunity.plus/connectivity_status");
ConnectivityManager connectivityManager =
(ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
Connectivity connectivity = new Connectivity(connectivityManager);
ConnectivityMethodChannelHandler methodChannelHandler =
new ConnectivityMethodChannelHandler(connectivity);
receiver = new ConnectivityBroadcastReceiver(context, connectivity);
methodChannel.setMethodCallHandler(methodChannelHandler);
eventChannel.setStreamHandler(receiver);
}
private void teardownChannels() {
methodChannel.setMethodCallHandler(null);
eventChannel.setStreamHandler(null);
receiver.onCancel(null);
methodChannel = null;
eventChannel = null;
receiver = null;
}
}

View File

@ -0,0 +1,4 @@
#import <Flutter/Flutter.h>
@interface ConnectivityPlusPlugin : NSObject <FlutterPlugin>
@end

View File

@ -0,0 +1,15 @@
#import "ConnectivityPlusPlugin.h"
#if __has_include(<connectivity_plus/connectivity_plus-Swift.h>)
#import <connectivity_plus/connectivity_plus-Swift.h>
#else
// Support project import fallback if the generated compatibility header
// is not copied when this plugin is created as a library.
// https://forums.swift.org/t/swift-static-libraries-dont-copy-generated-objective-c-header/19816
#import "connectivity_plus-Swift.h"
#endif
@implementation ConnectivityPlusPlugin
+ (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar> *)registrar {
[SwiftConnectivityPlusPlugin registerWithRegistrar:registrar];
}
@end

View File

@ -0,0 +1,21 @@
import Foundation
public enum ConnectivityType {
case none
case wiredEthernet
case wifi
case cellular
case other
}
public protocol ConnectivityProvider: NSObjectProtocol {
typealias ConnectivityUpdateHandler = (ConnectivityType) -> Void
var currentConnectivityType: ConnectivityType { get }
var connectivityUpdateHandler: ConnectivityUpdateHandler? { get set }
func start()
func stop()
}

View File

@ -0,0 +1,60 @@
import Foundation
import Network
@available(iOS 12, *)
public class PathMonitorConnectivityProvider: NSObject, ConnectivityProvider {
private let queue = DispatchQueue.global(qos: .background)
private var _pathMonitor: NWPathMonitor?
public var currentConnectivityType: ConnectivityType {
let path = ensurePathMonitor().currentPath
// .satisfied means that the network is available
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
}
}
return .none
}
public var connectivityUpdateHandler: ConnectivityUpdateHandler?
override init() {
super.init()
_ = ensurePathMonitor()
}
public func start() {
_ = ensurePathMonitor()
}
public func stop() {
_pathMonitor?.cancel()
_pathMonitor = nil
}
@discardableResult
private func ensurePathMonitor() -> NWPathMonitor {
if (_pathMonitor == nil) {
let pathMonitor = NWPathMonitor()
pathMonitor.start(queue: queue)
pathMonitor.pathUpdateHandler = pathUpdateHandler
_pathMonitor = pathMonitor
}
return _pathMonitor!
}
private func pathUpdateHandler(path: NWPath) {
connectivityUpdateHandler?(currentConnectivityType)
}
}

View File

@ -0,0 +1,59 @@
import Foundation
import Reachability
public class ReachabilityConnectivityProvider: NSObject, ConnectivityProvider {
private var _reachability: Reachability?
public var currentConnectivityType: ConnectivityType {
let reachability = ensureReachability()
switch reachability.connection {
case .wifi:
return .wifi
case .cellular:
return .cellular
default:
return .none
}
}
public var connectivityUpdateHandler: ConnectivityUpdateHandler?
override init() {
super.init()
_ = ensureReachability()
}
public func start() {
let reachability = ensureReachability()
NotificationCenter.default.addObserver(
self,
selector: #selector(reachabilityChanged),
name: .reachabilityChanged,
object: reachability)
try? reachability.startNotifier()
}
public func stop() {
NotificationCenter.default.removeObserver(
self,
name: .reachabilityChanged,
object: _reachability)
_reachability?.stopNotifier()
_reachability = nil
}
private func ensureReachability() -> Reachability {
if (_reachability == nil) {
let reachability = try? Reachability()
_reachability = reachability
}
return _reachability!
}
@objc private func reachabilityChanged(notification: NSNotification) {
connectivityUpdateHandler?(currentConnectivityType)
}
}

View File

@ -0,0 +1,89 @@
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source is governed by a BSD-style license that can
// be found in the LICENSE file.
import Flutter
public class SwiftConnectivityPlusPlugin: NSObject, FlutterPlugin, FlutterStreamHandler {
private let connectivityProvider: ConnectivityProvider
private var eventSink: FlutterEventSink?
init(connectivityProvider: ConnectivityProvider) {
self.connectivityProvider = connectivityProvider
super.init()
self.connectivityProvider.connectivityUpdateHandler = connectivityUpdateHandler
}
public static func register(with registrar: FlutterPluginRegistrar) {
let channel = FlutterMethodChannel(
name: "dev.fluttercommunity.plus/connectivity",
binaryMessenger: registrar.messenger())
let streamChannel = FlutterEventChannel(
name: "dev.fluttercommunity.plus/connectivity_status",
binaryMessenger: registrar.messenger())
let connectivityProvider: ConnectivityProvider
if #available(iOS 12, *) {
connectivityProvider = PathMonitorConnectivityProvider()
} else {
connectivityProvider = ReachabilityConnectivityProvider()
}
let instance = SwiftConnectivityPlusPlugin(connectivityProvider: connectivityProvider)
streamChannel.setStreamHandler(instance)
registrar.addMethodCallDelegate(instance, channel: channel)
}
public func detachFromEngine(for registrar: FlutterPluginRegistrar) {
eventSink = nil
connectivityProvider.stop()
}
public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
switch call.method {
case "check":
result(statusFrom(connectivityType: connectivityProvider.currentConnectivityType))
default:
result(FlutterMethodNotImplemented)
}
}
private func statusFrom(connectivityType: ConnectivityType) -> String {
switch connectivityType {
case .wifi:
return "wifi"
case .cellular:
return "mobile"
case .wiredEthernet:
return "ethernet"
case .other:
return "other"
case .none:
return "none"
}
}
public func onListen(
withArguments _: Any?,
eventSink events: @escaping FlutterEventSink
) -> FlutterError? {
eventSink = events
connectivityProvider.start()
connectivityUpdateHandler(connectivityType: connectivityProvider.currentConnectivityType)
return nil
}
private func connectivityUpdateHandler(connectivityType: ConnectivityType) {
DispatchQueue.main.async {
self.eventSink?(self.statusFrom(connectivityType: connectivityType))
}
}
public func onCancel(withArguments _: Any?) -> FlutterError? {
connectivityProvider.stop()
eventSink = nil
return nil
}
}

View File

@ -0,0 +1,24 @@
#
# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html
#
Pod::Spec.new do |s|
s.name = 'connectivity_plus'
s.version = '0.0.1'
s.summary = 'Flutter Connectivity'
s.description = <<-DESC
This plugin allows Flutter apps to discover network connectivity and configure themselves accordingly.
Downloaded by pub (not CocoaPods).
DESC
s.homepage = 'https://plus.fluttercommunity.dev/'
s.license = { :type => 'BSD', :file => '../LICENSE' }
s.author = { 'Flutter Community Team' => 'authors@fluttercommunity.dev' }
s.source = { :http => 'https://github.com/fluttercommunity/plus_plugins' }
s.documentation_url = 'https://pub.dev/packages/connectivity_plus'
s.source_files = 'Classes/**/*'
s.public_header_files = 'Classes/**/*.h'
s.dependency 'Flutter'
s.dependency 'ReachabilitySwift'
s.platform = :ios, '9.0'
s.swift_version = '5.0'
s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES', 'VALID_ARCHS[sdk=iphonesimulator*]' => 'x86_64' }
end

View File

@ -0,0 +1,54 @@
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:async';
import 'package:connectivity_plus_platform_interface/connectivity_plus_platform_interface.dart';
// Export enums from the platform_interface so plugin users can use them directly.
export 'package:connectivity_plus_platform_interface/connectivity_plus_platform_interface.dart'
show ConnectivityResult;
export 'src/connectivity_plus_linux.dart';
/// Discover network connectivity configurations: Distinguish between WI-FI and cellular, check WI-FI status and more.
class Connectivity {
/// Constructs a singleton instance of [Connectivity].
///
/// [Connectivity] is designed to work as a singleton.
// When a second instance is created, the first instance will not be able to listen to the
// EventChannel because it is overridden. Forcing the class to be a singleton class can prevent
// misuse of creating a second instance from a programmer.
factory Connectivity() {
_singleton ??= Connectivity._();
return _singleton!;
}
Connectivity._();
static Connectivity? _singleton;
static ConnectivityPlatform get _platform {
return ConnectivityPlatform.instance;
}
/// Fires whenever the connectivity state changes.
///
/// 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 {
return _platform.onConnectivityChanged;
}
/// Checks the connection status of the device.
///
/// Do not use the result of this function to decide whether you can reliably
/// make a network request. It only gives you the radio status.
///
/// Instead listen for connectivity changes via [onConnectivityChanged] stream.
Future<ConnectivityResult> checkConnectivity() {
return _platform.checkConnectivity();
}
}

View File

@ -0,0 +1,74 @@
import 'dart:async';
import 'package:connectivity_plus_platform_interface/connectivity_plus_platform_interface.dart';
import 'package:meta/meta.dart';
import 'package:cwtch/third_party/nm/nm.dart';
// Used internally
// ignore_for_file: public_member_api_docs
@visibleForTesting
typedef NetworkManagerClientFactory = NetworkManagerClient Function();
/// The Linux implementation of ConnectivityPlatform.
class ConnectivityPlusLinuxPlugin extends ConnectivityPlatform {
/// Register this dart class as the platform implementation for linux
static void registerWith() {
ConnectivityPlatform.instance = ConnectivityPlusLinuxPlugin();
}
/// Checks the connection status of the device.
@override
Future<ConnectivityResult> checkConnectivity() async {
final client = createClient();
await client.connect();
final connectivity = _getConnectivity(client);
await client.close();
return connectivity;
}
NetworkManagerClient? _client;
StreamController<ConnectivityResult>? _controller;
/// Returns a Stream of ConnectivityResults changes.
@override
Stream<ConnectivityResult> get onConnectivityChanged {
_controller ??= StreamController<ConnectivityResult>.broadcast(
onListen: _startListenConnectivity,
onCancel: _stopListenConnectivity,
);
return _controller!.stream;
}
ConnectivityResult _getConnectivity(NetworkManagerClient client) {
if (client.connectivity != NetworkManagerConnectivityState.full) {
return ConnectivityResult.none;
}
// Open privacy update: we only need online/offline, so deleting type specificity
return ConnectivityResult.mobile;
}
Future<void> _startListenConnectivity() async {
_client ??= createClient();
await _client!.connect();
_addConnectivity(_client!);
_client!.propertiesChanged.listen((properties) {
if (properties.contains('Connectivity')) {
_addConnectivity(_client!);
}
});
}
void _addConnectivity(NetworkManagerClient client) {
_controller!.add(_getConnectivity(client));
}
Future<void> _stopListenConnectivity() async {
await _client?.close();
_client = null;
}
@visibleForTesting
// ignore: prefer_function_declarations_over_variables
NetworkManagerClientFactory createClient = () => NetworkManagerClient();
}

View File

@ -0,0 +1,90 @@
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source is governed by a BSD-style license that can
// be found in the LICENSE file.
import Cocoa
import FlutterMacOS
public class ConnectivityPlugin: NSObject, FlutterPlugin, FlutterStreamHandler {
private let connectivityProvider: ConnectivityProvider
private var eventSink: FlutterEventSink?
init(connectivityProvider: ConnectivityProvider) {
self.connectivityProvider = connectivityProvider
super.init()
self.connectivityProvider.connectivityUpdateHandler = connectivityUpdateHandler
}
public static func register(with registrar: FlutterPluginRegistrar) {
let channel = FlutterMethodChannel(
name: "dev.fluttercommunity.plus/connectivity",
binaryMessenger: registrar.messenger)
let streamChannel = FlutterEventChannel(
name: "dev.fluttercommunity.plus/connectivity_status",
binaryMessenger: registrar.messenger)
let connectivityProvider: ConnectivityProvider
if #available(macOS 10.14, *) {
connectivityProvider = PathMonitorConnectivityProvider()
} else {
connectivityProvider = ReachabilityConnectivityProvider()
}
let instance = ConnectivityPlugin(connectivityProvider: connectivityProvider)
streamChannel.setStreamHandler(instance)
registrar.addMethodCallDelegate(instance, channel: channel)
}
public func detachFromEngine(for registrar: FlutterPluginRegistrar) {
eventSink = nil
connectivityProvider.stop()
}
public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
switch call.method {
case "check":
result(statusFrom(connectivityType: connectivityProvider.currentConnectivityType))
default:
result(FlutterMethodNotImplemented)
}
}
private func statusFrom(connectivityType: ConnectivityType) -> String {
switch connectivityType {
case .wifi:
return "wifi"
case .cellular:
return "mobile"
case .wiredEthernet:
return "ethernet"
case .other:
return "other"
case .none:
return "none"
}
}
public func onListen(
withArguments _: Any?,
eventSink events: @escaping FlutterEventSink
) -> FlutterError? {
eventSink = events
connectivityProvider.start()
connectivityUpdateHandler(connectivityType: connectivityProvider.currentConnectivityType)
return nil
}
private func connectivityUpdateHandler(connectivityType: ConnectivityType) {
DispatchQueue.main.async {
self.eventSink?(self.statusFrom(connectivityType: connectivityType))
}
}
public func onCancel(withArguments _: Any?) -> FlutterError? {
connectivityProvider.stop()
eventSink = nil
return nil
}
}

View File

@ -0,0 +1,21 @@
import Foundation
public enum ConnectivityType {
case none
case wiredEthernet
case wifi
case cellular
case other
}
public protocol ConnectivityProvider: NSObjectProtocol {
typealias ConnectivityUpdateHandler = (ConnectivityType) -> Void
var currentConnectivityType: ConnectivityType { get }
var connectivityUpdateHandler: ConnectivityUpdateHandler? { get set }
func start()
func stop()
}

View File

@ -0,0 +1,57 @@
import Foundation
import Network
@available(macOS 10.14, *)
public class PathMonitorConnectivityProvider: NSObject, ConnectivityProvider {
private let queue = DispatchQueue.global(qos: .background)
private var _pathMonitor: NWPathMonitor?
public var currentConnectivityType: ConnectivityType {
let path = ensurePathMonitor().currentPath
// .satisfied means that the network is available
if path.status == .satisfied {
if path.usesInterfaceType(.wifi) {
return .wifi
} else if path.usesInterfaceType(.cellular) {
return .cellular
} else if path.usesInterfaceType(.wiredEthernet) {
return .wiredEthernet
} else if path.usesInterfaceType(.other) {
return .other
}
}
return .none
}
public var connectivityUpdateHandler: ConnectivityUpdateHandler?
override init() {
super.init()
_ = ensurePathMonitor()
}
public func start() {
_ = ensurePathMonitor()
}
public func stop() {
_pathMonitor?.cancel()
_pathMonitor = nil
}
private func ensurePathMonitor() -> NWPathMonitor {
if (_pathMonitor == nil) {
let pathMonitor = NWPathMonitor()
pathMonitor.start(queue: queue)
pathMonitor.pathUpdateHandler = pathUpdateHandler
_pathMonitor = pathMonitor
}
return _pathMonitor!
}
private func pathUpdateHandler(path: NWPath) {
connectivityUpdateHandler?(currentConnectivityType)
}
}

View File

@ -0,0 +1,59 @@
import Foundation
import Reachability
public class ReachabilityConnectivityProvider: NSObject, ConnectivityProvider {
private var _reachability: Reachability?
public var currentConnectivityType: ConnectivityType {
let reachability = ensureReachability()
switch reachability.connection {
case .wifi:
return .wifi
case .cellular:
return .cellular
default:
return .none
}
}
public var connectivityUpdateHandler: ConnectivityUpdateHandler?
override init() {
super.init()
_ = ensureReachability()
}
public func start() {
let reachability = ensureReachability()
NotificationCenter.default.addObserver(
self,
selector: #selector(reachabilityChanged),
name: .reachabilityChanged,
object: reachability)
try? reachability.startNotifier()
}
public func stop() {
NotificationCenter.default.removeObserver(
self,
name: .reachabilityChanged,
object: _reachability)
_reachability?.stopNotifier()
_reachability = nil
}
private func ensureReachability() -> Reachability {
if (_reachability == nil) {
let reachability = try? Reachability()
_reachability = reachability
}
return _reachability!
}
@objc private func reachabilityChanged(notification: NSNotification) {
connectivityUpdateHandler?(currentConnectivityType)
}
}

View File

@ -0,0 +1,22 @@
#
# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html
#
Pod::Spec.new do |s|
s.name = 'connectivity_plus'
s.version = '0.0.1'
s.summary = 'Flutter plugin for checking connectivity'
s.description = <<-DESC
Desktop implementation of the connectivity plugin
DESC
s.homepage = 'https://plus.fluttercommunity.dev/'
s.license = { :type => 'BSD', :file => '../LICENSE' }
s.author = { 'Flutter Community Team' => 'authors@fluttercommunity.dev' }
s.source = { :http => 'https://github.com/fluttercommunity/plus_plugins' }
s.documentation_url = 'https://pub.dev/packages/connectivity_plus'
s.source_files = 'Classes/**/*'
s.dependency 'FlutterMacOS'
s.dependency 'ReachabilitySwift'
s.platform = :osx
s.osx.deployment_target = '10.11'
end

View File

@ -0,0 +1,45 @@
name: connectivity_plus
description: Flutter plugin for discovering the state of the network (WiFi & mobile/cellular) connectivity on Android and iOS.
version: 3.0.6
homepage: https://plus.fluttercommunity.dev/
repository: https://github.com/fluttercommunity/plus_plugins/tree/main/packages/
issue_tracker: https://github.com/fluttercommunity/plus_plugins/labels/connectivity_plus
environment:
sdk: ">=2.12.0 <3.0.0"
flutter: ">=2.11.0"
flutter:
plugin:
platforms:
android:
package: dev.fluttercommunity.plus.connectivity
pluginClass: ConnectivityPlugin
ios:
pluginClass: ConnectivityPlusPlugin
linux:
dartPluginClass: ConnectivityPlusLinuxPlugin
macos:
pluginClass: ConnectivityPlugin
windows:
pluginClass: ConnectivityPlusWindowsPlugin
dependencies:
flutter:
sdk: flutter
flutter_web_plugins:
sdk: flutter
connectivity_plus_platform_interface:
path: ./../connectivity_plus_platform_interface
js: ^0.6.3
meta: ^1.8.0
dev_dependencies:
flutter_test:
sdk: flutter
build_runner: ^2.1.11
dbus: ^0.7.5
flutter_lints: ^2.0.1
mockito: ^5.2.0
plugin_platform_interface: ^2.1.2
test: ^1.21.1

View File

@ -0,0 +1,17 @@
flutter/
# Visual Studio user-specific files.
*.suo
*.user
*.userosscache
*.sln.docstates
# Visual Studio build-related files.
x64/
x86/
# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
!*.[Cc]ache/

View File

@ -0,0 +1,29 @@
cmake_minimum_required(VERSION 3.15)
set(PROJECT_NAME "connectivity_plus")
project(${PROJECT_NAME} LANGUAGES CXX)
# This value is used when generating builds using this plugin, so it must
# not be changed
set(PLUGIN_NAME "connectivity_plus_plugin")
add_library(${PLUGIN_NAME} SHARED
"connectivity_plus_plugin.cpp"
"network_manager.cpp"
)
apply_standard_settings(${PLUGIN_NAME})
set_target_properties(${PLUGIN_NAME} PROPERTIES
CXX_VISIBILITY_PRESET hidden)
target_compile_definitions(${PLUGIN_NAME} PRIVATE FLUTTER_PLUGIN_IMPL)
target_include_directories(${PLUGIN_NAME} INTERFACE
"${CMAKE_CURRENT_SOURCE_DIR}/include")
target_link_libraries(${PLUGIN_NAME} PRIVATE
flutter
flutter_wrapper_plugin
iphlpapi
)
# List of absolute paths to libraries that should be bundled with the plugin
set(connectivity_plus_bundled_libraries
""
PARENT_SCOPE
)

View File

@ -0,0 +1,171 @@
// clang-format off
#include "include/connectivity_plus/network_manager.h"
// clang-format on
#include "include/connectivity_plus/connectivity_plus_windows_plugin.h"
#include <flutter/event_channel.h>
#include <flutter/event_sink.h>
#include <flutter/event_stream_handler.h>
#include <flutter/method_channel.h>
#include <flutter/plugin_registrar_windows.h>
#include <flutter/standard_method_codec.h>
#include <functional>
#include <memory>
namespace {
typedef flutter::EventChannel<flutter::EncodableValue> FlEventChannel;
typedef flutter::EventSink<flutter::EncodableValue> FlEventSink;
typedef flutter::MethodCall<flutter::EncodableValue> FlMethodCall;
typedef flutter::MethodResult<flutter::EncodableValue> FlMethodResult;
typedef flutter::MethodChannel<flutter::EncodableValue> FlMethodChannel;
typedef flutter::StreamHandler<flutter::EncodableValue> FlStreamHandler;
typedef flutter::StreamHandlerError<flutter::EncodableValue>
FlStreamHandlerError;
class ConnectivityPlusWindowsPlugin : public flutter::Plugin {
public:
ConnectivityPlusWindowsPlugin();
virtual ~ConnectivityPlusWindowsPlugin();
std::shared_ptr<NetworkManager> GetManager() const;
static void RegisterWithRegistrar(flutter::PluginRegistrarWindows *registrar);
private:
void HandleMethodCall(const FlMethodCall &method_call,
std::unique_ptr<FlMethodResult> result);
std::shared_ptr<NetworkManager> manager;
};
class ConnectivityStreamHandler : public FlStreamHandler {
public:
ConnectivityStreamHandler(std::shared_ptr<NetworkManager> manager);
virtual ~ConnectivityStreamHandler();
protected:
void AddConnectivityEvent();
std::unique_ptr<FlStreamHandlerError>
OnListenInternal(const flutter::EncodableValue *arguments,
std::unique_ptr<FlEventSink> &&sink) override;
std::unique_ptr<FlStreamHandlerError>
OnCancelInternal(const flutter::EncodableValue *arguments) override;
private:
std::shared_ptr<NetworkManager> manager;
std::unique_ptr<FlEventSink> sink;
};
ConnectivityPlusWindowsPlugin::ConnectivityPlusWindowsPlugin() {
manager = std::make_shared<NetworkManager>();
manager->Init();
}
ConnectivityPlusWindowsPlugin::~ConnectivityPlusWindowsPlugin() {
manager->Cleanup();
}
std::shared_ptr<NetworkManager>
ConnectivityPlusWindowsPlugin::GetManager() const {
return manager;
}
void ConnectivityPlusWindowsPlugin::RegisterWithRegistrar(
flutter::PluginRegistrarWindows *registrar) {
auto plugin = std::make_unique<ConnectivityPlusWindowsPlugin>();
auto methodChannel =
std::make_unique<flutter::MethodChannel<flutter::EncodableValue>>(
registrar->messenger(), "dev.fluttercommunity.plus/connectivity",
&flutter::StandardMethodCodec::GetInstance());
methodChannel->SetMethodCallHandler(
[plugin_pointer = plugin.get()](const auto &call, auto result) {
plugin_pointer->HandleMethodCall(call, std::move(result));
});
auto eventChannel = std::make_unique<FlEventChannel>(
registrar->messenger(), "dev.fluttercommunity.plus/connectivity_status",
&flutter::StandardMethodCodec::GetInstance());
eventChannel->SetStreamHandler(
std::make_unique<ConnectivityStreamHandler>(plugin->GetManager()));
registrar->AddPlugin(std::move(plugin));
}
static std::string ConnectivityToString(ConnectivityType connectivityType) {
switch (connectivityType) {
case ConnectivityType::WiFi:
return "wifi";
case ConnectivityType::Ethernet:
return "ethernet";
case ConnectivityType::None:
default:
return "none";
}
}
void ConnectivityPlusWindowsPlugin::HandleMethodCall(
const flutter::MethodCall<flutter::EncodableValue> &method_call,
std::unique_ptr<flutter::MethodResult<flutter::EncodableValue>> result) {
if (method_call.method_name().compare("check") == 0) {
std::string connectivity =
ConnectivityToString(manager->GetConnectivityType());
result->Success(flutter::EncodableValue(connectivity));
} else {
result->NotImplemented();
}
}
ConnectivityStreamHandler::ConnectivityStreamHandler(
std::shared_ptr<NetworkManager> manager)
: manager(manager) {}
ConnectivityStreamHandler::~ConnectivityStreamHandler() {}
void ConnectivityStreamHandler::AddConnectivityEvent() {
std::string connectivity =
ConnectivityToString(manager->GetConnectivityType());
sink->Success(flutter::EncodableValue(connectivity));
}
std::unique_ptr<FlStreamHandlerError>
ConnectivityStreamHandler::OnListenInternal(
const flutter::EncodableValue *arguments,
std::unique_ptr<FlEventSink> &&events) {
sink = std::move(events);
auto callback =
std::bind(&ConnectivityStreamHandler::AddConnectivityEvent, this);
if (!manager->StartListen(callback)) {
return std::make_unique<FlStreamHandlerError>(
std::to_string(manager->GetError()), "NetworkManager::StartListen",
nullptr);
}
AddConnectivityEvent();
return nullptr;
}
std::unique_ptr<FlStreamHandlerError>
ConnectivityStreamHandler::OnCancelInternal(
const flutter::EncodableValue *arguments) {
manager->StopListen();
sink.reset();
return nullptr;
}
} // namespace
void ConnectivityPlusWindowsPluginRegisterWithRegistrar(
FlutterDesktopPluginRegistrarRef registrar) {
ConnectivityPlusWindowsPlugin::RegisterWithRegistrar(
flutter::PluginRegistrarManager::GetInstance()
->GetRegistrar<flutter::PluginRegistrarWindows>(registrar));
}

View File

@ -0,0 +1,23 @@
#ifndef FLUTTER_PLUGIN_CONNECTIVITY_WINDOWS_PLUS_PLUGIN_H_
#define FLUTTER_PLUGIN_CONNECTIVITY_WINDOWS_PLUS_PLUGIN_H_
#include <flutter_plugin_registrar.h>
#ifdef FLUTTER_PLUGIN_IMPL
#define FLUTTER_PLUGIN_EXPORT __declspec(dllexport)
#else
#define FLUTTER_PLUGIN_EXPORT __declspec(dllimport)
#endif
#if defined(__cplusplus)
extern "C" {
#endif
FLUTTER_PLUGIN_EXPORT void ConnectivityPlusWindowsPluginRegisterWithRegistrar(
FlutterDesktopPluginRegistrarRef registrar);
#if defined(__cplusplus)
} // extern "C"
#endif
#endif // FLUTTER_PLUGIN_CONNECTIVITY_PLUS_WINDOWS_PLUGIN_H_

View File

@ -0,0 +1,49 @@
#ifndef NETWORK_MANAGER_H
#define NETWORK_MANAGER_H
// clang-format off
#include <winsock2.h>
// clang-format on
#include <windows.h>
#include <functional>
#include <string>
enum class ConnectivityType { None, Ethernet, WiFi };
class NetworkListener;
struct IConnectionPoint;
struct IConnectionPointContainer;
struct INetworkListManager;
struct IUnknown;
typedef std::function<void()> NetworkCallback;
class NetworkManager {
public:
NetworkManager();
~NetworkManager();
bool Init();
void Cleanup();
ConnectivityType GetConnectivityType() const;
bool StartListen(NetworkCallback pCallback);
void StopListen();
bool HasError() const;
int GetError() const;
private:
std::vector<GUID> GetConnectedAdapterIds() const;
DWORD dwCookie = 0;
IUnknown *pUnknown = NULL;
INetworkListManager *pNetworkListManager = NULL;
IConnectionPointContainer *pCPContainer = NULL;
IConnectionPoint *pConnectPoint = NULL;
NetworkListener *pListener = NULL;
};
#endif // NETWORK_MANAGER_H

View File

@ -0,0 +1,243 @@
// based on
// https://github.com/PurpleI2P/i2pd/blob/master/Win32/Win32NetState.cpp
/*
* Copyright (c) 2013-2020, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
* See full license text in LICENSE file at top of project tree
*/
#include "include/connectivity_plus/network_manager.h"
#include <iphlpapi.h>
#include <netlistmgr.h>
#include <ocidl.h>
#include <cassert>
#include <set>
class NetworkListener final : public INetworkEvents {
public:
NetworkListener(NetworkCallback pCb) : pCallback(pCb) {}
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject) {
AddRef();
HRESULT hr = S_OK;
if (IsEqualIID(riid, IID_IUnknown)) {
*ppvObject = (IUnknown *)this;
} else if (IsEqualIID(riid, IID_INetworkEvents)) {
*ppvObject = (INetworkEvents *)this;
} else {
hr = E_NOINTERFACE;
}
return hr;
}
ULONG STDMETHODCALLTYPE AddRef() { return InterlockedIncrement(&lRef); }
ULONG STDMETHODCALLTYPE Release() {
LONG lAddend = InterlockedDecrement(&lRef);
if (lRef == 0) {
delete this;
}
return lAddend;
}
HRESULT STDMETHODCALLTYPE NetworkAdded(GUID networkId) { return S_OK; }
HRESULT STDMETHODCALLTYPE
NetworkConnectivityChanged(GUID networkId, NLM_CONNECTIVITY newConnectivity) {
Callback();
return S_OK;
}
HRESULT STDMETHODCALLTYPE NetworkDeleted(GUID networkId) { return S_OK; }
HRESULT STDMETHODCALLTYPE
NetworkPropertyChanged(GUID networkId, NLM_NETWORK_PROPERTY_CHANGE flags) {
if (flags & NLM_NETWORK_PROPERTY_CHANGE_CONNECTION) {
Callback();
}
return S_OK;
}
void Callback() {
assert(pCallback);
pCallback();
}
private:
volatile LONG lRef = 1;
NetworkCallback pCallback = nullptr;
};
NetworkManager::NetworkManager() {}
NetworkManager::~NetworkManager() {
StopListen();
Cleanup();
}
bool NetworkManager::Init() {
CoInitialize(NULL);
HRESULT hr = CoCreateInstance(CLSID_NetworkListManager, NULL, CLSCTX_ALL,
IID_IUnknown, (void **)&pUnknown);
if (SUCCEEDED(hr)) {
hr = pUnknown->QueryInterface(IID_INetworkListManager,
(void **)&pNetworkListManager);
}
return SUCCEEDED(hr);
}
void NetworkManager::Cleanup() {
if (pNetworkListManager) {
pNetworkListManager->Release();
pNetworkListManager = NULL;
}
if (pUnknown) {
pUnknown->Release();
pUnknown = NULL;
}
CoUninitialize();
}
std::vector<GUID> NetworkManager::GetConnectedAdapterIds() const {
std::vector<GUID> adapterIds;
IEnumNetworkConnections *connections = NULL;
HRESULT hr = pNetworkListManager->GetNetworkConnections(&connections);
if (hr == S_OK) {
while (true) {
INetworkConnection *connection = NULL;
hr = connections->Next(1, &connection, NULL);
if (hr != S_OK) {
break;
}
VARIANT_BOOL isConnected = VARIANT_FALSE;
hr = connection->get_IsConnectedToInternet(&isConnected);
if (hr == S_OK && isConnected == VARIANT_TRUE) {
GUID guid;
hr = connection->GetAdapterId(&guid);
if (hr == S_OK) {
adapterIds.push_back(std::move(guid));
}
}
connection->Release();
}
connections->Release();
}
return adapterIds;
}
ConnectivityType NetworkManager::GetConnectivityType() const {
ULONG bufferSize = 15 * 1024;
ULONG flags = GAA_FLAG_SKIP_UNICAST | GAA_FLAG_SKIP_ANYCAST |
GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER |
GAA_FLAG_SKIP_FRIENDLY_NAME;
std::vector<unsigned char> buffer(bufferSize);
PIP_ADAPTER_ADDRESSES addresses =
reinterpret_cast<PIP_ADAPTER_ADDRESSES>(&buffer.front());
DWORD rc = GetAdaptersAddresses(AF_UNSPEC, flags, 0, addresses, &bufferSize);
if (rc == ERROR_BUFFER_OVERFLOW) {
buffer.resize(bufferSize);
addresses = reinterpret_cast<PIP_ADAPTER_ADDRESSES>(&buffer.front());
rc = GetAdaptersAddresses(AF_UNSPEC, flags, 0, addresses, &bufferSize);
}
if (rc != NO_ERROR) {
return ConnectivityType::None;
}
std::vector<GUID> adapterIds = GetConnectedAdapterIds();
if (adapterIds.empty()) {
return ConnectivityType::None;
}
std::set<ConnectivityType> connectivities;
for (; addresses != NULL; addresses = addresses->Next) {
NET_LUID luid;
rc = ConvertInterfaceIndexToLuid(addresses->IfIndex, &luid);
if (rc != NO_ERROR) {
continue;
}
GUID guid;
rc = ConvertInterfaceLuidToGuid(&luid, &guid);
if (rc != NO_ERROR) {
continue;
}
if (std::find(adapterIds.begin(), adapterIds.end(), guid) !=
adapterIds.end()) {
switch (addresses->IfType) {
case IF_TYPE_ETHERNET_CSMACD:
connectivities.insert(ConnectivityType::Ethernet);
break;
default:
connectivities.insert(ConnectivityType::WiFi);
break;
}
}
}
if (connectivities.find(ConnectivityType::WiFi) != connectivities.end()) {
return ConnectivityType::WiFi;
}
if (connectivities.find(ConnectivityType::Ethernet) != connectivities.end()) {
return ConnectivityType::Ethernet;
}
return ConnectivityType::None;
}
bool NetworkManager::StartListen(NetworkCallback pCallback) {
if (!pCallback || pListener) {
return false;
}
HRESULT hr = pNetworkListManager->QueryInterface(
IID_IConnectionPointContainer, (void **)&pCPContainer);
if (SUCCEEDED(hr)) {
hr = pCPContainer->FindConnectionPoint(IID_INetworkEvents, &pConnectPoint);
if (SUCCEEDED(hr)) {
pListener = new NetworkListener(pCallback);
hr = pConnectPoint->Advise((IUnknown *)pListener, &dwCookie);
if (SUCCEEDED(hr)) {
return true;
}
}
}
return false;
}
void NetworkManager::StopListen() {
if (pConnectPoint) {
pConnectPoint->Unadvise(dwCookie);
pConnectPoint->Release();
pConnectPoint = NULL;
dwCookie = 0;
}
if (pCPContainer) {
pCPContainer->Release();
pCPContainer = NULL;
}
if (pListener) {
pListener->Release();
pListener = NULL;
}
}
bool NetworkManager::HasError() const { return GetLastError() != 0; }
int NetworkManager::GetError() const { return GetLastError(); }

View File

@ -0,0 +1,25 @@
# Auto detect text files and perform LF normalization
* text=auto
# Always perform LF normalization on these files
*.dart text
*.gradle text
*.html text
*.java text
*.json text
*.md text
*.py text
*.sh text
*.txt text
*.xml text
*.yaml text
# Make sure that these Windows files always have CRLF line endings in checkout
*.bat text eol=crlf
*.ps1 text eol=crlf
# Never perform LF normalization on these files
*.ico binary
*.jar binary
*.png binary
*.zip binary

View File

@ -0,0 +1,46 @@
.DS_Store
.atom/
.idea/
.vscode/
.packages
.pub/
.dart_tool/
pubspec.lock
flutter_export_environment.sh
examples/all_plugins/pubspec.yaml
Podfile
Podfile.lock
Pods/
.symlinks/
**/Flutter/App.framework/
**/Flutter/ephemeral/
**/Flutter/Flutter.framework/
**/Flutter/Generated.xcconfig
**/Flutter/flutter_assets/
ServiceDefinitions.json
xcuserdata/
**/DerivedData/
local.properties
keystore.properties
.gradle/
gradlew
gradlew.bat
gradle-wrapper.jar
.flutter-plugins-dependencies
*.iml
GeneratedPluginRegistrant.h
GeneratedPluginRegistrant.m
GeneratedPluginRegistrant.java
GeneratedPluginRegistrant.swift
build/
.flutter-plugins
.project
.classpath
.settings

View File

@ -0,0 +1,27 @@
Copyright 2020 The Chromium Authors. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@ -0,0 +1,12 @@
# Connectivity Plus Platform Interface
[![Flutter Community: connectivity_plus_platform_interface](https://fluttercommunity.dev/_github/header/connectivity_plus_platform_interface)](https://github.com/fluttercommunity/community)
[![pub package](https://img.shields.io/pub/v/connectivity_plus_platform_interface.svg)](https://pub.dev/packages/connectivity_plus_platform_interface)
A common platform interface for [`connectivity_plus`](https://pub.dev/packages/connectivity_plus).
## Usage
This package is already included as part of the `connectivity_plus` package dependency, and will
be included when using `connectivity_plus` as normal.

View File

@ -0,0 +1,51 @@
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:async';
import 'package:plugin_platform_interface/plugin_platform_interface.dart';
import 'method_channel_connectivity.dart';
import 'src/enums.dart';
export 'src/enums.dart';
/// The interface that implementations of connectivity must implement.
///
/// Platform implementations should extend this class rather than implement it as `Connectivity`
/// does not consider newly added methods to be breaking changes. Extending this class
/// (using `extends`) ensures that the subclass will get the default implementation, while
/// platform implementations that `implements` this interface will be broken by newly added
/// [ConnectivityPlatform] methods.
abstract class ConnectivityPlatform extends PlatformInterface {
/// Constructs a ConnectivityPlatform.
ConnectivityPlatform() : super(token: _token);
static final Object _token = Object();
static ConnectivityPlatform _instance = MethodChannelConnectivity();
/// The default instance of [ConnectivityPlatform] to use.
///
/// Defaults to [MethodChannelConnectivity].
static ConnectivityPlatform get instance => _instance;
/// Platform-specific plugins should set this with their own platform-specific
/// class that extends [ConnectivityPlatform] when they register themselves.
static set instance(ConnectivityPlatform instance) {
PlatformInterface.verifyToken(instance, _token);
_instance = instance;
}
/// Checks the connection status of the device.
Future<ConnectivityResult> checkConnectivity() {
throw UnimplementedError('checkConnectivity() has not been implemented.');
}
/// Returns a Stream of ConnectivityResults changes.
Stream<ConnectivityResult> get onConnectivityChanged {
throw UnimplementedError(
'get onConnectivityChanged has not been implemented.');
}
}

View File

@ -0,0 +1,43 @@
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:async';
import 'package:connectivity_plus_platform_interface/connectivity_plus_platform_interface.dart';
import 'package:flutter/services.dart';
import 'package:meta/meta.dart';
import 'src/utils.dart';
/// An implementation of [ConnectivityPlatform] that uses method channels.
class MethodChannelConnectivity extends ConnectivityPlatform {
/// The method channel used to interact with the native platform.
@visibleForTesting
MethodChannel methodChannel =
const MethodChannel('dev.fluttercommunity.plus/connectivity');
/// The event channel used to receive ConnectivityResult changes from the native platform.
@visibleForTesting
EventChannel eventChannel =
const EventChannel('dev.fluttercommunity.plus/connectivity_status');
Stream<ConnectivityResult>? _onConnectivityChanged;
/// Fires whenever the connectivity state changes.
@override
Stream<ConnectivityResult> get onConnectivityChanged {
_onConnectivityChanged ??= eventChannel
.receiveBroadcastStream()
.map((dynamic result) => result.toString())
.map(parseConnectivityResult);
return _onConnectivityChanged!;
}
@override
Future<ConnectivityResult> checkConnectivity() {
return methodChannel
.invokeMethod<String>('check')
.then((value) => parseConnectivityResult(value ?? ''));
}
}

View File

@ -0,0 +1,18 @@
/// Connection status check result.
enum ConnectivityResult {
/// WiFi: Device connected via Wi-Fi
wifi,
/// Ethernet: Device connected to ethernet network
ethernet,
/// Mobile: Device connected to cellular network
mobile,
/// None: Device not connected to any network
none,
/// Other: Device is connected to an unknown network
other
}

View File

@ -0,0 +1,17 @@
import 'package:connectivity_plus_platform_interface/connectivity_plus_platform_interface.dart';
/// Convert a String to a ConnectivityResult value.
ConnectivityResult parseConnectivityResult(String state) {
switch (state) {
case 'bluetooth':
case 'wifi':
case 'ethernet':
case 'mobile':
case 'vpn':
case 'other':
return ConnectivityResult.mobile;
case 'none':
default:
return ConnectivityResult.none;
}
}

View File

@ -0,0 +1,20 @@
name: connectivity_plus_platform_interface
description: A common platform interface for the connectivity_plus plugin.
version: 1.2.4
homepage: https://plus.fluttercommunity.dev/
repository: https://github.com/fluttercommunity/plus_plugins/tree/main/packages/
environment:
sdk: ">=2.12.0 <3.0.0"
flutter: ">=2.11.0"
dependencies:
flutter:
sdk: flutter
meta: ^1.7.0
plugin_platform_interface: ^2.1.2
dev_dependencies:
flutter_test:
sdk: flutter
flutter_lints: ^2.0.1

373
lib/third_party/nm/LICENSE vendored Normal file
View File

@ -0,0 +1,373 @@
Mozilla Public License Version 2.0
==================================
1. Definitions
--------------
1.1. "Contributor"
means each individual or legal entity that creates, contributes to
the creation of, or owns Covered Software.
1.2. "Contributor Version"
means the combination of the Contributions of others (if any) used
by a Contributor and that particular Contributor's Contribution.
1.3. "Contribution"
means Covered Software of a particular Contributor.
1.4. "Covered Software"
means Source Code Form to which the initial Contributor has attached
the notice in Exhibit A, the Executable Form of such Source Code
Form, and Modifications of such Source Code Form, in each case
including portions thereof.
1.5. "Incompatible With Secondary Licenses"
means
(a) that the initial Contributor has attached the notice described
in Exhibit B to the Covered Software; or
(b) that the Covered Software was made available under the terms of
version 1.1 or earlier of the License, but not also under the
terms of a Secondary License.
1.6. "Executable Form"
means any form of the work other than Source Code Form.
1.7. "Larger Work"
means a work that combines Covered Software with other material, in
a separate file or files, that is not Covered Software.
1.8. "License"
means this document.
1.9. "Licensable"
means having the right to grant, to the maximum extent possible,
whether at the time of the initial grant or subsequently, any and
all of the rights conveyed by this License.
1.10. "Modifications"
means any of the following:
(a) any file in Source Code Form that results from an addition to,
deletion from, or modification of the contents of Covered
Software; or
(b) any new file in Source Code Form that contains any Covered
Software.
1.11. "Patent Claims" of a Contributor
means any patent claim(s), including without limitation, method,
process, and apparatus claims, in any patent Licensable by such
Contributor that would be infringed, but for the grant of the
License, by the making, using, selling, offering for sale, having
made, import, or transfer of either its Contributions or its
Contributor Version.
1.12. "Secondary License"
means either the GNU General Public License, Version 2.0, the GNU
Lesser General Public License, Version 2.1, the GNU Affero General
Public License, Version 3.0, or any later versions of those
licenses.
1.13. "Source Code Form"
means the form of the work preferred for making modifications.
1.14. "You" (or "Your")
means an individual or a legal entity exercising rights under this
License. For legal entities, "You" includes any entity that
controls, is controlled by, or is under common control with You. For
purposes of this definition, "control" means (a) the power, direct
or indirect, to cause the direction or management of such entity,
whether by contract or otherwise, or (b) ownership of more than
fifty percent (50%) of the outstanding shares or beneficial
ownership of such entity.
2. License Grants and Conditions
--------------------------------
2.1. Grants
Each Contributor hereby grants You a world-wide, royalty-free,
non-exclusive license:
(a) under intellectual property rights (other than patent or trademark)
Licensable by such Contributor to use, reproduce, make available,
modify, display, perform, distribute, and otherwise exploit its
Contributions, either on an unmodified basis, with Modifications, or
as part of a Larger Work; and
(b) under Patent Claims of such Contributor to make, use, sell, offer
for sale, have made, import, and otherwise transfer either its
Contributions or its Contributor Version.
2.2. Effective Date
The licenses granted in Section 2.1 with respect to any Contribution
become effective for each Contribution on the date the Contributor first
distributes such Contribution.
2.3. Limitations on Grant Scope
The licenses granted in this Section 2 are the only rights granted under
this License. No additional rights or licenses will be implied from the
distribution or licensing of Covered Software under this License.
Notwithstanding Section 2.1(b) above, no patent license is granted by a
Contributor:
(a) for any code that a Contributor has removed from Covered Software;
or
(b) for infringements caused by: (i) Your and any other third party's
modifications of Covered Software, or (ii) the combination of its
Contributions with other software (except as part of its Contributor
Version); or
(c) under Patent Claims infringed by Covered Software in the absence of
its Contributions.
This License does not grant any rights in the trademarks, service marks,
or logos of any Contributor (except as may be necessary to comply with
the notice requirements in Section 3.4).
2.4. Subsequent Licenses
No Contributor makes additional grants as a result of Your choice to
distribute the Covered Software under a subsequent version of this
License (see Section 10.2) or under the terms of a Secondary License (if
permitted under the terms of Section 3.3).
2.5. Representation
Each Contributor represents that the Contributor believes its
Contributions are its original creation(s) or it has sufficient rights
to grant the rights to its Contributions conveyed by this License.
2.6. Fair Use
This License is not intended to limit any rights You have under
applicable copyright doctrines of fair use, fair dealing, or other
equivalents.
2.7. Conditions
Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
in Section 2.1.
3. Responsibilities
-------------------
3.1. Distribution of Source Form
All distribution of Covered Software in Source Code Form, including any
Modifications that You create or to which You contribute, must be under
the terms of this License. You must inform recipients that the Source
Code Form of the Covered Software is governed by the terms of this
License, and how they can obtain a copy of this License. You may not
attempt to alter or restrict the recipients' rights in the Source Code
Form.
3.2. Distribution of Executable Form
If You distribute Covered Software in Executable Form then:
(a) such Covered Software must also be made available in Source Code
Form, as described in Section 3.1, and You must inform recipients of
the Executable Form how they can obtain a copy of such Source Code
Form by reasonable means in a timely manner, at a charge no more
than the cost of distribution to the recipient; and
(b) You may distribute such Executable Form under the terms of this
License, or sublicense it under different terms, provided that the
license for the Executable Form does not attempt to limit or alter
the recipients' rights in the Source Code Form under this License.
3.3. Distribution of a Larger Work
You may create and distribute a Larger Work under terms of Your choice,
provided that You also comply with the requirements of this License for
the Covered Software. If the Larger Work is a combination of Covered
Software with a work governed by one or more Secondary Licenses, and the
Covered Software is not Incompatible With Secondary Licenses, this
License permits You to additionally distribute such Covered Software
under the terms of such Secondary License(s), so that the recipient of
the Larger Work may, at their option, further distribute the Covered
Software under the terms of either this License or such Secondary
License(s).
3.4. Notices
You may not remove or alter the substance of any license notices
(including copyright notices, patent notices, disclaimers of warranty,
or limitations of liability) contained within the Source Code Form of
the Covered Software, except that You may alter any license notices to
the extent required to remedy known factual inaccuracies.
3.5. Application of Additional Terms
You may choose to offer, and to charge a fee for, warranty, support,
indemnity or liability obligations to one or more recipients of Covered
Software. However, You may do so only on Your own behalf, and not on
behalf of any Contributor. You must make it absolutely clear that any
such warranty, support, indemnity, or liability obligation is offered by
You alone, and You hereby agree to indemnify every Contributor for any
liability incurred by such Contributor as a result of warranty, support,
indemnity or liability terms You offer. You may include additional
disclaimers of warranty and limitations of liability specific to any
jurisdiction.
4. Inability to Comply Due to Statute or Regulation
---------------------------------------------------
If it is impossible for You to comply with any of the terms of this
License with respect to some or all of the Covered Software due to
statute, judicial order, or regulation then You must: (a) comply with
the terms of this License to the maximum extent possible; and (b)
describe the limitations and the code they affect. Such description must
be placed in a text file included with all distributions of the Covered
Software under this License. Except to the extent prohibited by statute
or regulation, such description must be sufficiently detailed for a
recipient of ordinary skill to be able to understand it.
5. Termination
--------------
5.1. The rights granted under this License will terminate automatically
if You fail to comply with any of its terms. However, if You become
compliant, then the rights granted under this License from a particular
Contributor are reinstated (a) provisionally, unless and until such
Contributor explicitly and finally terminates Your grants, and (b) on an
ongoing basis, if such Contributor fails to notify You of the
non-compliance by some reasonable means prior to 60 days after You have
come back into compliance. Moreover, Your grants from a particular
Contributor are reinstated on an ongoing basis if such Contributor
notifies You of the non-compliance by some reasonable means, this is the
first time You have received notice of non-compliance with this License
from such Contributor, and You become compliant prior to 30 days after
Your receipt of the notice.
5.2. If You initiate litigation against any entity by asserting a patent
infringement claim (excluding declaratory judgment actions,
counter-claims, and cross-claims) alleging that a Contributor Version
directly or indirectly infringes any patent, then the rights granted to
You by any and all Contributors for the Covered Software under Section
2.1 of this License shall terminate.
5.3. In the event of termination under Sections 5.1 or 5.2 above, all
end user license agreements (excluding distributors and resellers) which
have been validly granted by You or Your distributors under this License
prior to termination shall survive termination.
************************************************************************
* *
* 6. Disclaimer of Warranty *
* ------------------------- *
* *
* Covered Software is provided under this License on an "as is" *
* basis, without warranty of any kind, either expressed, implied, or *
* statutory, including, without limitation, warranties that the *
* Covered Software is free of defects, merchantable, fit for a *
* particular purpose or non-infringing. The entire risk as to the *
* quality and performance of the Covered Software is with You. *
* Should any Covered Software prove defective in any respect, You *
* (not any Contributor) assume the cost of any necessary servicing, *
* repair, or correction. This disclaimer of warranty constitutes an *
* essential part of this License. No use of any Covered Software is *
* authorized under this License except under this disclaimer. *
* *
************************************************************************
************************************************************************
* *
* 7. Limitation of Liability *
* -------------------------- *
* *
* Under no circumstances and under no legal theory, whether tort *
* (including negligence), contract, or otherwise, shall any *
* Contributor, or anyone who distributes Covered Software as *
* permitted above, be liable to You for any direct, indirect, *
* special, incidental, or consequential damages of any character *
* including, without limitation, damages for lost profits, loss of *
* goodwill, work stoppage, computer failure or malfunction, or any *
* and all other commercial damages or losses, even if such party *
* shall have been informed of the possibility of such damages. This *
* limitation of liability shall not apply to liability for death or *
* personal injury resulting from such party's negligence to the *
* extent applicable law prohibits such limitation. Some *
* jurisdictions do not allow the exclusion or limitation of *
* incidental or consequential damages, so this exclusion and *
* limitation may not apply to You. *
* *
************************************************************************
8. Litigation
-------------
Any litigation relating to this License may be brought only in the
courts of a jurisdiction where the defendant maintains its principal
place of business and such litigation shall be governed by laws of that
jurisdiction, without reference to its conflict-of-law provisions.
Nothing in this Section shall prevent a party's ability to bring
cross-claims or counter-claims.
9. Miscellaneous
----------------
This License represents the complete agreement concerning the subject
matter hereof. If any provision of this License is held to be
unenforceable, such provision shall be reformed only to the extent
necessary to make it enforceable. Any law or regulation which provides
that the language of a contract shall be construed against the drafter
shall not be used to construe this License against a Contributor.
10. Versions of the License
---------------------------
10.1. New Versions
Mozilla Foundation is the license steward. Except as provided in Section
10.3, no one other than the license steward has the right to modify or
publish new versions of this License. Each version will be given a
distinguishing version number.
10.2. Effect of New Versions
You may distribute the Covered Software under the terms of the version
of the License under which You originally received the Covered Software,
or under the terms of any subsequent version published by the license
steward.
10.3. Modified Versions
If you create software not governed by this License, and you want to
create a new license for such software, you may create and use a
modified version of this License if you rename the license and remove
any references to the name of the license steward (except to note that
such modified license differs from this License).
10.4. Distributing Source Code Form that is Incompatible With Secondary
Licenses
If You choose to distribute Source Code Form that is Incompatible With
Secondary Licenses under the terms of this version of the License, the
notice described in Exhibit B of this License must be attached.
Exhibit A - Source Code Form License Notice
-------------------------------------------
This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this
file, You can obtain one at http://mozilla.org/MPL/2.0/.
If it is not possible or desirable to put the notice in a particular
file, then You may include the notice in a location (such as a LICENSE
file in a relevant directory) where a recipient would be likely to look
for such a notice.
You may add additional accurate notices of copyright ownership.
Exhibit B - "Incompatible With Secondary Licenses" Notice
---------------------------------------------------------
This Source Code Form is "Incompatible With Secondary Licenses", as
defined by the Mozilla Public License, v. 2.0.

1
lib/third_party/nm/nm.dart vendored Normal file
View File

@ -0,0 +1 @@
export 'src/network_manager_client.dart';

View File

@ -0,0 +1,415 @@
import 'dart:async';
import 'dart:io';
import 'package:dbus/dbus.dart';
/// D-Bus interface names
const _managerInterfaceName = 'org.freedesktop.NetworkManager';
/// Overall networking states.
enum NetworkManagerState {
unknown,
asleep,
disconnected,
disconnecting,
connecting,
connectedLocal,
connectedSite,
connectedGlobal,
}
NetworkManagerState _decodeState(int value) {
switch (value) {
case 10:
return NetworkManagerState.asleep;
case 20:
return NetworkManagerState.disconnected;
case 30:
return NetworkManagerState.disconnecting;
case 40:
return NetworkManagerState.connecting;
case 50:
return NetworkManagerState.connectedLocal;
case 60:
return NetworkManagerState.connectedSite;
case 70:
return NetworkManagerState.connectedGlobal;
default:
return NetworkManagerState.unknown;
}
}
/// Internet connectivity states.
enum NetworkManagerConnectivityState { unknown, none, portal, limited, full }
NetworkManagerConnectivityState _decodeConnectivityState(int value) {
switch (value) {
case 1:
return NetworkManagerConnectivityState.none;
case 2:
return NetworkManagerConnectivityState.portal;
case 3:
return NetworkManagerConnectivityState.limited;
case 4:
return NetworkManagerConnectivityState.full;
default:
return NetworkManagerConnectivityState.unknown;
}
}
class _NetworkManagerInterface {
final Map<String, DBusValue> properties;
final propertiesChangedStreamController =
StreamController<List<String>>.broadcast();
/// Stream of property names as their values change.
Stream<List<String>> get propertiesChanged =>
propertiesChangedStreamController.stream;
_NetworkManagerInterface(this.properties);
void updateProperties(Map<String, DBusValue> changedProperties) {
properties.addAll(changedProperties);
propertiesChangedStreamController.add(changedProperties.keys.toList());
}
}
class _NetworkManagerObject extends DBusRemoteObject {
final interfaces = <String, _NetworkManagerInterface>{};
void updateInterfaces(
Map<String, Map<String, DBusValue>> interfacesAndProperties) {
interfacesAndProperties.forEach((interfaceName, properties) {
interfaces[interfaceName] = _NetworkManagerInterface(properties);
});
}
/// Returns true if removing [interfaceNames] would remove all interfaces on this object.
bool wouldRemoveAllInterfaces(List<String> interfaceNames) {
for (var interface in interfaces.keys) {
if (!interfaceNames.contains(interface)) {
return false;
}
}
return true;
}
void removeInterfaces(List<String> interfaceNames) {
for (var interfaceName in interfaceNames) {
interfaces.remove(interfaceName);
}
}
void updateProperties(
String interfaceName, Map<String, DBusValue> changedProperties) {
var interface = interfaces[interfaceName];
if (interface != null) {
interface.updateProperties(changedProperties);
}
}
/// Gets a cached property.
DBusValue? getCachedProperty(String interfaceName, String name) {
var interface = interfaces[interfaceName];
if (interface == null) {
return null;
}
return interface.properties[name];
}
/// Gets a cached boolean property, or returns null if not present or not the correct type.
bool? getBooleanProperty(String interface, String name) {
var value = getCachedProperty(interface, name);
if (value == null) {
return null;
}
if (value.signature != DBusSignature('b')) {
return null;
}
return (value as DBusBoolean).value;
}
/// Gets a cached unsigned 8 bit integer property, or returns null if not present or not the correct type.
int? getByteProperty(String interface, String name) {
var value = getCachedProperty(interface, name);
if (value == null) {
return null;
}
if (value.signature != DBusSignature('y')) {
return null;
}
return (value as DBusByte).value;
}
/// Gets a cached signed 32 bit integer property, or returns null if not present or not the correct type.
int? getInt32Property(String interface, String name) {
var value = getCachedProperty(interface, name);
if (value == null) {
return null;
}
if (value.signature != DBusSignature('i')) {
return null;
}
return (value as DBusInt32).value;
}
/// Gets a cached unsigned 32 bit integer property, or returns null if not present or not the correct type.
int? getUint32Property(String interface, String name) {
var value = getCachedProperty(interface, name);
if (value == null) {
return null;
}
if (value.signature != DBusSignature('u')) {
return null;
}
return (value as DBusUint32).value;
}
/// Gets a cached signed 64 bit integer property, or returns null if not present or not the correct type.
int? getInt64Property(String interface, String name) {
var value = getCachedProperty(interface, name);
if (value == null) {
return null;
}
if (value.signature != DBusSignature('x')) {
return null;
}
return (value as DBusInt64).value;
}
/// Gets a cached unsigned 64 bit integer property, or returns null if not present or not the correct type.
int? getUint64Property(String interface, String name) {
var value = getCachedProperty(interface, name);
if (value == null) {
return null;
}
if (value.signature != DBusSignature('t')) {
return null;
}
return (value as DBusUint64).value;
}
/// Gets a cached string property, or returns null if not present or not the correct type.
String? getStringProperty(String interface, String name) {
var value = getCachedProperty(interface, name);
if (value == null) {
return null;
}
if (value.signature != DBusSignature('s')) {
return null;
}
return (value as DBusString).value;
}
/// Gets a cached string array property, or returns null if not present or not the correct type.
List<String>? getStringArrayProperty(String interface, String name) {
var value = getCachedProperty(interface, name);
if (value == null) {
return null;
}
if (value.signature != DBusSignature('as')) {
return null;
}
return (value as DBusArray)
.children
.map((e) => (e as DBusString).value)
.toList();
}
/// Gets a cached object path property, or returns null if not present or not the correct type.
DBusObjectPath? getObjectPathProperty(String interface, String name) {
var value = getCachedProperty(interface, name);
if (value == null) {
return null;
}
if (value.signature != DBusSignature('o')) {
return null;
}
return (value as DBusObjectPath);
}
/// Gets a cached object path array property, or returns null if not present or not the correct type.
List<DBusObjectPath>? getObjectPathArrayProperty(
String interface, String name) {
var value = getCachedProperty(interface, name);
if (value == null) {
return null;
}
if (value.signature != DBusSignature('ao')) {
return null;
}
return (value as DBusArray)
.children
.map((e) => (e as DBusObjectPath))
.toList();
}
/// Gets a cached list of data property, or returns null if not present or not the correct type.
List<Map<String, dynamic>>? getDataListProperty(
String interface, String name) {
var value = getCachedProperty(interface, name);
if (value == null) {
return null;
}
if (value.signature != DBusSignature('aa{sv}')) {
return null;
}
Map<String, dynamic> convertData(DBusValue value) {
return (value as DBusDict).children.map((key, value) => MapEntry(
(key as DBusString).value,
(value as DBusVariant).value.toNative(),
));
}
return (value as DBusArray)
.children
.map((value) => convertData(value))
.toList();
}
_NetworkManagerObject(DBusClient client, DBusObjectPath path,
Map<String, Map<String, DBusValue>> interfacesAndProperties)
: super(client, name: 'org.freedesktop.NetworkManager', path: path) {
updateInterfaces(interfacesAndProperties);
}
}
/// A client that connects to NetworkManager.
class NetworkManagerClient {
/// The bus this client is connected to.
final DBusClient _bus;
final bool _closeBus;
/// The root D-Bus NetworkManager object at path '/org/freedesktop'.
late final DBusRemoteObjectManager _root;
// Objects exported on the bus.
final _objects = <DBusObjectPath, _NetworkManagerObject>{};
// Subscription to object manager signals.
StreamSubscription? _objectManagerSubscription;
/// Creates a new NetworkManager client connected to the system D-Bus.
NetworkManagerClient({DBusClient? bus})
: _bus = bus ?? DBusClient.system(),
_closeBus = bus == null {
_root = DBusRemoteObjectManager(
_bus,
name: 'org.freedesktop.NetworkManager',
path: DBusObjectPath('/org/freedesktop'),
);
}
/// Stream of property names as their values change.
Stream<List<String>> get propertiesChanged =>
_manager?.interfaces[_managerInterfaceName]
?.propertiesChangedStreamController.stream ??
Stream<List<String>>.empty();
/// Connects to the NetworkManager D-Bus objects.
/// Must be called before accessing methods and properties.
Future<void> connect() async {
// Already connected
if (_objectManagerSubscription != null) {
return;
}
// Big old grody Hack
// DBus/nm doesnt seem to offer a way to deter ine if dbus is available on system
// worse the first connections get triggered in dbus_client onListen an isn't a catahable exception so crashes the app
// this is a hacky way to force an exception on thread if dbus isn't available and bail with out crashing
try {
await _root.client.getNameOwner(_root.name);
} on SocketException catch (e) {
print("nm dbus connect/emit test threw exception, dbus likely unavailable on system, aborting connect: $e");
return;
}
// Subscribe to changes
_objectManagerSubscription = _root.signals.listen((signal) {
if (signal is DBusObjectManagerInterfacesAddedSignal) {
var object = _objects[signal.changedPath];
if (object != null) {
object.updateInterfaces(signal.interfacesAndProperties);
} else {
object = _NetworkManagerObject(
_bus, signal.changedPath, signal.interfacesAndProperties);
_objects[signal.changedPath] = object;
}
} else if (signal is DBusObjectManagerInterfacesRemovedSignal) {
var object = _objects[signal.changedPath];
if (object != null) {
// If all the interface are removed, then this object has been removed.
// Keep the previous values around for the client to use.
if (object.wouldRemoveAllInterfaces(signal.interfaces)) {
_objects.remove(signal.changedPath);
} else {
object.removeInterfaces(signal.interfaces);
}
}
} else if (signal is DBusPropertiesChangedSignal) {
var object = _objects[signal.path];
if (object != null) {
object.updateProperties(
signal.propertiesInterface, signal.changedProperties);
}
}
});
// Find all the objects exported.
var objects = await _root.getManagedObjects();
objects.forEach((objectPath, interfacesAndProperties) {
_objects[objectPath] =
_NetworkManagerObject(_bus, objectPath, interfacesAndProperties);
});
}
/// The type of connection being used to access the network.
String get primaryConnectionType {
return _manager?.getStringProperty(
_managerInterfaceName,
'PrimaryConnectionType',
) ??
'';
}
/// True is NetworkManager is still starting up.
bool get startup {
return _manager?.getBooleanProperty(_managerInterfaceName, 'Startup') ??
false;
}
/// The version of NetworkManager running.
String get version {
return _manager?.getStringProperty(_managerInterfaceName, 'Version') ?? '';
}
/// The result of the last connectivity check.
NetworkManagerConnectivityState get connectivity {
var value =
_manager?.getUint32Property(_managerInterfaceName, 'Connectivity') ?? 0;
return _decodeConnectivityState(value);
}
/// The overall networking state.
NetworkManagerState get state {
var value =
_manager?.getUint32Property(_managerInterfaceName, 'State') ?? 0;
return _decodeState(value);
}
_NetworkManagerObject? get _manager =>
_objects[DBusObjectPath('/org/freedesktop/NetworkManager')];
/// Terminates all active connections. If a client remains unclosed, the Dart process may not terminate.
Future<void> close() async {
if (_objectManagerSubscription != null) {
await _objectManagerSubscription!.cancel();
_objectManagerSubscription = null;
}
if (_closeBus) {
await _bus.close();
}
}
}

View File

@ -5,6 +5,7 @@
import FlutterMacOS
import Foundation
import connectivity_plus
import flutter_local_notifications
import package_info_plus_macos
import path_provider_foundation
@ -13,6 +14,7 @@ import url_launcher_macos
import window_manager
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
ConnectivityPlugin.register(with: registry.registrar(forPlugin: "ConnectivityPlugin"))
FlutterLocalNotificationsPlugin.register(with: registry.registrar(forPlugin: "FlutterLocalNotificationsPlugin"))
FLTPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FLTPackageInfoPlusPlugin"))
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))

View File

@ -85,10 +85,10 @@ packages:
dependency: "direct dev"
description:
name: build_runner
sha256: b0a8a7b8a76c493e85f1b84bffa0588859a06197863dba8c9036b15581fd9727
sha256: "56942f8114731d1e79942cd981cfef29501937ff1bccf4dbdce0273f31f13640"
url: "https://pub.dev"
source: hosted
version: "2.3.3"
version: "2.2.0"
build_runner_core:
dependency: transitive
description:
@ -161,6 +161,20 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.17.0"
connectivity_plus:
dependency: "direct main"
description:
path: "lib/third_party/connectivity_plus/connectivity_plus"
relative: true
source: path
version: "3.0.6"
connectivity_plus_platform_interface:
dependency: transitive
description:
path: "lib/third_party/connectivity_plus/connectivity_plus_platform_interface"
relative: true
source: path
version: "1.2.4"
console:
dependency: transitive
description:
@ -202,7 +216,7 @@ packages:
source: hosted
version: "2.2.4"
dbus:
dependency: transitive
dependency: "direct main"
description:
name: dbus
sha256: "253bfaa3d340778d8bc755e89c3af38e85ef95e65fd5d5670aa3167f8d4f6577"
@ -335,10 +349,10 @@ packages:
dependency: transitive
description:
name: frontend_server_client
sha256: "408e3ca148b31c20282ad6f37ebfa6f4bdc8fede5b74bc2f08d9d92b55db3612"
sha256: "4f4a162323c86ffc1245765cfe138872b8f069deb42f7dbb36115fa27f31469b"
url: "https://pub.dev"
source: hosted
version: "3.2.0"
version: "2.1.3"
fuchsia_remote_debug_protocol:
dependency: transitive
description: flutter

View File

@ -32,6 +32,7 @@ dependencies:
# The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons.
cupertino_icons: ^1.0.0
# Todo: upgrade to 2.x, allow other package upgrades (dbus)
ffi: ^1.2.1
path_provider: ^2.0.0
crypto: ^3.0.2
@ -46,6 +47,12 @@ dependencies:
win_toast: ^0.0.2
flutter_local_notifications: ^9.6.1
desktop_notifications: ^0.6.3
# network management plugins
# dbus >=0.7.5 depends on ffi ^2.0.0 and cwtch depends on ffi ^1.2.1, dbus >=0.7.5 is forbidden.
dbus: 0.7.4
connectivity_plus:
path: lib/third_party/connectivity_plus/connectivity_plus
# misc plugins
qr_flutter: ^4.0.0
dev_dependencies:

View File

@ -6,12 +6,15 @@
#include "generated_plugin_registrant.h"
#include <connectivity_plus/connectivity_plus_windows_plugin.h>
#include <screen_retriever/screen_retriever_plugin.h>
#include <url_launcher_windows/url_launcher_windows.h>
#include <win_toast/win_toast_plugin.h>
#include <window_manager/window_manager_plugin.h>
void RegisterPlugins(flutter::PluginRegistry* registry) {
ConnectivityPlusWindowsPluginRegisterWithRegistrar(
registry->GetRegistrarForPlugin("ConnectivityPlusWindowsPlugin"));
ScreenRetrieverPluginRegisterWithRegistrar(
registry->GetRegistrarForPlugin("ScreenRetrieverPlugin"));
UrlLauncherWindowsRegisterWithRegistrar(

View File

@ -3,6 +3,7 @@
#
list(APPEND FLUTTER_PLUGIN_LIST
connectivity_plus
screen_retriever
url_launcher_windows
win_toast