diff --git a/README.md b/README.md index 49b11e42..4f8639e5 100644 --- a/README.md +++ b/README.md @@ -177,12 +177,14 @@ The `details` value depends on the `type` value. | Property | Platform | Type | Description | | ----------------------- | --------------------------------- | --------- | -------------------------------------------------------------------------------------------------------------------------- | | `isConnectionExpensive` | Android, iOS, macOS, Windows, Web | `boolean` | If the network connection is considered "expensive". This could be in either energy or monetary terms. | -| `ssid` | Android, iOS (not tvOS) | `string` | The SSID of the network. May not be present, `null`, or an empty string if it cannot be determined. **On iOS, make sure your app meets at least one of the [following requirements](https://developer.apple.com/documentation/systemconfiguration/1614126-cncopycurrentnetworkinfo?language=objc#discussion). On Android, you need to have the `ACCESS_FINE_LOCATION` permission in your `AndroidManifest.xml` and accepted by the user**. | -| `bssid` | Android, iOS (not tvOS) | `string` | The BSSID of the network. May not be present, `null`, or an empty string if it cannot be determined. **On iOS, make sure your app meets at least one of the [following requirements](https://developer.apple.com/documentation/systemconfiguration/1614126-cncopycurrentnetworkinfo?language=objc#discussion). On Android, you need to have the `ACCESS_FINE_LOCATION` permission in your `AndroidManifest.xml` and accepted by the user**. | -| `strength` | Android | `number` | An integer number from `0` to `100` for the signal strength. May not be present if the signal strength cannot be determined. | +| `ssid` | Android, iOS (not tvOS), Windows | `string` | The SSID of the network. May not be present, `null`, or an empty string if it cannot be determined. **On iOS, make sure your app meets at least one of the [following requirements](https://developer.apple.com/documentation/systemconfiguration/1614126-cncopycurrentnetworkinfo?language=objc#discussion). On Android, you need to have the `ACCESS_FINE_LOCATION` permission in your `AndroidManifest.xml` and accepted by the user**. | +| `bssid` | Android, iOS (not tvOS), Windows* | `string` | The BSSID of the network. May not be present, `null`, or an empty string if it cannot be determined. **On iOS, make sure your app meets at least one of the [following requirements](https://developer.apple.com/documentation/systemconfiguration/1614126-cncopycurrentnetworkinfo?language=objc#discussion). On Android, you need to have the `ACCESS_FINE_LOCATION` permission in your `AndroidManifest.xml` and accepted by the user**. | +| `strength` | Android, Windows | `number` | An integer number from `0` to `100` for the signal strength. May not be present if the signal strength cannot be determined. | | `ipAddress` | Android, iOS, macOS | `string` | The external IP address. Can be in IPv4 or IPv6 format. May not be present if it cannot be determined. | | `subnet` | Android, iOS, macOS | `string` | The subnet mask in IPv4 format. May not be present if it cannot be determined. | -| `frequency` | Android | `number` | Network frequency. Example: For 2.4 GHz networks, the method will return 2457. May not be present if it cannot be determined. | +| `frequency` | Android, Windows* | `number` | Network frequency. Example: For 2.4 GHz networks, the method will return 2457. May not be present if it cannot be determined. | + +`*` Requires `wiFiControl` capability in appxmanifest. Without it, these values will be null. ##### `type` is `cellular` diff --git a/example/windows/NetInfoExample/Package.appxmanifest b/example/windows/NetInfoExample/Package.appxmanifest index 1a4d8763..6143558d 100644 --- a/example/windows/NetInfoExample/Package.appxmanifest +++ b/example/windows/NetInfoExample/Package.appxmanifest @@ -45,5 +45,6 @@ + \ No newline at end of file diff --git a/windows/RNCNetInfo.sln b/windows/RNCNetInfo.sln index 37780c14..4d724c9b 100644 --- a/windows/RNCNetInfo.sln +++ b/windows/RNCNetInfo.sln @@ -84,6 +84,18 @@ Global {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Release|x64.Build.0 = Release|x64 {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Release|x86.ActiveCfg = Release|Win32 {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Release|x86.Build.0 = Release|Win32 + {14B93DC8-FD93-4A6D-81CB-8BC96644501C}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {14B93DC8-FD93-4A6D-81CB-8BC96644501C}.Debug|ARM64.Build.0 = Debug|ARM64 + {14B93DC8-FD93-4A6D-81CB-8BC96644501C}.Debug|x64.ActiveCfg = Debug|x64 + {14B93DC8-FD93-4A6D-81CB-8BC96644501C}.Debug|x64.Build.0 = Debug|x64 + {14B93DC8-FD93-4A6D-81CB-8BC96644501C}.Debug|x86.ActiveCfg = Debug|Win32 + {14B93DC8-FD93-4A6D-81CB-8BC96644501C}.Debug|x86.Build.0 = Debug|Win32 + {14B93DC8-FD93-4A6D-81CB-8BC96644501C}.Release|ARM64.ActiveCfg = Release|ARM64 + {14B93DC8-FD93-4A6D-81CB-8BC96644501C}.Release|ARM64.Build.0 = Release|ARM64 + {14B93DC8-FD93-4A6D-81CB-8BC96644501C}.Release|x64.ActiveCfg = Release|x64 + {14B93DC8-FD93-4A6D-81CB-8BC96644501C}.Release|x64.Build.0 = Release|x64 + {14B93DC8-FD93-4A6D-81CB-8BC96644501C}.Release|x86.ActiveCfg = Release|Win32 + {14B93DC8-FD93-4A6D-81CB-8BC96644501C}.Release|x86.Build.0 = Release|Win32 {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Debug|ARM64.ActiveCfg = Debug|ARM64 {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Debug|ARM64.Build.0 = Debug|ARM64 {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Debug|x64.ActiveCfg = Debug|x64 @@ -120,26 +132,13 @@ Global {FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Release|x64.Build.0 = Release|x64 {FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Release|x86.ActiveCfg = Release|Win32 {FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Release|x86.Build.0 = Release|Win32 - {14B93DC8-FD93-4A6D-81CB-8BC96644501C}.Debug|ARM64.ActiveCfg = Debug|ARM64 - {14B93DC8-FD93-4A6D-81CB-8BC96644501C}.Debug|ARM64.Build.0 = Debug|ARM64 - {14B93DC8-FD93-4A6D-81CB-8BC96644501C}.Debug|x64.ActiveCfg = Debug|x64 - {14B93DC8-FD93-4A6D-81CB-8BC96644501C}.Debug|x64.Build.0 = Debug|x64 - {14B93DC8-FD93-4A6D-81CB-8BC96644501C}.Debug|x86.ActiveCfg = Debug|Win32 - {14B93DC8-FD93-4A6D-81CB-8BC96644501C}.Debug|x86.Build.0 = Debug|Win32 - {14B93DC8-FD93-4A6D-81CB-8BC96644501C}.Debug|x86.Deploy.0 = Debug|Win32 - {14B93DC8-FD93-4A6D-81CB-8BC96644501C}.Release|ARM64.ActiveCfg = Release|ARM64 - {14B93DC8-FD93-4A6D-81CB-8BC96644501C}.Release|ARM64.Build.0 = Release|ARM64 - {14B93DC8-FD93-4A6D-81CB-8BC96644501C}.Release|x64.ActiveCfg = Release|x64 - {14B93DC8-FD93-4A6D-81CB-8BC96644501C}.Release|x64.Build.0 = Release|x64 - {14B93DC8-FD93-4A6D-81CB-8BC96644501C}.Release|x86.ActiveCfg = Release|Win32 - {14B93DC8-FD93-4A6D-81CB-8BC96644501C}.Release|x86.Build.0 = Release|Win32 - {14B93DC8-FD93-4A6D-81CB-8BC96644501C}.Release|x86.Deploy.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution {A990658C-CE31-4BCC-976F-0FC6B1AF693D} = {5EA20F54-880A-49F3-99FA-4B3FE54E8AB1} + {14B93DC8-FD93-4A6D-81CB-8BC96644501C} = {5EA20F54-880A-49F3-99FA-4B3FE54E8AB1} {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD} = {5EA20F54-880A-49F3-99FA-4B3FE54E8AB1} {C38970C0-5FBF-4D69-90D8-CBAC225AE895} = {5EA20F54-880A-49F3-99FA-4B3FE54E8AB1} {F7D32BD0-2749-483E-9A0D-1635EF7E3136} = {5EA20F54-880A-49F3-99FA-4B3FE54E8AB1} @@ -148,7 +147,6 @@ Global {2049DBE9-8D13-42C9-AE4B-413AE38FFFD0} = {5EA20F54-880A-49F3-99FA-4B3FE54E8AB1} {84E05BFA-CBAF-4F0D-BFB6-4CE85742A57E} = {5EA20F54-880A-49F3-99FA-4B3FE54E8AB1} {EF074BA1-2D54-4D49-A28E-5E040B47CD2E} = {5EA20F54-880A-49F3-99FA-4B3FE54E8AB1} - {14B93DC8-FD93-4A6D-81CB-8BC96644501C} = {5EA20F54-880A-49F3-99FA-4B3FE54E8AB1} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {D43FAD39-F619-437D-BB40-04A3982ACB6A} diff --git a/windows/RNCNetInfoCPP/NetworkInfo.cpp b/windows/RNCNetInfoCPP/NetworkInfo.cpp deleted file mode 100644 index 74c51c68..00000000 --- a/windows/RNCNetInfoCPP/NetworkInfo.cpp +++ /dev/null @@ -1,109 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#include "pch.h" -#include "NetworkInfo.h" - -namespace winrt{ - using namespace Windows::Foundation; - using namespace Windows::Networking::Connectivity; -} - -namespace winrt::ReactNativeNetInfo::implementation { - - NetworkInfo::NetworkInfo() { - GetConnectionProfile(); - - m_networkStatusChangedRevoker = NetworkInformation::NetworkStatusChanged(winrt::auto_revoke, [&](const winrt::IInspectable& sender) { - GetConnectionProfile(); - - if (m_statusChangedHandler) { - m_statusChangedHandler(sender); - } - }); - } - - void NetworkInfo::StatusChanged(const NetworkStatusChangedEventHandler& handler) { - m_statusChangedHandler = handler; - } - - bool NetworkInfo::IsConnected() { - return m_profile && m_profile.GetNetworkConnectivityLevel() != NetworkConnectivityLevel::None; - } - - void NetworkInfo::GetConnectionProfile() { - try - { - m_profile = NetworkInformation::GetInternetConnectionProfile(); - } - catch (const std::exception&) - { - m_profile = { nullptr }; - } - } - - std::string NetworkInfo::ConnectivityType() { - if (!m_profile) { - return CONNECTION_TYPE_NONE; - } - if (m_profile.IsWlanConnectionProfile()) { - return CONNECTION_TYPE_WIFI; - } - if (m_profile.IsWwanConnectionProfile()) { - return CONNECTION_TYPE_CELLULAR; - } - - auto networkAdapter = m_profile.NetworkAdapter(); - if (!networkAdapter) { - return CONNECTION_TYPE_UNKNOWN; - } - // Possible values: https://docs.microsoft.com/en-us/uwp/api/windows.networking.connectivity.networkadapter.ianainterfacetype - if (networkAdapter.IanaInterfaceType() == 6u) { - return CONNECTION_TYPE_ETHERNET; - } - else { - return CONNECTION_TYPE_OTHER; - } - } - - std::string NetworkInfo::CellularGeneration() { - if (!m_profile.IsWwanConnectionProfile()) { - return CELLULAR_GENERATION_NONE; - } - - auto dataClass = m_profile.WwanConnectionProfileDetails().GetCurrentDataClass(); - switch (dataClass) { - case WwanDataClass::None: - return CELLULAR_GENERATION_NONE; - case WwanDataClass::Edge: - case WwanDataClass::Gprs: - return CELLULAR_GENERATION_2G; - case WwanDataClass::Cdma1xEvdo: - case WwanDataClass::Cdma1xEvdoRevA: - case WwanDataClass::Cdma1xEvdoRevB: - case WwanDataClass::Cdma1xEvdv: - case WwanDataClass::Cdma1xRtt: - case WwanDataClass::Cdma3xRtt: - case WwanDataClass::Hsdpa: - case WwanDataClass::Hsupa: - case WwanDataClass::Umts: - return CELLULAR_GENERATION_3G; - case WwanDataClass::CdmaUmb: - case WwanDataClass::LteAdvanced: - return CELLULAR_GENERATION_4G; - case WwanDataClass::Custom: - default: - return CELLULAR_GENERATION_UNKNOWN; - } - } - - bool NetworkInfo::IsConnectionExpensive() { - if (!m_profile) { - return false; - } - - auto costType = m_profile.GetConnectionCost().NetworkCostType(); - return costType == NetworkCostType::Fixed || costType == NetworkCostType::Variable; - } - -} diff --git a/windows/RNCNetInfoCPP/NetworkInfo.h b/windows/RNCNetInfoCPP/NetworkInfo.h deleted file mode 100644 index 0139a9f1..00000000 --- a/windows/RNCNetInfoCPP/NetworkInfo.h +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. -#pragma once -#include "NativeModules.h" - -namespace winrt::ReactNativeNetInfo::implementation { - - class NetworkInfo { - public: - NetworkInfo(); - bool IsConnected(); - std::string ConnectivityType(); - std::string CellularGeneration(); - bool IsConnectionExpensive(); - void StatusChanged(const winrt::Windows::Networking::Connectivity::NetworkStatusChangedEventHandler& handler); - - static constexpr auto CONNECTION_TYPE_CELLULAR = "cellular"; - static constexpr auto CONNECTION_TYPE_ETHERNET = "ethernet"; - static constexpr auto CONNECTION_TYPE_NONE = "none"; - static constexpr auto CONNECTION_TYPE_UNKNOWN = "unknown"; - static constexpr auto CONNECTION_TYPE_WIFI = "wifi"; - static constexpr auto CONNECTION_TYPE_OTHER = "other"; - - static constexpr auto CELLULAR_GENERATION_2G = "2g"; - static constexpr auto CELLULAR_GENERATION_3G = "3g"; - static constexpr auto CELLULAR_GENERATION_4G = "4g"; - static constexpr auto CELLULAR_GENERATION_NONE = nullptr; - static constexpr auto CELLULAR_GENERATION_UNKNOWN = nullptr; - - private: - void GetConnectionProfile(); - winrt::Windows::Networking::Connectivity::NetworkInformation::NetworkStatusChanged_revoker m_networkStatusChangedRevoker{}; - winrt::Windows::Networking::Connectivity::NetworkStatusChangedEventHandler m_statusChangedHandler{}; - winrt::Windows::Networking::Connectivity::ConnectionProfile m_profile{ nullptr }; - }; - -} \ No newline at end of file diff --git a/windows/RNCNetInfoCPP/RNCNetInfo.cpp b/windows/RNCNetInfoCPP/RNCNetInfo.cpp new file mode 100644 index 00000000..3e4e3057 --- /dev/null +++ b/windows/RNCNetInfoCPP/RNCNetInfo.cpp @@ -0,0 +1,195 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "pch.h" +#include "RNCNetInfo.h" + +#include + +namespace winrt { + using namespace Windows::Foundation; + using namespace Windows::Networking::Connectivity; + using namespace Windows::Devices::WiFi; +} + +using namespace winrt::Microsoft::ReactNative; + +namespace winrt::ReactNativeNetInfo::implementation { + + static constexpr auto CONNECTION_TYPE_CELLULAR = "cellular"; + static constexpr auto CONNECTION_TYPE_ETHERNET = "ethernet"; + static constexpr auto CONNECTION_TYPE_NONE = "none"; + static constexpr auto CONNECTION_TYPE_UNKNOWN = "unknown"; + static constexpr auto CONNECTION_TYPE_WIFI = "wifi"; + static constexpr auto CONNECTION_TYPE_OTHER = "other"; + + static constexpr auto CELLULAR_GENERATION_2G = "2g"; + static constexpr auto CELLULAR_GENERATION_3G = "3g"; + static constexpr auto CELLULAR_GENERATION_4G = "4g"; + static constexpr auto CELLULAR_GENERATION_NONE = nullptr; + static constexpr auto CELLULAR_GENERATION_UNKNOWN = nullptr; + + static constexpr auto WIFI_GENERATION_1 = "WiFi 1"; + static constexpr auto WIFI_GENERATION_2 = "WiFi 2"; + static constexpr auto WIFI_GENERATION_3 = "WiFi 3"; + static constexpr auto WIFI_GENERATION_4 = "WiFi 4"; + static constexpr auto WIFI_GENERATION_5 = "WiFi 5"; + static constexpr auto WIFI_GENERATION_6 = "WiFi 6"; + static constexpr auto WIFI_GENERATION_UNKNOWN = nullptr; + + std::optional GetCellularGeneration(winrt::WwanDataClass dataClass) { + switch (dataClass) { + case WwanDataClass::None: + return CELLULAR_GENERATION_NONE; + case WwanDataClass::Edge: + case WwanDataClass::Gprs: + return CELLULAR_GENERATION_2G; + case WwanDataClass::Cdma1xEvdo: + case WwanDataClass::Cdma1xEvdoRevA: + case WwanDataClass::Cdma1xEvdoRevB: + case WwanDataClass::Cdma1xEvdv: + case WwanDataClass::Cdma1xRtt: + case WwanDataClass::Cdma3xRtt: + case WwanDataClass::Hsdpa: + case WwanDataClass::Hsupa: + case WwanDataClass::Umts: + return CELLULAR_GENERATION_3G; + case WwanDataClass::CdmaUmb: + case WwanDataClass::LteAdvanced: + return CELLULAR_GENERATION_4G; + case WwanDataClass::Custom: + default: + return CELLULAR_GENERATION_UNKNOWN; + } + } + + std::optional GetWifiGeneration(winrt::WiFiPhyKind kind) { + switch (kind) { + case WiFiPhyKind::Dsss: // 802.11b + return WIFI_GENERATION_1; + case WiFiPhyKind::Ofdm: // 802.11a + return WIFI_GENERATION_2; + case WiFiPhyKind::Erp: // 802.11g + return WIFI_GENERATION_3; + case WiFiPhyKind::HT: // 802.11n + return WIFI_GENERATION_4; + case WiFiPhyKind::Vht: // 802.11ac + return WIFI_GENERATION_5; + case WiFiPhyKind::HE: // 802.11ax + return WIFI_GENERATION_6; + default: + return WIFI_GENERATION_UNKNOWN; + } + } + + winrt::IAsyncOperation GetWiFiNetwork(winrt::NetworkAdapter adapter, winrt::hstring ssid) + { + // Unfortunately UWP doesn't have any APIs for getting WiFi network info for an existing connection. We have to trigger a scan + // of available networks and walk through them to get details. + try { + // This call only works if the app has the "wiFiControl" capability enabled in its appxmanifest, otherwise it will throw. + auto wifiAdapters = co_await WiFiAdapter::FindAllAdaptersAsync(); + for (const auto& wifiAdapter : wifiAdapters) + { + if (wifiAdapter.NetworkAdapter().NetworkAdapterId() == adapter.NetworkAdapterId()) { + auto networks = wifiAdapter.NetworkReport().AvailableNetworks(); + for (const auto& network : networks) { + if (network.Ssid() == ssid) { + co_return network; + } + } + } + } + } + catch (...) {} + co_return nullptr; + } + + void RNCNetInfo::Initialize(winrt::Microsoft::ReactNative::ReactContext const& /*reactContext*/) noexcept { + + // NetworkStatusChanged callback is captured by value on purpose. The event handler is called asynchronously and thus can fire even + // after we've already revoked it in our destructor during module teardown. In such a case, a reference + // to "this" or "this->NetworkStatusChanged" would be invalid. + m_networkStatusChangedRevoker = NetworkInformation::NetworkStatusChanged(winrt::auto_revoke, [callback = NetworkStatusChanged](const winrt::IInspectable& /*sender*/) -> winrt::fire_and_forget { + try { + // Copy lambda capture into a local so it still exists after the co_await. + auto localCallback = callback; + localCallback(co_await GetNetworkStatus()); + } + catch (...) {} + }); + } + + winrt::fire_and_forget RNCNetInfo::getCurrentState(std::string requestedInterface, winrt::Microsoft::ReactNative::ReactPromise promise) noexcept { + // Jump to background to avoid blocking the JS thread while we gather the requested data + co_await winrt::resume_background(); + + promise.Resolve(co_await GetNetworkStatus()); + } + + /*static*/ std::future RNCNetInfo::GetNetworkStatus() { + NetInfoState state{}; + + // https://docs.microsoft.com/en-us/uwp/api/windows.networking.connectivity.connectionprofile + try { + auto profile = NetworkInformation::GetInternetConnectionProfile(); + if (profile) { + auto networkAdapter = profile.NetworkAdapter(); + auto connectivityLevel = profile.GetNetworkConnectivityLevel(); + auto signal = profile.GetSignalBars(); + auto costType = profile.GetConnectionCost().NetworkCostType(); + + state.isConnected = connectivityLevel != NetworkConnectivityLevel::None; + + if (state.isConnected) { + NetInfoDetails details{}; + + state.isInternetReachable = connectivityLevel == NetworkConnectivityLevel::InternetAccess; + details.isConnectionExpensive = costType == NetworkCostType::Fixed || costType == NetworkCostType::Variable; + if (signal) { + details.strength = winrt::unbox_value(signal) * 20; // Signal strength is 0-5 but we want 0-100. + } + + if (profile.IsWlanConnectionProfile()) { + auto wlanDetails = profile.WlanConnectionProfileDetails(); + auto ssid = wlanDetails.GetConnectedSsid(); + auto network = co_await GetWiFiNetwork(networkAdapter, ssid); + + state.type = CONNECTION_TYPE_WIFI; + details.ssid = winrt::to_string(ssid); + if (network) { + details.bssid = winrt::to_string(network.Bssid()); + details.frequency = network.ChannelCenterFrequencyInKilohertz() / 1000; // Convert to Mhz + details.wifiGeneration = GetWifiGeneration(network.PhyKind()); + } + } + else if (profile.IsWwanConnectionProfile()) { + auto wwanDetails = profile.WwanConnectionProfileDetails(); + auto dataClass = wwanDetails.GetCurrentDataClass(); + + state.type = CONNECTION_TYPE_CELLULAR; + details.cellularGeneration = GetCellularGeneration(dataClass); + } + else if (networkAdapter) { + // Possible values: https://docs.microsoft.com/en-us/uwp/api/windows.networking.connectivity.networkadapter.ianainterfacetype + if (networkAdapter.IanaInterfaceType() == 6u) { + state.type = CONNECTION_TYPE_ETHERNET; + } + else { + state.type = CONNECTION_TYPE_OTHER; + } + } + else { + state.type = CONNECTION_TYPE_UNKNOWN; + } + + state.details = std::move(details); + } + } + } + catch (...) { + } + + co_return state; + } +} \ No newline at end of file diff --git a/windows/RNCNetInfoCPP/RNCNetInfo.h b/windows/RNCNetInfoCPP/RNCNetInfo.h index 907fad1b..af504355 100644 --- a/windows/RNCNetInfoCPP/RNCNetInfo.h +++ b/windows/RNCNetInfoCPP/RNCNetInfo.h @@ -2,56 +2,81 @@ // Licensed under the MIT License. #pragma once -#include "pch.h" #include +#include +#include +#include +#include #include "NativeModules.h" -#include "NetworkInfo.h" namespace winrt::ReactNativeNetInfo::implementation { + REACT_STRUCT(NetInfoDetails); + struct NetInfoDetails { + REACT_FIELD(isConnectionExpensive); + bool isConnectionExpensive; + + REACT_FIELD(cellularGeneration); + std::optional cellularGeneration; + + REACT_FIELD(wifiGeneration); + std::optional wifiGeneration; + + REACT_FIELD(ssid); + std::optional ssid; + + REACT_FIELD(bssid); + std::optional bssid; + + REACT_FIELD(strength); + std::optional strength; + + REACT_FIELD(frequency); + std::optional frequency; + }; + + REACT_STRUCT(NetInfoState); + struct NetInfoState { + /// + /// The type of the active network connection + /// + /// + REACT_FIELD(type); + std::string type; + + /// + /// Is there an active network connection + /// + /// + REACT_FIELD(isConnected); + bool isConnected; + + /// + /// Is the internet reachable with the active network + /// + /// + REACT_FIELD(isInternetReachable); + std::optional isInternetReachable; + + REACT_FIELD(details); + std::optional details; + }; + REACT_MODULE(RNCNetInfo); struct RNCNetInfo { - NetworkInfo networkInfo; + public: + REACT_INIT(Initialize); + void Initialize(winrt::Microsoft::ReactNative::ReactContext const& reactContext) noexcept; - RNCNetInfo() { - networkInfo.StatusChanged([&](const auto& /*sender*/) { - NetworkStatusChanged(CreateNetInfoStateObject()); - }); - } + REACT_METHOD(getCurrentState); + winrt::fire_and_forget getCurrentState(std::string requestedInterface, winrt::Microsoft::ReactNative::ReactPromise promise) noexcept; REACT_EVENT(NetworkStatusChanged, L"netInfo.networkStatusDidChange"); - std::function NetworkStatusChanged; + std::function NetworkStatusChanged; - REACT_METHOD(getCurrentState); - void getCurrentState(std::string requestedInterface, - ReactPromise const& promise) noexcept { - promise.Resolve(CreateNetInfoStateObject()); - } - - JSValue CreateNetInfoStateObject() - { - auto isConnected = networkInfo.IsConnected(); - auto type = networkInfo.ConnectivityType(); - auto detailsWriter = MakeJSValueTreeWriter(); - if (isConnected) { - detailsWriter.WriteObjectBegin(); - WriteProperty(detailsWriter, L"isConnectionExpensive", networkInfo.IsConnectionExpensive()); - if (type == NetworkInfo::CONNECTION_TYPE_CELLULAR) - { - WriteProperty(detailsWriter, L"cellularGeneration", networkInfo.CellularGeneration()); - } - detailsWriter.WriteObjectEnd(); - } - - auto writer = winrt::Microsoft::ReactNative::MakeJSValueTreeWriter(); - writer.WriteObjectBegin(); - WriteProperty(writer, L"type", type); - WriteProperty(writer, L"isConnected", isConnected); - if (isConnected) { - WriteProperty(writer, L"details", TakeJSValue(detailsWriter)); - } - writer.WriteObjectEnd(); - return TakeJSValue(writer); - } + static std::future GetNetworkStatus(); + + private: + winrt::Windows::Networking::Connectivity::NetworkInformation::NetworkStatusChanged_revoker m_networkStatusChangedRevoker{}; }; } \ No newline at end of file diff --git a/windows/RNCNetInfoCPP/RNCNetInfoCPP.vcxproj b/windows/RNCNetInfoCPP/RNCNetInfoCPP.vcxproj index 9587f409..5fecea68 100644 --- a/windows/RNCNetInfoCPP/RNCNetInfoCPP.vcxproj +++ b/windows/RNCNetInfoCPP/RNCNetInfoCPP.vcxproj @@ -113,7 +113,6 @@ ReactPackageProvider.idl - @@ -124,8 +123,8 @@ ReactPackageProvider.idl - + diff --git a/windows/RNCNetInfoCPP/RNCNetInfoCPP.vcxproj.filters b/windows/RNCNetInfoCPP/RNCNetInfoCPP.vcxproj.filters index 19ebfadd..5b15c094 100644 --- a/windows/RNCNetInfoCPP/RNCNetInfoCPP.vcxproj.filters +++ b/windows/RNCNetInfoCPP/RNCNetInfoCPP.vcxproj.filters @@ -7,12 +7,11 @@ - + - diff --git a/windows/RNCNetInfoCPP/pch.h b/windows/RNCNetInfoCPP/pch.h index 4ee087d0..8fe0e977 100644 --- a/windows/RNCNetInfoCPP/pch.h +++ b/windows/RNCNetInfoCPP/pch.h @@ -12,5 +12,3 @@ #include #include #include - -using namespace winrt::Windows::Foundation;