@amazon-devices/expo-network 2.0.1758683737
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc.js +2 -0
- package/CHANGELOG.md +156 -0
- package/CMakeLists.txt +50 -0
- package/LICENSE +7 -0
- package/README.kepler.md +104 -0
- package/README.md +44 -0
- package/THIRD_PARTY_NOTICES.txt +24 -0
- package/android/build.gradle +107 -0
- package/android/src/main/AndroidManifest.xml +4 -0
- package/android/src/main/java/expo/modules/network/NetworkExceptions.kt +9 -0
- package/android/src/main/java/expo/modules/network/NetworkModule.kt +144 -0
- package/android/src/main/java/expo/modules/network/NetworkUtils.kt +7 -0
- package/build/ExpoNetwork.d.ts +3 -0
- package/build/ExpoNetwork.d.ts.map +1 -0
- package/build/ExpoNetwork.js +3 -0
- package/build/ExpoNetwork.js.map +1 -0
- package/build/ExpoNetwork.kepler.d.ts +9 -0
- package/build/ExpoNetwork.kepler.d.ts.map +1 -0
- package/build/ExpoNetwork.kepler.js +62 -0
- package/build/ExpoNetwork.kepler.js.map +1 -0
- package/build/ExpoNetwork.web.d.ts +7 -0
- package/build/ExpoNetwork.web.d.ts.map +1 -0
- package/build/ExpoNetwork.web.js +22 -0
- package/build/ExpoNetwork.web.js.map +1 -0
- package/build/Network.d.ts +50 -0
- package/build/Network.d.ts.map +1 -0
- package/build/Network.js +70 -0
- package/build/Network.js.map +1 -0
- package/build/Network.types.d.ts +62 -0
- package/build/Network.types.d.ts.map +1 -0
- package/build/Network.types.js +45 -0
- package/build/Network.types.js.map +1 -0
- package/expo-module.config.json +10 -0
- package/ios/Exceptions.swift +7 -0
- package/ios/ExpoNetwork.podspec +31 -0
- package/ios/NetworkModule.swift +102 -0
- package/ios/NetworkType.swift +28 -0
- package/kepler/ExpoNetwork.cpp +55 -0
- package/kepler/ExpoNetwork.h +24 -0
- package/kepler/KeplerInit.cpp +28 -0
- package/kepler/NetworkInterfaces.cpp +74 -0
- package/kepler/NetworkInterfaces.h +20 -0
- package/kepler/test/Network.cpp +147 -0
- package/package.json +1 -0
- package/react-native.config.js +21 -0
- package/src/ExpoNetwork.kepler.ts +80 -0
- package/src/ExpoNetwork.ts +2 -0
- package/src/ExpoNetwork.web.ts +21 -0
- package/src/Network.ts +74 -0
- package/src/Network.types.ts +64 -0
- package/tsconfig.json +9 -0
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) 2023 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
3
|
+
*
|
|
4
|
+
* PROPRIETARY/CONFIDENTIAL
|
|
5
|
+
*
|
|
6
|
+
* Use is subject to license terms.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
#include <KeplerScript/logger/KPLog.h>
|
|
10
|
+
#include <KeplerScript/utils/autolink/KeplerAutoLinkInfo.h>
|
|
11
|
+
#include <keplerui-072/keplerscript-export.h>
|
|
12
|
+
|
|
13
|
+
#include "ExpoNetwork.h"
|
|
14
|
+
#include "RegisterModule.h"
|
|
15
|
+
|
|
16
|
+
extern "C" {
|
|
17
|
+
KEPLERSCRIPT_EXPORT void keplerAutoLinkInitV1(const kepler::autolink::v1::KeplerAutoLinkInfo* autoLinkInfo) noexcept {
|
|
18
|
+
volta::react::KPLog.debug("keplerAutoLinkInitV1 for ExpoNetwork");
|
|
19
|
+
|
|
20
|
+
REGISTER_MODULE(autoLinkInfo, ExpoNetwork, "ExpoNetwork");
|
|
21
|
+
|
|
22
|
+
volta::react::KPLog.debug("after registering module");
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
int main() {
|
|
27
|
+
return 0;
|
|
28
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) 2023 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
3
|
+
*
|
|
4
|
+
* PROPRIETARY/CONFIDENTIAL
|
|
5
|
+
*
|
|
6
|
+
* Use is subject to license terms.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
#include "NetworkInterfaces.h"
|
|
10
|
+
|
|
11
|
+
#include <KeplerScript/logger/KPLog.h>
|
|
12
|
+
#include <arpa/inet.h>
|
|
13
|
+
#include <ifaddrs.h>
|
|
14
|
+
#include <linux/if_link.h>
|
|
15
|
+
#include <netdb.h>
|
|
16
|
+
#include <stdio.h>
|
|
17
|
+
#include <stdlib.h>
|
|
18
|
+
#include <sys/socket.h>
|
|
19
|
+
#include <sys/wait.h>
|
|
20
|
+
#include <unistd.h>
|
|
21
|
+
|
|
22
|
+
namespace {
|
|
23
|
+
const std::string unresolvedAddress = "0.0.0.0";
|
|
24
|
+
const std::string wlanInterfaceName = "wlan0";
|
|
25
|
+
} // namespace
|
|
26
|
+
|
|
27
|
+
NetworkInterfaces::NetworkInterfaces() {
|
|
28
|
+
if (getifaddrs(&ifaddr) == -1) {
|
|
29
|
+
throw std::runtime_error("network interfaces info failed to fetch.");
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
NetworkInterfaces::~NetworkInterfaces() {
|
|
34
|
+
freeifaddrs(ifaddr);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
std::string NetworkInterfaces::wlanInterfaceAddress() {
|
|
38
|
+
try {
|
|
39
|
+
char host[NI_MAXHOST];
|
|
40
|
+
|
|
41
|
+
for (auto* ifa = ifaddr; ifa != nullptr; ifa = ifa->ifa_next) {
|
|
42
|
+
if (ifa->ifa_addr == nullptr) {
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
auto ifFamily = ifa->ifa_addr->sa_family;
|
|
47
|
+
if (ifFamily == AF_INET && std::string(ifa->ifa_name) == wlanInterfaceName) {
|
|
48
|
+
auto nameInfo = getnameinfo(
|
|
49
|
+
ifa->ifa_addr,
|
|
50
|
+
sizeof(struct sockaddr_in),
|
|
51
|
+
host,
|
|
52
|
+
NI_MAXHOST,
|
|
53
|
+
nullptr,
|
|
54
|
+
0,
|
|
55
|
+
NI_NUMERICHOST);
|
|
56
|
+
if (nameInfo != 0) {
|
|
57
|
+
throw std::runtime_error("wlan interface info failed to fetch.");
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return std::string(host);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
volta::react::KPLog.error("No wlan interface found.");
|
|
65
|
+
} catch (std::exception& e) {
|
|
66
|
+
volta::react::KPLog.error("Can't get ip address: {}", std::string(e.what()));
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return unresolvedAddress;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
bool NetworkInterfaces::isNetworkConnected() {
|
|
73
|
+
return wlanInterfaceAddress() != unresolvedAddress;
|
|
74
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) 2023 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
3
|
+
*
|
|
4
|
+
* PROPRIETARY/CONFIDENTIAL
|
|
5
|
+
*
|
|
6
|
+
* Use is subject to license terms.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
#include <string>
|
|
10
|
+
|
|
11
|
+
class NetworkInterfaces {
|
|
12
|
+
public:
|
|
13
|
+
NetworkInterfaces();
|
|
14
|
+
~NetworkInterfaces();
|
|
15
|
+
std::string wlanInterfaceAddress();
|
|
16
|
+
bool isNetworkConnected();
|
|
17
|
+
|
|
18
|
+
private:
|
|
19
|
+
struct ifaddrs* ifaddr;
|
|
20
|
+
};
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
3
|
+
*
|
|
4
|
+
* PROPRIETARY/CONFIDENTIAL
|
|
5
|
+
*
|
|
6
|
+
* Use is subject to license terms.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
#include <gmock/gmock-actions.h>
|
|
10
|
+
#include <gmock/gmock.h>
|
|
11
|
+
#include <gtest/gtest.h>
|
|
12
|
+
|
|
13
|
+
#include <iostream>
|
|
14
|
+
|
|
15
|
+
#include "../ExpoNetwork.h"
|
|
16
|
+
#include "JSObjectsConversion.h"
|
|
17
|
+
#include "catch.hpp"
|
|
18
|
+
|
|
19
|
+
namespace {
|
|
20
|
+
bool isValidIPv4Address(const std::string& s) {
|
|
21
|
+
std::stringstream ss(s);
|
|
22
|
+
std::string segment;
|
|
23
|
+
int segmentCount = 0;
|
|
24
|
+
|
|
25
|
+
while (std::getline(ss, segment, '.')) {
|
|
26
|
+
++segmentCount;
|
|
27
|
+
|
|
28
|
+
if (segment.empty() || segment.length() > 3 || !std::all_of(segment.begin(), segment.end(), ::isdigit) ||
|
|
29
|
+
stoi(segment) > 255 || (segment[0] == '0' && segment.length() > 1)) {
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
return segmentCount == 4;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
void handlePromiseRejection(volta::react::NativeJSObject payload) {
|
|
38
|
+
std::string rejectionMessage = std::get<std::string>(payload["message"]);
|
|
39
|
+
FAIL(rejectionMessage);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
enum NetworkState {
|
|
43
|
+
NONE = 0,
|
|
44
|
+
WIFI = 3,
|
|
45
|
+
};
|
|
46
|
+
} // namespace
|
|
47
|
+
|
|
48
|
+
SCENARIO("Testing Expo Network module") {
|
|
49
|
+
GIVEN("Expo Network module") {
|
|
50
|
+
ExpoNetwork networkModule;
|
|
51
|
+
|
|
52
|
+
// Unable to test due to lack of 'Promise' support
|
|
53
|
+
// WHEN("getIpAddressAsync is called") {
|
|
54
|
+
// auto promise = networkModule.getIpAddressAsync();
|
|
55
|
+
|
|
56
|
+
// promise.promiseOperation_(std::make_shared<volta::react::Promise>(
|
|
57
|
+
// volta::react::Callback([](auto args) {
|
|
58
|
+
// THEN("Resolved promise contains valid IP") {
|
|
59
|
+
// REQUIRE(args.size() == 1);
|
|
60
|
+
// REQUIRE(std::holds_alternative<std::string>(args[0]));
|
|
61
|
+
|
|
62
|
+
// auto ipAddress = std::get<std::string>(args[0]);
|
|
63
|
+
|
|
64
|
+
// REQUIRE(isValidIPv4Address(ipAddress));
|
|
65
|
+
// }
|
|
66
|
+
// }),
|
|
67
|
+
// volta::react::Callback([](auto args) {
|
|
68
|
+
// volta::react::NativeJSObject payload = ExpoUtils::convertJsonContainerToNativeJSObject(
|
|
69
|
+
// std::get<utils::json::JsonContainer>(args[0]));
|
|
70
|
+
// handlePromiseRejection(payload);
|
|
71
|
+
// })));
|
|
72
|
+
// }
|
|
73
|
+
|
|
74
|
+
// Unable to test due to lack of 'Promise' support
|
|
75
|
+
// WHEN("getNetworkStateAsync is called") {
|
|
76
|
+
// auto promise = networkModule.getNetworkStateAsync();
|
|
77
|
+
|
|
78
|
+
// promise.promiseOperation_(std::make_shared<volta::react::Promise>(
|
|
79
|
+
// volta::react::Callback([](auto args) {
|
|
80
|
+
// THEN("Resolved promise contains valid network state object") {
|
|
81
|
+
// REQUIRE(args.size() == 1);
|
|
82
|
+
// REQUIRE(std::holds_alternative<utils::json::JsonContainer>(args[0]));
|
|
83
|
+
|
|
84
|
+
// volta::react::NativeJSObject networkState =
|
|
85
|
+
// ExpoUtils::convertJsonContainerToNativeJSObject(
|
|
86
|
+
// std::get<utils::json::JsonContainer>(args[0]));
|
|
87
|
+
|
|
88
|
+
// REQUIRE(std::holds_alternative<int32_t>(networkState["type"]));
|
|
89
|
+
// REQUIRE(std::holds_alternative<bool>(networkState["isConnected"]));
|
|
90
|
+
|
|
91
|
+
// auto type = std::get<int32_t>(networkState["type"]);
|
|
92
|
+
// auto isConnected = std::get<bool>(networkState["isConnected"]);
|
|
93
|
+
|
|
94
|
+
// if (isConnected) {
|
|
95
|
+
// REQUIRE(type == WIFI);
|
|
96
|
+
// } else {
|
|
97
|
+
// REQUIRE(type == NONE);
|
|
98
|
+
// }
|
|
99
|
+
// }
|
|
100
|
+
// }),
|
|
101
|
+
// volta::react::Callback([](auto args) {
|
|
102
|
+
// volta::react::NativeJSObject payload = ExpoUtils::convertJsonContainerToNativeJSObject(
|
|
103
|
+
// std::get<utils::json::JsonContainer>(args[0]));
|
|
104
|
+
// handlePromiseRejection(payload);
|
|
105
|
+
// })));
|
|
106
|
+
// }
|
|
107
|
+
|
|
108
|
+
// Unable to test due to lack of 'Promise' support
|
|
109
|
+
// WHEN("isAirplaneModeEnabledAsync is called") {
|
|
110
|
+
// auto promise = networkModule.isAirplaneModeEnabledAsync();
|
|
111
|
+
|
|
112
|
+
// promise.promiseOperation_(std::make_shared<volta::react::Promise>(
|
|
113
|
+
// volta::react::Callback([](auto args) {
|
|
114
|
+
// THEN("Resolved promise contains false boolean") {
|
|
115
|
+
// REQUIRE(args.size() == 1);
|
|
116
|
+
// REQUIRE(std::holds_alternative<bool>(args[0]));
|
|
117
|
+
|
|
118
|
+
// auto isAirplaneModeEnabled = std::get<bool>(args[0]);
|
|
119
|
+
// REQUIRE_FALSE(isAirplaneModeEnabled);
|
|
120
|
+
// }
|
|
121
|
+
// }),
|
|
122
|
+
// volta::react::Callback([](auto args) {
|
|
123
|
+
// volta::react::NativeJSObject payload = ExpoUtils::convertJsonContainerToNativeJSObject(
|
|
124
|
+
// std::get<utils::json::JsonContainer>(args[0]));
|
|
125
|
+
// handlePromiseRejection(payload);
|
|
126
|
+
// })));
|
|
127
|
+
// }
|
|
128
|
+
|
|
129
|
+
WHEN("aggregateMethods is called") {
|
|
130
|
+
std::weak_ptr<facebook::react::Instance> instance;
|
|
131
|
+
networkModule.triggerMethodAggregation(*networkModule.jsQueue_, instance);
|
|
132
|
+
|
|
133
|
+
THEN("methodContainerMap contains expected methods") {
|
|
134
|
+
REQUIRE(networkModule.methodContainerMap_.find("getIpAddressAsync") !=
|
|
135
|
+
networkModule.methodContainerMap_.end());
|
|
136
|
+
REQUIRE(networkModule.methodContainerMap_.find("getNetworkStateAsync") !=
|
|
137
|
+
networkModule.methodContainerMap_.end());
|
|
138
|
+
REQUIRE(networkModule.methodContainerMap_.find("isAirplaneModeEnabledAsync") !=
|
|
139
|
+
networkModule.methodContainerMap_.end());
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
THEN("size of methodContainerMap is increased by addListener and removeListeners") {
|
|
143
|
+
REQUIRE(networkModule.methodContainerMap_.size() == 5);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"name": "@amazon-devices/expo-network", "version": "2.0.1758683737+5.7.0", "description": "Provides useful information about the device's network such as its IP address, MAC address, and airplane mode status", "main": "build/Network.js", "types": "build/Network.d.ts", "scripts": {"build": "expo-module build", "clean": "expo-module clean", "lint": "expo-module lint", "test": "expo-module test", "expo-module": "expo-module"}, "kepler": {"temporary-alias-for-package": {"name": "expo-network", "version": "5.7.0"}}, "keywords": ["react-native", "expo", "expo-network"], "repository": {"type": "git", "url": "https://github.com/expo/expo.git", "directory": "packages/expo-network"}, "bugs": {"url": "https://github.com/expo/expo/issues"}, "author": "650 Industries, Inc.", "license": "See license in LICENSE", "homepage": "https://docs.expo.dev/versions/latest/sdk/network/", "dependencies": {"@amazon-devices/keplerscript-turbomodule-api": "^1.0.0"}, "devDependencies": {"expo-module-scripts": "^3.0.0"}, "peerDependencies": {"expo": "*"}, "jest": {"preset": "expo-module-scripts"}}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
module.exports = {
|
|
2
|
+
dependencies: {
|
|
3
|
+
'@amazon-devices/react-native-kepler': {
|
|
4
|
+
platforms: {
|
|
5
|
+
kepler: null, // do not use platform definition from @react-native-kepler
|
|
6
|
+
},
|
|
7
|
+
},
|
|
8
|
+
},
|
|
9
|
+
dependency: {
|
|
10
|
+
platforms: {
|
|
11
|
+
kepler: {
|
|
12
|
+
autolink: {
|
|
13
|
+
ExpoNetworkLib: {
|
|
14
|
+
provider: 'system',
|
|
15
|
+
turbomodules: ['ExpoNetwork'],
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
};
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import {KeplerTurboModule, TurboModuleRegistry} from '@amazon-devices/keplerscript-turbomodule-api';
|
|
2
|
+
import {NetworkState, NetworkStateType} from './Network.types';
|
|
3
|
+
|
|
4
|
+
export {NetworkState, NetworkStateType};
|
|
5
|
+
|
|
6
|
+
type NativeModuleNetworkState = {
|
|
7
|
+
isConnected: boolean; isInternetReachable: boolean; type: number;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
interface Spec extends KeplerTurboModule {
|
|
11
|
+
getNetworkStateAsync(): Promise<NativeModuleNetworkState>;
|
|
12
|
+
getIpAddressAsync(): Promise<string>;
|
|
13
|
+
isAirplaneModeEnabledAsync(): Promise<boolean>;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const nativeModule = TurboModuleRegistry.getEnforcing<Spec>('ExpoNetwork') as Spec;
|
|
17
|
+
|
|
18
|
+
const networkStateNumberToType = (num: number): NetworkStateType => {
|
|
19
|
+
switch (num) {
|
|
20
|
+
case 0:
|
|
21
|
+
return NetworkStateType.NONE;
|
|
22
|
+
case 1:
|
|
23
|
+
return NetworkStateType.UNKNOWN;
|
|
24
|
+
case 2:
|
|
25
|
+
return NetworkStateType.CELLULAR;
|
|
26
|
+
case 3:
|
|
27
|
+
return NetworkStateType.WIFI;
|
|
28
|
+
case 4:
|
|
29
|
+
return NetworkStateType.BLUETOOTH;
|
|
30
|
+
case 5:
|
|
31
|
+
return NetworkStateType.ETHERNET;
|
|
32
|
+
case 6:
|
|
33
|
+
return NetworkStateType.WIMAX;
|
|
34
|
+
case 7:
|
|
35
|
+
return NetworkStateType.VPN;
|
|
36
|
+
case 8:
|
|
37
|
+
return NetworkStateType.OTHER;
|
|
38
|
+
default:
|
|
39
|
+
return NetworkStateType.UNKNOWN;
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
async function fetchWithTimeout(url: string) {
|
|
44
|
+
const controller = new AbortController();
|
|
45
|
+
const id = setTimeout(() => controller.abort(), 800);
|
|
46
|
+
|
|
47
|
+
const response = await fetch(url, {signal: controller.signal});
|
|
48
|
+
clearTimeout(id);
|
|
49
|
+
|
|
50
|
+
return response;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const module = {
|
|
54
|
+
async getNetworkStateAsync(): Promise<NetworkState> {
|
|
55
|
+
const state = await nativeModule.getNetworkStateAsync();
|
|
56
|
+
|
|
57
|
+
let dnsResponseReceived = false;
|
|
58
|
+
try {
|
|
59
|
+
const response = await fetchWithTimeout('https://dns.google/');
|
|
60
|
+
dnsResponseReceived = !!response?.ok;
|
|
61
|
+
} catch (error) {
|
|
62
|
+
dnsResponseReceived = false;
|
|
63
|
+
console.error(error)
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return {
|
|
67
|
+
type: networkStateNumberToType(state.type),
|
|
68
|
+
isConnected: state.isConnected,
|
|
69
|
+
isInternetReachable: dnsResponseReceived,
|
|
70
|
+
};
|
|
71
|
+
},
|
|
72
|
+
async getIpAddressAsync(): Promise<string> {
|
|
73
|
+
return nativeModule.getIpAddressAsync();
|
|
74
|
+
},
|
|
75
|
+
async isAirplaneModeEnabledAsync(): Promise<boolean> {
|
|
76
|
+
return nativeModule.isAirplaneModeEnabledAsync();
|
|
77
|
+
},
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
export default module;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { NetworkState, NetworkStateType } from './Network.types';
|
|
2
|
+
|
|
3
|
+
export default {
|
|
4
|
+
async getIpAddressAsync(): Promise<string> {
|
|
5
|
+
try {
|
|
6
|
+
const resp = await fetch('https://api.ipify.org?format=json');
|
|
7
|
+
const data = await resp.json();
|
|
8
|
+
return data.ip;
|
|
9
|
+
} catch (e) {
|
|
10
|
+
throw e;
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
async getNetworkStateAsync(): Promise<NetworkState> {
|
|
14
|
+
const isOnline = typeof navigator !== 'undefined' && navigator.onLine;
|
|
15
|
+
return {
|
|
16
|
+
type: isOnline ? NetworkStateType.UNKNOWN : NetworkStateType.NONE,
|
|
17
|
+
isConnected: isOnline,
|
|
18
|
+
isInternetReachable: isOnline,
|
|
19
|
+
};
|
|
20
|
+
},
|
|
21
|
+
};
|
package/src/Network.ts
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { UnavailabilityError } from 'expo-modules-core';
|
|
2
|
+
|
|
3
|
+
import ExpoNetwork from './ExpoNetwork';
|
|
4
|
+
import { NetworkState, NetworkStateType } from './Network.types';
|
|
5
|
+
|
|
6
|
+
export { NetworkState, NetworkStateType };
|
|
7
|
+
|
|
8
|
+
// @needsAudit
|
|
9
|
+
/**
|
|
10
|
+
* Gets the device's current network connection state.
|
|
11
|
+
*
|
|
12
|
+
* On web, `navigator.connection.type` is not available on browsers. So if there is an active
|
|
13
|
+
* network connection, the field `type` returns `NetworkStateType.UNKNOWN`. Otherwise, it returns
|
|
14
|
+
* `NetworkStateType.NONE`.
|
|
15
|
+
* @return A `Promise` that fulfils with a `NetworkState` object.
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```ts
|
|
19
|
+
* await Network.getNetworkStateAsync();
|
|
20
|
+
* // {
|
|
21
|
+
* // type: NetworkStateType.CELLULAR,
|
|
22
|
+
* // isConnected: true,
|
|
23
|
+
* // isInternetReachable: true,
|
|
24
|
+
* // }
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
27
|
+
export async function getNetworkStateAsync(): Promise<NetworkState> {
|
|
28
|
+
if (!ExpoNetwork.getNetworkStateAsync) {
|
|
29
|
+
throw new UnavailabilityError('expo-network', 'getNetworkStateAsync');
|
|
30
|
+
}
|
|
31
|
+
return await ExpoNetwork.getNetworkStateAsync();
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// @needsAudit
|
|
35
|
+
/**
|
|
36
|
+
* Gets the device's current IPv4 address. Returns `0.0.0.0` if the IP address could not be retrieved.
|
|
37
|
+
*
|
|
38
|
+
* On web, this method uses the third-party [`ipify service`](https://www.ipify.org/) to get the
|
|
39
|
+
* public IP address of the current device.
|
|
40
|
+
* @return A `Promise` that fulfils with a `string` of the current IP address of the device's main
|
|
41
|
+
* network interface. Can only be IPv4 address.
|
|
42
|
+
*
|
|
43
|
+
* @example
|
|
44
|
+
* ```ts
|
|
45
|
+
* await Network.getIpAddressAsync();
|
|
46
|
+
* // "92.168.32.44"
|
|
47
|
+
* ```
|
|
48
|
+
*/
|
|
49
|
+
export async function getIpAddressAsync(): Promise<string> {
|
|
50
|
+
if (!ExpoNetwork.getIpAddressAsync) {
|
|
51
|
+
throw new UnavailabilityError('expo-network', 'getIpAddressAsync');
|
|
52
|
+
}
|
|
53
|
+
return await ExpoNetwork.getIpAddressAsync();
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// @needsAudit
|
|
57
|
+
/**
|
|
58
|
+
* Tells if the device is in airplane mode.
|
|
59
|
+
* @return Returns a `Promise` that fulfils with a `boolean` value for whether the device is in
|
|
60
|
+
* airplane mode or not.
|
|
61
|
+
* @platform android
|
|
62
|
+
*
|
|
63
|
+
* @example
|
|
64
|
+
* ```ts
|
|
65
|
+
* await Network.isAirplaneModeEnabledAsync();
|
|
66
|
+
* // false
|
|
67
|
+
* ```
|
|
68
|
+
*/
|
|
69
|
+
export async function isAirplaneModeEnabledAsync(): Promise<boolean> {
|
|
70
|
+
if (!ExpoNetwork.isAirplaneModeEnabledAsync) {
|
|
71
|
+
throw new UnavailabilityError('expo-network', 'isAirplaneModeEnabledAsync');
|
|
72
|
+
}
|
|
73
|
+
return await ExpoNetwork.isAirplaneModeEnabledAsync();
|
|
74
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
// @needsAudit
|
|
2
|
+
export type NetworkState = {
|
|
3
|
+
/**
|
|
4
|
+
* A [`NetworkStateType`](#networkstatetype) enum value that represents the current network
|
|
5
|
+
* connection type.
|
|
6
|
+
*/
|
|
7
|
+
type?: NetworkStateType;
|
|
8
|
+
/**
|
|
9
|
+
* If there is an active network connection. Note that this does not mean that internet is reachable.
|
|
10
|
+
* This field is `false` if the type is either `Network.NetworkStateType.NONE` or `Network.NetworkStateType.UNKNOWN`,
|
|
11
|
+
* `true` otherwise.
|
|
12
|
+
*/
|
|
13
|
+
isConnected?: boolean;
|
|
14
|
+
/**
|
|
15
|
+
* If the internet is reachable with the currently active network connection. On Android, this
|
|
16
|
+
* depends on `NetInfo.isConnected()` (API level < 29) or `ConnectivityManager.getActiveNetwork()`
|
|
17
|
+
* (API level >= 29). On iOS, this value will always be the same as `isConnected`.
|
|
18
|
+
*/
|
|
19
|
+
isInternetReachable?: boolean;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
// @needsAudit
|
|
23
|
+
/**
|
|
24
|
+
* An enum of the different types of devices supported by Expo.
|
|
25
|
+
*/
|
|
26
|
+
export enum NetworkStateType {
|
|
27
|
+
/**
|
|
28
|
+
* No active network connection detected.
|
|
29
|
+
*/
|
|
30
|
+
NONE = 'NONE',
|
|
31
|
+
/**
|
|
32
|
+
* The connection type could not be determined.
|
|
33
|
+
*/
|
|
34
|
+
UNKNOWN = 'UNKNOWN',
|
|
35
|
+
/**
|
|
36
|
+
* Active network connection over mobile data or [`DUN-specific`](https://developer.android.com/reference/android/net/ConnectivityManager#TYPE_MOBILE_DUN)
|
|
37
|
+
* mobile connection when setting an upstream connection for tethering.
|
|
38
|
+
*/
|
|
39
|
+
CELLULAR = 'CELLULAR',
|
|
40
|
+
/**
|
|
41
|
+
* Active network connection over WiFi.
|
|
42
|
+
*/
|
|
43
|
+
WIFI = 'WIFI',
|
|
44
|
+
/**
|
|
45
|
+
* Active network connection over Bluetooth.
|
|
46
|
+
*/
|
|
47
|
+
BLUETOOTH = 'BLUETOOTH',
|
|
48
|
+
/**
|
|
49
|
+
* Active network connection over Ethernet.
|
|
50
|
+
*/
|
|
51
|
+
ETHERNET = 'ETHERNET',
|
|
52
|
+
/**
|
|
53
|
+
* Active network connection over Wimax.
|
|
54
|
+
*/
|
|
55
|
+
WIMAX = 'WIMAX',
|
|
56
|
+
/**
|
|
57
|
+
* Active network connection over VPN.
|
|
58
|
+
*/
|
|
59
|
+
VPN = 'VPN',
|
|
60
|
+
/**
|
|
61
|
+
* Active network connection over other network connection types.
|
|
62
|
+
*/
|
|
63
|
+
OTHER = 'OTHER',
|
|
64
|
+
}
|