import of connectivity_plus and massively reduced nm plugins
This commit is contained in:
parent
d9551a1cd9
commit
a18cf9329d
|
@ -14,7 +14,7 @@ import 'package:flutter_local_notifications_linux/src/model/icon.dart';
|
||||||
|
|
||||||
import 'package:path/path.dart' as path;
|
import 'package:path/path.dart' as path;
|
||||||
|
|
||||||
import 'config.dart';
|
import '../../config.dart';
|
||||||
|
|
||||||
// NotificationsManager provides a wrapper around platform specific notifications logic.
|
// NotificationsManager provides a wrapper around platform specific notifications logic.
|
||||||
abstract class NotificationsManager {
|
abstract class NotificationsManager {
|
||||||
|
|
|
@ -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.
|
|
@ -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.
|
|
@ -0,0 +1,106 @@
|
||||||
|
# connectivity_plus
|
||||||
|
|
||||||
|
[![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)
|
|
@ -0,0 +1,41 @@
|
||||||
|
group 'io.flutter.plugins.connectivity'
|
||||||
|
version '1.0-SNAPSHOT'
|
||||||
|
|
||||||
|
buildscript {
|
||||||
|
repositories {
|
||||||
|
google()
|
||||||
|
mavenCentral()
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
classpath 'com.android.tools.build:gradle:7.4.2'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rootProject.allprojects {
|
||||||
|
repositories {
|
||||||
|
google()
|
||||||
|
mavenCentral()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
apply plugin: 'com.android.library'
|
||||||
|
|
||||||
|
android {
|
||||||
|
compileSdkVersion 31
|
||||||
|
|
||||||
|
namespace 'dev.fluttercommunity.plus.connectivity'
|
||||||
|
|
||||||
|
compileOptions {
|
||||||
|
sourceCompatibility JavaVersion.VERSION_1_8
|
||||||
|
targetCompatibility JavaVersion.VERSION_1_8
|
||||||
|
}
|
||||||
|
|
||||||
|
defaultConfig {
|
||||||
|
minSdkVersion 16
|
||||||
|
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||||
|
}
|
||||||
|
lintOptions {
|
||||||
|
disable 'InvalidPackage'
|
||||||
|
}
|
||||||
|
}
|
1
lib/third_party/connectivity_plus/connectivity_plus/android/gradle.properties
vendored
Normal file
1
lib/third_party/connectivity_plus/connectivity_plus/android/gradle.properties
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
org.gradle.jvmargs=-Xmx1536M
|
|
@ -0,0 +1,5 @@
|
||||||
|
distributionBase=GRADLE_USER_HOME
|
||||||
|
distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.1-bin.zip
|
||||||
|
distributionPath=wrapper/dists
|
||||||
|
zipStorePath=wrapper/dists
|
||||||
|
zipStoreBase=GRADLE_USER_HOME
|
|
@ -0,0 +1 @@
|
||||||
|
rootProject.name = 'connectivity'
|
4
lib/third_party/connectivity_plus/connectivity_plus/android/src/main/AndroidManifest.xml
vendored
Normal file
4
lib/third_party/connectivity_plus/connectivity_plus/android/src/main/AndroidManifest.xml
vendored
Normal 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>
|
|
@ -0,0 +1,83 @@
|
||||||
|
// 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_WIFI = "wifi";
|
||||||
|
static final String CONNECTIVITY_MOBILE = "mobile";
|
||||||
|
static final String CONNECTIVITY_ETHERNET = "ethernet";
|
||||||
|
static final String CONNECTIVITY_BLUETOOTH = "bluetooth";
|
||||||
|
static final String CONNECTIVITY_VPN = "vpn";
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) {
|
||||||
|
return CONNECTIVITY_WIFI;
|
||||||
|
}
|
||||||
|
if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET)) {
|
||||||
|
return CONNECTIVITY_ETHERNET;
|
||||||
|
}
|
||||||
|
if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_VPN)) {
|
||||||
|
return CONNECTIVITY_VPN;
|
||||||
|
}
|
||||||
|
if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) {
|
||||||
|
return CONNECTIVITY_MOBILE;
|
||||||
|
}
|
||||||
|
if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_BLUETOOTH)) {
|
||||||
|
return CONNECTIVITY_BLUETOOTH;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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:
|
||||||
|
return CONNECTIVITY_BLUETOOTH;
|
||||||
|
case ConnectivityManager.TYPE_ETHERNET:
|
||||||
|
return CONNECTIVITY_ETHERNET;
|
||||||
|
case ConnectivityManager.TYPE_WIFI:
|
||||||
|
case ConnectivityManager.TYPE_WIMAX:
|
||||||
|
return CONNECTIVITY_WIFI;
|
||||||
|
case ConnectivityManager.TYPE_VPN:
|
||||||
|
return CONNECTIVITY_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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
4
lib/third_party/connectivity_plus/connectivity_plus/ios/Classes/ConnectivityPlusPlugin.h
vendored
Normal file
4
lib/third_party/connectivity_plus/connectivity_plus/ios/Classes/ConnectivityPlusPlugin.h
vendored
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
#import <Flutter/Flutter.h>
|
||||||
|
|
||||||
|
@interface ConnectivityPlusPlugin : NSObject <FlutterPlugin>
|
||||||
|
@end
|
15
lib/third_party/connectivity_plus/connectivity_plus/ios/Classes/ConnectivityPlusPlugin.m
vendored
Normal file
15
lib/third_party/connectivity_plus/connectivity_plus/ios/Classes/ConnectivityPlusPlugin.m
vendored
Normal 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
|
21
lib/third_party/connectivity_plus/connectivity_plus/ios/Classes/ConnectivityProvider.swift
vendored
Normal file
21
lib/third_party/connectivity_plus/connectivity_plus/ios/Classes/ConnectivityProvider.swift
vendored
Normal 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()
|
||||||
|
}
|
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
24
lib/third_party/connectivity_plus/connectivity_plus/ios/connectivity_plus.podspec
vendored
Normal file
24
lib/third_party/connectivity_plus/connectivity_plus/ios/connectivity_plus.podspec
vendored
Normal 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
|
55
lib/third_party/connectivity_plus/connectivity_plus/lib/connectivity_plus.dart
vendored
Normal file
55
lib/third_party/connectivity_plus/connectivity_plus/lib/connectivity_plus.dart
vendored
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
// 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'
|
||||||
|
if (dart.library.html) 'src/connectivity_plus_web.dart';
|
||||||
|
|
||||||
|
/// Discover network connectivity configurations: Distinguish between WI-FI and cellular, check WI-FI status and more.
|
||||||
|
class Connectivity {
|
||||||
|
/// 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();
|
||||||
|
}
|
||||||
|
}
|
85
lib/third_party/connectivity_plus/connectivity_plus/lib/src/connectivity_plus_linux.dart
vendored
Normal file
85
lib/third_party/connectivity_plus/connectivity_plus/lib/src/connectivity_plus_linux.dart
vendored
Normal file
|
@ -0,0 +1,85 @@
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
if (client.primaryConnectionType.contains('wireless')) {
|
||||||
|
return ConnectivityResult.wifi;
|
||||||
|
}
|
||||||
|
if (client.primaryConnectionType.contains('ethernet')) {
|
||||||
|
return ConnectivityResult.ethernet;
|
||||||
|
}
|
||||||
|
if (client.primaryConnectionType.contains('vpn')) {
|
||||||
|
return ConnectivityResult.vpn;
|
||||||
|
}
|
||||||
|
if (client.primaryConnectionType.contains('bluetooth')) {
|
||||||
|
return ConnectivityResult.bluetooth;
|
||||||
|
}
|
||||||
|
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();
|
||||||
|
}
|
27
lib/third_party/connectivity_plus/connectivity_plus/lib/src/connectivity_plus_web.dart
vendored
Normal file
27
lib/third_party/connectivity_plus/connectivity_plus/lib/src/connectivity_plus_web.dart
vendored
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
import 'package:connectivity_plus_platform_interface/connectivity_plus_platform_interface.dart';
|
||||||
|
import 'package:flutter_web_plugins/flutter_web_plugins.dart';
|
||||||
|
|
||||||
|
import 'web/network_information_api_connectivity_plugin.dart';
|
||||||
|
import 'web/dart_html_connectivity_plugin.dart';
|
||||||
|
|
||||||
|
/// The web implementation of the ConnectivityPlatform of the Connectivity plugin.
|
||||||
|
class ConnectivityPlusWebPlugin extends ConnectivityPlatform {
|
||||||
|
/// Factory method that initializes the connectivity plugin platform with an instance
|
||||||
|
/// of the plugin for the web.
|
||||||
|
static void registerWith(Registrar registrar) {
|
||||||
|
// Since the `NetworkInformationApi` is currently an experimental API and
|
||||||
|
// does not provide a reliable way to check a connectivity change
|
||||||
|
// from an onnline state to an offline state,
|
||||||
|
// its implementation is disabled for now.
|
||||||
|
// See also: https://developer.mozilla.org/en-US/docs/Web/API/Network_Information_API
|
||||||
|
//
|
||||||
|
// TODO: use `NetworkInformationApiConnectivityPlugin.isSupported()` when it becomes a stable DOM API.
|
||||||
|
const isSupported = false;
|
||||||
|
|
||||||
|
if (isSupported) {
|
||||||
|
ConnectivityPlatform.instance = NetworkInformationApiConnectivityPlugin();
|
||||||
|
} else {
|
||||||
|
ConnectivityPlatform.instance = DartHtmlConnectivityPlugin();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,35 @@
|
||||||
|
import 'dart:async';
|
||||||
|
import 'dart:html' as html show window;
|
||||||
|
|
||||||
|
import 'package:connectivity_plus_platform_interface/connectivity_plus_platform_interface.dart';
|
||||||
|
|
||||||
|
import '../connectivity_plus_web.dart';
|
||||||
|
|
||||||
|
/// The web implementation of the ConnectivityPlatform of the Connectivity plugin.
|
||||||
|
class DartHtmlConnectivityPlugin extends ConnectivityPlusWebPlugin {
|
||||||
|
/// Checks the connection status of the device.
|
||||||
|
@override
|
||||||
|
Future<ConnectivityResult> checkConnectivity() async {
|
||||||
|
return (html.window.navigator.onLine ?? false)
|
||||||
|
? ConnectivityResult.wifi
|
||||||
|
: ConnectivityResult.none;
|
||||||
|
}
|
||||||
|
|
||||||
|
StreamController<ConnectivityResult>? _connectivityResult;
|
||||||
|
|
||||||
|
/// Returns a Stream of ConnectivityResults changes.
|
||||||
|
@override
|
||||||
|
Stream<ConnectivityResult> get onConnectivityChanged {
|
||||||
|
if (_connectivityResult == null) {
|
||||||
|
_connectivityResult = StreamController<ConnectivityResult>.broadcast();
|
||||||
|
// Fallback to dart:html window.onOnline / window.onOffline
|
||||||
|
html.window.onOnline.listen((event) {
|
||||||
|
_connectivityResult!.add(ConnectivityResult.wifi);
|
||||||
|
});
|
||||||
|
html.window.onOffline.listen((event) {
|
||||||
|
_connectivityResult!.add(ConnectivityResult.none);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return _connectivityResult!.stream;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,92 @@
|
||||||
|
import 'dart:async';
|
||||||
|
import 'dart:html' as html show window, NetworkInformation;
|
||||||
|
import 'dart:js_util';
|
||||||
|
|
||||||
|
import 'package:connectivity_plus/src/web/utils/connectivity_result.dart';
|
||||||
|
import 'package:connectivity_plus_platform_interface/connectivity_plus_platform_interface.dart';
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
|
import 'package:js/js.dart';
|
||||||
|
|
||||||
|
import '../connectivity_plus_web.dart';
|
||||||
|
|
||||||
|
/// The web implementation of the ConnectivityPlatform of the Connectivity plugin.
|
||||||
|
class NetworkInformationApiConnectivityPlugin
|
||||||
|
extends ConnectivityPlusWebPlugin {
|
||||||
|
final html.NetworkInformation _networkInformation;
|
||||||
|
|
||||||
|
/// A check to determine if this version of the plugin can be used.
|
||||||
|
static bool isSupported() => html.window.navigator.connection != null;
|
||||||
|
|
||||||
|
/// The constructor of the plugin.
|
||||||
|
NetworkInformationApiConnectivityPlugin()
|
||||||
|
: this.withConnection(html.window.navigator.connection!);
|
||||||
|
|
||||||
|
/// Creates the plugin, with an override of the NetworkInformation object.
|
||||||
|
@visibleForTesting
|
||||||
|
NetworkInformationApiConnectivityPlugin.withConnection(
|
||||||
|
html.NetworkInformation connection)
|
||||||
|
: _networkInformation = connection;
|
||||||
|
|
||||||
|
/// Checks the connection status of the device.
|
||||||
|
@override
|
||||||
|
Future<ConnectivityResult> checkConnectivity() async {
|
||||||
|
return networkInformationToConnectivityResult(_networkInformation);
|
||||||
|
}
|
||||||
|
|
||||||
|
StreamController<ConnectivityResult>? _connectivityResultStreamController;
|
||||||
|
late Stream<ConnectivityResult> _connectivityResultStream;
|
||||||
|
|
||||||
|
/// Returns a Stream of ConnectivityResults changes.
|
||||||
|
@override
|
||||||
|
Stream<ConnectivityResult> get onConnectivityChanged {
|
||||||
|
// use fallback implementation if [_connectionSupported] is not availible
|
||||||
|
if (_connectionSupported == null) {
|
||||||
|
return _webPseudoStream();
|
||||||
|
}
|
||||||
|
if (_connectivityResultStreamController == null) {
|
||||||
|
_connectivityResultStreamController =
|
||||||
|
StreamController<ConnectivityResult>();
|
||||||
|
setProperty(_networkInformation, 'onchange', allowInterop((_) {
|
||||||
|
_connectivityResultStreamController!
|
||||||
|
.add(networkInformationToConnectivityResult(_networkInformation));
|
||||||
|
}));
|
||||||
|
// ignore: todo
|
||||||
|
// TODO: Implement the above with _networkInformation.onChange:
|
||||||
|
// _networkInformation.onChange.listen((_) {
|
||||||
|
// _connectivityResult
|
||||||
|
// .add(networkInformationToConnectivityResult(_networkInformation));
|
||||||
|
// });
|
||||||
|
// Once we can detect when to *cancel* a subscription to the _networkInformation
|
||||||
|
// onChange Stream upon hot restart.
|
||||||
|
// https://github.com/dart-lang/sdk/issues/42679
|
||||||
|
_connectivityResultStream =
|
||||||
|
_connectivityResultStreamController!.stream.asBroadcastStream();
|
||||||
|
}
|
||||||
|
return _connectivityResultStream;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// stores the last fallback network state
|
||||||
|
ConnectivityResult? _lastFallbackState;
|
||||||
|
|
||||||
|
/// periodically checks the current network state
|
||||||
|
Stream<ConnectivityResult> _webPseudoStream() {
|
||||||
|
final StreamController<ConnectivityResult> webStream =
|
||||||
|
StreamController.broadcast();
|
||||||
|
Timer.periodic(
|
||||||
|
const Duration(milliseconds: 250),
|
||||||
|
(timer) async {
|
||||||
|
final result = await checkConnectivity();
|
||||||
|
if (result != _lastFallbackState) {
|
||||||
|
webStream.add(result);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
return webStream.stream;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// accesses the JS-native `navigator.connection`
|
||||||
|
///
|
||||||
|
/// ensures `navigator.connection.onchange` is availible
|
||||||
|
@JS("navigator.connection")
|
||||||
|
external get _connectionSupported;
|
53
lib/third_party/connectivity_plus/connectivity_plus/lib/src/web/utils/connectivity_result.dart
vendored
Normal file
53
lib/third_party/connectivity_plus/connectivity_plus/lib/src/web/utils/connectivity_result.dart
vendored
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
import 'dart:html' as html show NetworkInformation;
|
||||||
|
|
||||||
|
import 'package:connectivity_plus_platform_interface/connectivity_plus_platform_interface.dart';
|
||||||
|
|
||||||
|
/// Converts an incoming NetworkInformation object into the correct ConnectivityResult.
|
||||||
|
ConnectivityResult networkInformationToConnectivityResult(
|
||||||
|
html.NetworkInformation info,
|
||||||
|
) {
|
||||||
|
if (info.downlink == 0 && info.rtt == 0) {
|
||||||
|
return ConnectivityResult.none;
|
||||||
|
}
|
||||||
|
if (info.type != null) {
|
||||||
|
return _typeToConnectivityResult(info.type!);
|
||||||
|
}
|
||||||
|
if (info.effectiveType != null) {
|
||||||
|
return _effectiveTypeToConnectivityResult(info.effectiveType!);
|
||||||
|
}
|
||||||
|
return ConnectivityResult.none;
|
||||||
|
}
|
||||||
|
|
||||||
|
ConnectivityResult _effectiveTypeToConnectivityResult(String effectiveType) {
|
||||||
|
// Possible values:
|
||||||
|
/*'2g'|'3g'|'4g'|'slow-2g'*/
|
||||||
|
switch (effectiveType) {
|
||||||
|
case 'slow-2g':
|
||||||
|
case '2g':
|
||||||
|
case '3g':
|
||||||
|
case '4g':
|
||||||
|
return ConnectivityResult.mobile;
|
||||||
|
default:
|
||||||
|
return ConnectivityResult.wifi;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ConnectivityResult _typeToConnectivityResult(String type) {
|
||||||
|
// Possible values:
|
||||||
|
/*'bluetooth'|'cellular'|'ethernet'|'mixed'|'none'|'other'|'unknown'|'wifi'|'wimax'*/
|
||||||
|
switch (type) {
|
||||||
|
case 'none':
|
||||||
|
return ConnectivityResult.none;
|
||||||
|
case 'bluetooth':
|
||||||
|
return ConnectivityResult.bluetooth;
|
||||||
|
case 'cellular':
|
||||||
|
case 'mixed':
|
||||||
|
case 'other':
|
||||||
|
case 'unknown':
|
||||||
|
return ConnectivityResult.mobile;
|
||||||
|
case 'ethernet':
|
||||||
|
return ConnectivityResult.ethernet;
|
||||||
|
default:
|
||||||
|
return ConnectivityResult.wifi;
|
||||||
|
}
|
||||||
|
}
|
90
lib/third_party/connectivity_plus/connectivity_plus/macos/Classes/ConnectivityPlugin.swift
vendored
Normal file
90
lib/third_party/connectivity_plus/connectivity_plus/macos/Classes/ConnectivityPlugin.swift
vendored
Normal 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
|
||||||
|
}
|
||||||
|
}
|
21
lib/third_party/connectivity_plus/connectivity_plus/macos/Classes/ConnectivityProvider.swift
vendored
Normal file
21
lib/third_party/connectivity_plus/connectivity_plus/macos/Classes/ConnectivityProvider.swift
vendored
Normal 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()
|
||||||
|
}
|
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
22
lib/third_party/connectivity_plus/connectivity_plus/macos/connectivity_plus.podspec
vendored
Normal file
22
lib/third_party/connectivity_plus/connectivity_plus/macos/connectivity_plus.podspec
vendored
Normal 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
|
|
@ -0,0 +1,48 @@
|
||||||
|
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
|
||||||
|
web:
|
||||||
|
pluginClass: ConnectivityPlusWebPlugin
|
||||||
|
fileName: src/connectivity_plus_web.dart
|
||||||
|
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
|
|
@ -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/
|
|
@ -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
|
||||||
|
)
|
171
lib/third_party/connectivity_plus/connectivity_plus/windows/connectivity_plus_plugin.cpp
vendored
Normal file
171
lib/third_party/connectivity_plus/connectivity_plus/windows/connectivity_plus_plugin.cpp
vendored
Normal 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));
|
||||||
|
}
|
|
@ -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_
|
|
@ -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
|
243
lib/third_party/connectivity_plus/connectivity_plus/windows/network_manager.cpp
vendored
Normal file
243
lib/third_party/connectivity_plus/connectivity_plus/windows/network_manager.cpp
vendored
Normal 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(); }
|
25
lib/third_party/connectivity_plus/connectivity_plus_platform_interface/.gitattributes
vendored
Normal file
25
lib/third_party/connectivity_plus/connectivity_plus_platform_interface/.gitattributes
vendored
Normal 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
|
46
lib/third_party/connectivity_plus/connectivity_plus_platform_interface/.gitignore
vendored
Normal file
46
lib/third_party/connectivity_plus/connectivity_plus_platform_interface/.gitignore
vendored
Normal 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
|
94
lib/third_party/connectivity_plus/connectivity_plus_platform_interface/CHANGELOG.md
vendored
Normal file
94
lib/third_party/connectivity_plus/connectivity_plus_platform_interface/CHANGELOG.md
vendored
Normal file
|
@ -0,0 +1,94 @@
|
||||||
|
## 1.2.4
|
||||||
|
|
||||||
|
- **FIX**: Do not return ConnectivityResult.none on iOS and MacOS with VPN (#1335).
|
||||||
|
|
||||||
|
## 1.2.3
|
||||||
|
|
||||||
|
- **FIX**: Increase min Flutter version to fix dartPluginClass registration (#1275).
|
||||||
|
|
||||||
|
## 1.2.2
|
||||||
|
|
||||||
|
- Add missing VPN enum
|
||||||
|
|
||||||
|
## 1.2.1
|
||||||
|
|
||||||
|
- Update flutter_lints to 2.0.1
|
||||||
|
- Update plugin_platform_interface to 2.1.2
|
||||||
|
- Fix analyzer issues
|
||||||
|
|
||||||
|
## 1.2.0
|
||||||
|
|
||||||
|
- Add bluetooth as connectivity result
|
||||||
|
|
||||||
|
## 1.1.1
|
||||||
|
|
||||||
|
- Dependencies update
|
||||||
|
|
||||||
|
## 1.1.0
|
||||||
|
|
||||||
|
- Add ethernet as connectivity result
|
||||||
|
|
||||||
|
## 1.0.2
|
||||||
|
|
||||||
|
- Update connectivity plus
|
||||||
|
|
||||||
|
## 1.0.1
|
||||||
|
|
||||||
|
- Improve documentation
|
||||||
|
|
||||||
|
## 1.0.0
|
||||||
|
|
||||||
|
- Migrated to null safety
|
||||||
|
|
||||||
|
## 0.4.1
|
||||||
|
|
||||||
|
- Address pub score
|
||||||
|
|
||||||
|
## 0.4.0
|
||||||
|
|
||||||
|
- Removed members that were moved to network_info_plus
|
||||||
|
|
||||||
|
## 0.3.0
|
||||||
|
|
||||||
|
- Renamed method channel
|
||||||
|
|
||||||
|
## 0.2.0
|
||||||
|
|
||||||
|
- Transfer to plus-plugins monorepo
|
||||||
|
|
||||||
|
## 0.1.7
|
||||||
|
|
||||||
|
- Transfer package to Flutter Community under new name `connectivity_plus_platform_interface`.
|
||||||
|
|
||||||
|
## 0.1.6
|
||||||
|
|
||||||
|
- Update lower bound of dart dependency to 2.1.0.
|
||||||
|
|
||||||
|
## 0.1.5
|
||||||
|
|
||||||
|
- Remove dart:io Platform checks from the MethodChannel implementation. This is
|
||||||
|
tripping the analysis of other versions of the plugin.
|
||||||
|
|
||||||
|
## 0.1.4
|
||||||
|
|
||||||
|
- Bump the minimum Flutter version to 1.12.13+hotfix.5.
|
||||||
|
|
||||||
|
## 0.1.3
|
||||||
|
|
||||||
|
- Make the pedantic dev_dependency explicit.
|
||||||
|
|
||||||
|
## 0.1.2
|
||||||
|
|
||||||
|
- Bring ConnectivityResult and LocationAuthorizationStatus enums from the core package.
|
||||||
|
- Use the above Enums as return values for ConnectivityPlatformInterface methods.
|
||||||
|
- Modify the MethodChannel implementation so it returns the right types.
|
||||||
|
- Bring all utility methods, asserts and other logic that is only needed on the MethodChannel implementation from the core package.
|
||||||
|
- Bring MethodChannel unit tests from core package.
|
||||||
|
|
||||||
|
## 0.1.1
|
||||||
|
|
||||||
|
- Fix README.md link.
|
||||||
|
|
||||||
|
## 0.1.0
|
||||||
|
|
||||||
|
- Initial release.
|
27
lib/third_party/connectivity_plus/connectivity_plus_platform_interface/LICENSE
vendored
Normal file
27
lib/third_party/connectivity_plus/connectivity_plus_platform_interface/LICENSE
vendored
Normal 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.
|
12
lib/third_party/connectivity_plus/connectivity_plus_platform_interface/README.md
vendored
Normal file
12
lib/third_party/connectivity_plus/connectivity_plus_platform_interface/README.md
vendored
Normal 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.
|
|
@ -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.');
|
||||||
|
}
|
||||||
|
}
|
|
@ -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 ?? ''));
|
||||||
|
}
|
||||||
|
}
|
27
lib/third_party/connectivity_plus/connectivity_plus_platform_interface/lib/src/enums.dart
vendored
Normal file
27
lib/third_party/connectivity_plus/connectivity_plus_platform_interface/lib/src/enums.dart
vendored
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
/// Connection status check result.
|
||||||
|
enum ConnectivityResult {
|
||||||
|
/// Bluetooth: Device connected via bluetooth
|
||||||
|
bluetooth,
|
||||||
|
|
||||||
|
/// 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,
|
||||||
|
|
||||||
|
/// VPN: Device connected to a VPN
|
||||||
|
///
|
||||||
|
/// Note for iOS and macOS:
|
||||||
|
/// There is no separate network interface type for [vpn].
|
||||||
|
/// It returns [other] on any device (also simulator).
|
||||||
|
vpn,
|
||||||
|
|
||||||
|
/// Other: Device is connected to an unknown network
|
||||||
|
other
|
||||||
|
}
|
22
lib/third_party/connectivity_plus/connectivity_plus_platform_interface/lib/src/utils.dart
vendored
Normal file
22
lib/third_party/connectivity_plus/connectivity_plus_platform_interface/lib/src/utils.dart
vendored
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
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':
|
||||||
|
return ConnectivityResult.bluetooth;
|
||||||
|
case 'wifi':
|
||||||
|
return ConnectivityResult.wifi;
|
||||||
|
case 'ethernet':
|
||||||
|
return ConnectivityResult.ethernet;
|
||||||
|
case 'mobile':
|
||||||
|
return ConnectivityResult.mobile;
|
||||||
|
case 'vpn':
|
||||||
|
return ConnectivityResult.vpn;
|
||||||
|
case 'other':
|
||||||
|
return ConnectivityResult.other;
|
||||||
|
case 'none':
|
||||||
|
default:
|
||||||
|
return ConnectivityResult.none;
|
||||||
|
}
|
||||||
|
}
|
20
lib/third_party/connectivity_plus/connectivity_plus_platform_interface/pubspec.yaml
vendored
Normal file
20
lib/third_party/connectivity_plus/connectivity_plus_platform_interface/pubspec.yaml
vendored
Normal 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
|
|
@ -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.
|
|
@ -0,0 +1 @@
|
||||||
|
export 'src/network_manager_client.dart';
|
|
@ -0,0 +1,403 @@
|
||||||
|
import 'dart:async';
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue