From f90996080c036f4a694b4b366621610f9e0b1bfc Mon Sep 17 00:00:00 2001 From: Osei Fortune Date: Mon, 6 Jul 2020 21:29:26 -0400 Subject: [PATCH] fix(connectivity): getActiveNetworkInfo and NetworkInfo modern compliance #8580 (#8652) --- .../connectivity/connectivity.android.ts | 115 ++++++++++++++++-- .../connectivity/connectivity.d.ts | 9 +- .../connectivity/connectivity.ios.ts | 66 ++++++++++ 3 files changed, 175 insertions(+), 15 deletions(-) diff --git a/nativescript-core/connectivity/connectivity.android.ts b/nativescript-core/connectivity/connectivity.android.ts index d1a3707359..42ec068275 100644 --- a/nativescript-core/connectivity/connectivity.android.ts +++ b/nativescript-core/connectivity/connectivity.android.ts @@ -1,17 +1,18 @@ -import { getNativeApplication, android as androidApp } from "../application"; - +import { android as androidApp, getNativeApplication } from "../application"; export enum connectionType { none = 0, wifi = 1, mobile = 2, ethernet = 3, - bluetooth = 4 + bluetooth = 4, + vpn = 5 } const wifi = "wifi"; const mobile = "mobile"; const ethernet = "ethernet"; const bluetooth = "bluetooth"; +const vpn = "vpn"; // Get Connection Type function getConnectivityManager(): android.net.ConnectivityManager { @@ -27,33 +28,74 @@ function getActiveNetworkInfo(): android.net.NetworkInfo { return connectivityManager.getActiveNetworkInfo(); } -export function getConnectionType(): number { - let activeNetworkInfo = getActiveNetworkInfo(); - if (!activeNetworkInfo || !activeNetworkInfo.isConnected()) { +function getNetworkCapabilities() { + const connectivityManager = getConnectivityManager() as any; + const network = connectivityManager.getActiveNetwork(); + const capabilities = connectivityManager.getNetworkCapabilities(network); + if (capabilities == null) { return connectionType.none; } - let type = activeNetworkInfo.getTypeName().toLowerCase(); - if (type.indexOf(wifi) !== -1) { + const NetworkCapabilities = (android as any).net.NetworkCapabilities; + + if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) { return connectionType.wifi; } - if (type.indexOf(mobile) !== -1) { + if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) { return connectionType.mobile; } - if (type.indexOf(ethernet) !== -1) { + if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET)) { return connectionType.ethernet; } - if (type.indexOf(bluetooth) !== -1) { + if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_BLUETOOTH)) { return connectionType.bluetooth; } + if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_VPN)) { + return connectionType.vpn; + } + return connectionType.none; } -export function startMonitoring(connectionTypeChangedCallback: (newConnectionType: number) => void): void { +export function getConnectionType(): number { + if (android.os.Build.VERSION.SDK_INT >= 28) { + return getNetworkCapabilities(); + } else { + let activeNetworkInfo = getActiveNetworkInfo(); + if (!activeNetworkInfo || !activeNetworkInfo.isConnected()) { + return connectionType.none; + } + + let type = activeNetworkInfo.getTypeName().toLowerCase(); + if (type.indexOf(wifi) !== -1) { + return connectionType.wifi; + } + + if (type.indexOf(mobile) !== -1) { + return connectionType.mobile; + } + + if (type.indexOf(ethernet) !== -1) { + return connectionType.ethernet; + } + + if (type.indexOf(bluetooth) !== -1) { + return connectionType.bluetooth; + } + + if (type.indexOf(vpn) !== -1) { + return connectionType.vpn; + } + } + + return connectionType.none; +} + +function startMonitoringLegacy(connectionTypeChangedCallback) { let onReceiveCallback = function onReceiveCallback(context: android.content.Context, intent: android.content.Intent) { let newConnectionType = getConnectionType(); connectionTypeChangedCallback(newConnectionType); @@ -62,6 +104,53 @@ export function startMonitoring(connectionTypeChangedCallback: (newConnectionTyp androidApp.registerBroadcastReceiver(android.net.ConnectivityManager.CONNECTIVITY_ACTION, zoneCallback); } +let callback; +let networkCallback; +let notifyCallback; +export function startMonitoring(connectionTypeChangedCallback: (newConnectionType: number) => void): void { + if (android.os.Build.VERSION.SDK_INT >= 28) { + const manager = getConnectivityManager() as any; + if (manager) { + notifyCallback = () => { + let newConnectionType = getConnectionType(); + let zoneCallback = zonedCallback(connectionTypeChangedCallback); + zoneCallback(newConnectionType); + }; + const ConnectivityManager = (android as any).net.ConnectivityManager; + if (!networkCallback) { + networkCallback = ConnectivityManager.NetworkCallback.extend({ + onAvailable(network) { + notifyCallback(); + }, + onCapabilitiesChanged(network, networkCapabilities) { + notifyCallback(); + }, + onLost(network) { + notifyCallback(); + }, + onUnavailable() { + notifyCallback(); + } + }); + } + callback = new networkCallback(); + manager.registerDefaultNetworkCallback(callback); + } + + } else { + startMonitoringLegacy(connectionTypeChangedCallback); + } +} + export function stopMonitoring(): void { - androidApp.unregisterBroadcastReceiver(android.net.ConnectivityManager.CONNECTIVITY_ACTION); + if (android.os.Build.VERSION.SDK_INT >= 28) { + const manager = getConnectivityManager() as any; + if (manager && callback) { + manager.unregisterNetworkCallback(callback); + notifyCallback = null; + callback = null; + } + } else { + androidApp.unregisterBroadcastReceiver(android.net.ConnectivityManager.CONNECTIVITY_ACTION); + } } diff --git a/nativescript-core/connectivity/connectivity.d.ts b/nativescript-core/connectivity/connectivity.d.ts index a41a68f47d..1322f80424 100644 --- a/nativescript-core/connectivity/connectivity.d.ts +++ b/nativescript-core/connectivity/connectivity.d.ts @@ -35,9 +35,14 @@ export enum connectionType { ethernet = 3, /** - * Denotes an bluetooth connection + * Denotes a bluetooth connection */ - bluetooth = 4 + bluetooth = 4, + + /** + * Denotes a vpn connection + */ + vpn = 5 } /** diff --git a/nativescript-core/connectivity/connectivity.ios.ts b/nativescript-core/connectivity/connectivity.ios.ts index c50b3be534..8eec968a4d 100644 --- a/nativescript-core/connectivity/connectivity.ios.ts +++ b/nativescript-core/connectivity/connectivity.ios.ts @@ -2,6 +2,9 @@ export enum connectionType { none = 0, wifi = 1, mobile = 2, + ethernet = 3, + bluetooth = 4, + vpn = 5 } // Get Connection Type @@ -52,9 +55,71 @@ function _getConnectionTypeFromFlags(flags: number): number { return connectionType.mobile; } + const cfDict = CFNetworkCopySystemProxySettings(); + const nsDict = cfDict.takeUnretainedValue(); + const keys = nsDict.objectForKey("__SCOPED__"); + + if (isVPNConnected(keys)) { + return connectionType.vpn; + } + + /* + TODO try improving with CBCentralManager since toggling bluetooth + with multiple connections fails to detect switch, require key added + to Info.plist. + */ + if (isBluetoothConnected(keys)) { + return connectionType.bluetooth; + } + return connectionType.wifi; } +function isBluetoothConnected (keys) { + if (!keys) { + return false; + } + const allKeys = keys.allKeys; + const size = allKeys.count; + let isBlueTooth = false; + for (let i = 0; i < size; i++) { + const key = allKeys.objectAtIndex(i); + if ( + key === "en4" + ) { + isBlueTooth = true; + break; + } + } + + return isBlueTooth; +} + +function isVPNConnected(keys) { + if (!keys) { + return false; + } + const allKeys = keys.allKeys; + const size = allKeys.count; + let isVPN = false; + for (let i = 0; i < size; i++) { + const key = allKeys.objectAtIndex(i); + if ( + key === "tap" || + key === "tun" || + key === "ppp" || + key === "ipsec" || + key === "ipsec0" || + key === "utun1" + ) { + isVPN = true; + break; + } + } + + return isVPN; +} + export function getConnectionType(): number { return _getConnectionType(); } @@ -65,6 +130,7 @@ function _reachabilityCallback(target: any, flags: number, info: any) { const newConnectionType = _getConnectionTypeFromFlags(flags); _connectionTypeChangedCallback(newConnectionType); } + } const _reachabilityCallbackFunctionRef = new interop.FunctionReference(_reachabilityCallback);