@ohos-ports/expo-network 57.0.2-beta.0
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/CHANGELOG.md +391 -0
- package/LICENSE +21 -0
- package/README.md +44 -0
- package/android/build.gradle +27 -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 +281 -0
- package/android/src/main/java/expo/modules/network/NetworkUtils.kt +52 -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.web.d.ts +14 -0
- package/build/ExpoNetwork.web.d.ts.map +1 -0
- package/build/ExpoNetwork.web.js +47 -0
- package/build/ExpoNetwork.web.js.map +1 -0
- package/build/Network.d.ts +80 -0
- package/build/Network.d.ts.map +1 -0
- package/build/Network.js +111 -0
- package/build/Network.js.map +1 -0
- package/build/Network.types.d.ts +85 -0
- package/build/Network.types.d.ts.map +1 -0
- package/build/Network.types.js +55 -0
- package/build/Network.types.js.map +1 -0
- package/expo-module.config.json +15 -0
- package/ios/Exceptions.swift +7 -0
- package/ios/ExpoNetwork.podspec +28 -0
- package/ios/NetworkModule.swift +155 -0
- package/ios/NetworkType.swift +30 -0
- package/local-maven-repo/host/exp/exponent/expo.modules.network/57.0.2/expo.modules.network-57.0.2-sources.jar +0 -0
- package/local-maven-repo/host/exp/exponent/expo.modules.network/57.0.2/expo.modules.network-57.0.2-sources.jar.md5 +1 -0
- package/local-maven-repo/host/exp/exponent/expo.modules.network/57.0.2/expo.modules.network-57.0.2-sources.jar.sha1 +1 -0
- package/local-maven-repo/host/exp/exponent/expo.modules.network/57.0.2/expo.modules.network-57.0.2-sources.jar.sha256 +1 -0
- package/local-maven-repo/host/exp/exponent/expo.modules.network/57.0.2/expo.modules.network-57.0.2-sources.jar.sha512 +1 -0
- package/local-maven-repo/host/exp/exponent/expo.modules.network/57.0.2/expo.modules.network-57.0.2.aar +0 -0
- package/local-maven-repo/host/exp/exponent/expo.modules.network/57.0.2/expo.modules.network-57.0.2.aar.md5 +1 -0
- package/local-maven-repo/host/exp/exponent/expo.modules.network/57.0.2/expo.modules.network-57.0.2.aar.sha1 +1 -0
- package/local-maven-repo/host/exp/exponent/expo.modules.network/57.0.2/expo.modules.network-57.0.2.aar.sha256 +1 -0
- package/local-maven-repo/host/exp/exponent/expo.modules.network/57.0.2/expo.modules.network-57.0.2.aar.sha512 +1 -0
- package/local-maven-repo/host/exp/exponent/expo.modules.network/57.0.2/expo.modules.network-57.0.2.module +101 -0
- package/local-maven-repo/host/exp/exponent/expo.modules.network/57.0.2/expo.modules.network-57.0.2.module.md5 +1 -0
- package/local-maven-repo/host/exp/exponent/expo.modules.network/57.0.2/expo.modules.network-57.0.2.module.sha1 +1 -0
- package/local-maven-repo/host/exp/exponent/expo.modules.network/57.0.2/expo.modules.network-57.0.2.module.sha256 +1 -0
- package/local-maven-repo/host/exp/exponent/expo.modules.network/57.0.2/expo.modules.network-57.0.2.module.sha512 +1 -0
- package/local-maven-repo/host/exp/exponent/expo.modules.network/57.0.2/expo.modules.network-57.0.2.pom +59 -0
- package/local-maven-repo/host/exp/exponent/expo.modules.network/57.0.2/expo.modules.network-57.0.2.pom.md5 +1 -0
- package/local-maven-repo/host/exp/exponent/expo.modules.network/57.0.2/expo.modules.network-57.0.2.pom.sha1 +1 -0
- package/local-maven-repo/host/exp/exponent/expo.modules.network/57.0.2/expo.modules.network-57.0.2.pom.sha256 +1 -0
- package/local-maven-repo/host/exp/exponent/expo.modules.network/57.0.2/expo.modules.network-57.0.2.pom.sha512 +1 -0
- package/local-maven-repo/host/exp/exponent/expo.modules.network/maven-metadata.xml +13 -0
- package/local-maven-repo/host/exp/exponent/expo.modules.network/maven-metadata.xml.md5 +1 -0
- package/local-maven-repo/host/exp/exponent/expo.modules.network/maven-metadata.xml.sha1 +1 -0
- package/local-maven-repo/host/exp/exponent/expo.modules.network/maven-metadata.xml.sha256 +1 -0
- package/local-maven-repo/host/exp/exponent/expo.modules.network/maven-metadata.xml.sha512 +1 -0
- package/package.json +41 -0
- package/spm.config.json +37 -0
- package/src/ExpoNetwork.ts +3 -0
- package/src/ExpoNetwork.web.ts +52 -0
- package/src/Network.ts +123 -0
- package/src/Network.types.ts +90 -0
- package/tsconfig.json +10 -0
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
package expo.modules.network
|
|
2
|
+
|
|
3
|
+
import android.content.Context
|
|
4
|
+
import android.net.ConnectivityManager
|
|
5
|
+
import android.net.Network
|
|
6
|
+
import android.net.NetworkCapabilities
|
|
7
|
+
import android.net.NetworkInfo
|
|
8
|
+
import android.net.wifi.WifiInfo
|
|
9
|
+
import android.net.wifi.WifiManager
|
|
10
|
+
import android.os.Build
|
|
11
|
+
import android.os.Bundle
|
|
12
|
+
import android.os.Handler
|
|
13
|
+
import android.os.Looper
|
|
14
|
+
import android.provider.Settings
|
|
15
|
+
import android.util.Log
|
|
16
|
+
import expo.modules.kotlin.exception.Exceptions
|
|
17
|
+
import expo.modules.kotlin.modules.Module
|
|
18
|
+
import expo.modules.kotlin.modules.ModuleDefinition
|
|
19
|
+
import java.math.BigInteger
|
|
20
|
+
import java.net.InetAddress
|
|
21
|
+
import java.net.UnknownHostException
|
|
22
|
+
import java.nio.ByteOrder
|
|
23
|
+
|
|
24
|
+
private val TAG = NetworkModule::class.java.simpleName
|
|
25
|
+
|
|
26
|
+
internal const val NETWORK_STATE_EVENT_NAME = "onNetworkStateChanged"
|
|
27
|
+
|
|
28
|
+
class NetworkModule : Module() {
|
|
29
|
+
private val context: Context
|
|
30
|
+
get() = appContext.reactContext ?: throw Exceptions.ReactContextLost()
|
|
31
|
+
private val connectivityManager: ConnectivityManager
|
|
32
|
+
get() = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
|
|
33
|
+
private val mainHandler = Handler(Looper.getMainLooper())
|
|
34
|
+
private val DELAY_MS = 250
|
|
35
|
+
private var isNetworkCallbackRegistered = false
|
|
36
|
+
|
|
37
|
+
private val emitRunnable = Runnable { emitNetworkState() }
|
|
38
|
+
|
|
39
|
+
private val networkCallback = object : ConnectivityManager.NetworkCallback() {
|
|
40
|
+
override fun onAvailable(network: android.net.Network) {
|
|
41
|
+
asyncEmitNetworkState(DELAY_MS)
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
override fun onLost(lostNetwork: android.net.Network) {
|
|
45
|
+
// We intentionally do NOT reuse asyncEmitNetworkState(DELAY_MS) here.
|
|
46
|
+
//
|
|
47
|
+
// The 250ms delay used by onAvailable cannot be applied to onLost. On
|
|
48
|
+
// Android 13+, connectivityManager.activeNetwork continues to return the
|
|
49
|
+
// just-lost Network object even after the delay. Re-querying it would
|
|
50
|
+
// emit a stale "isConnected = true" event — the exact bug reported in
|
|
51
|
+
// https://github.com/expo/expo/issues/37972. This behavior isn't
|
|
52
|
+
// documented by AOSP as version-specific, so we apply this check
|
|
53
|
+
// defensively on all API 29+ devices.
|
|
54
|
+
//
|
|
55
|
+
// Instead, we compare the lost network against the current active network.
|
|
56
|
+
// If they match (or activeNetwork is null), there is no replacement
|
|
57
|
+
// network and we emit a disconnected state directly. If a different
|
|
58
|
+
// network is active (e.g. cellular), we emit
|
|
59
|
+
// its state instead.
|
|
60
|
+
//
|
|
61
|
+
// Note: android.net.Network.equals() compares by netId, so the check
|
|
62
|
+
// below is a reliable "same network" comparison.
|
|
63
|
+
//
|
|
64
|
+
// We still post to the main looper because sendEvent must run on the
|
|
65
|
+
// main thread; we just skip the artificial delay.
|
|
66
|
+
mainHandler.removeCallbacks(emitRunnable)
|
|
67
|
+
mainHandler.post {
|
|
68
|
+
try {
|
|
69
|
+
val activeNetwork = connectivityManager.activeNetwork
|
|
70
|
+
if (activeNetwork == null || activeNetwork == lostNetwork) {
|
|
71
|
+
val result = Bundle().apply {
|
|
72
|
+
putString("type", NetworkStateType.NONE.value)
|
|
73
|
+
putBoolean("isInternetReachable", false)
|
|
74
|
+
putBoolean("isConnected", false)
|
|
75
|
+
}
|
|
76
|
+
sendEvent(NETWORK_STATE_EVENT_NAME, result)
|
|
77
|
+
} else {
|
|
78
|
+
emitNetworkState()
|
|
79
|
+
}
|
|
80
|
+
} catch (e: SecurityException) {
|
|
81
|
+
// Missing ACCESS_NETWORK_STATE permission (or runtime revocation).
|
|
82
|
+
// Ensure the permission is declared in AndroidManifest.xml and
|
|
83
|
+
// granted at runtime on devices that require it.
|
|
84
|
+
Log.w(TAG, "expo-network could not read network state in onLost: missing ACCESS_NETWORK_STATE permission", e)
|
|
85
|
+
} catch (e: Exception) {
|
|
86
|
+
// The runnable may outlive the module if the React context is torn
|
|
87
|
+
// down between the ConnectivityManager.NetworkCallback firing and
|
|
88
|
+
// the posted runnable executing. In that case, the `connectivityManager`
|
|
89
|
+
// getter throws `ReactContextLost` when it
|
|
90
|
+
// attempts to resolve `appContext.reactContext`. Since
|
|
91
|
+
// unregisterNetworkCallback only prevents future callbacks and
|
|
92
|
+
// cannot cancel a runnable that is already in the queue, we must
|
|
93
|
+
// catch teardown-time exceptions here to avoid crashing the
|
|
94
|
+
// host app's main thread.
|
|
95
|
+
Log.w(TAG, "expo-network dropped a network state update during teardown (the module or React context is no longer available)", e)
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
override fun onCapabilitiesChanged(network: android.net.Network, networkCapabilities: NetworkCapabilities) {
|
|
101
|
+
asyncEmitNetworkState(DELAY_MS)
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
override fun definition() = ModuleDefinition {
|
|
106
|
+
Name("ExpoNetwork")
|
|
107
|
+
|
|
108
|
+
Events(NETWORK_STATE_EVENT_NAME)
|
|
109
|
+
|
|
110
|
+
OnCreate {
|
|
111
|
+
try {
|
|
112
|
+
connectivityManager.registerDefaultNetworkCallback(networkCallback)
|
|
113
|
+
isNetworkCallbackRegistered = true
|
|
114
|
+
} catch (e: SecurityException) {
|
|
115
|
+
Log.w(TAG, "expo-network cannot observe internet reachability: missing ACCESS_NETWORK_STATE permission", e)
|
|
116
|
+
} catch (e: RuntimeException) {
|
|
117
|
+
Log.e(TAG, "expo-network cannot observe internet reachability, too many callbacks registered!", e)
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
OnDestroy {
|
|
122
|
+
mainHandler.removeCallbacks(emitRunnable)
|
|
123
|
+
if (isNetworkCallbackRegistered) {
|
|
124
|
+
try {
|
|
125
|
+
connectivityManager.unregisterNetworkCallback(networkCallback)
|
|
126
|
+
} catch (e: SecurityException) {
|
|
127
|
+
Log.w(TAG, "expo-network could not unregister network callback: missing ACCESS_NETWORK_STATE permission", e)
|
|
128
|
+
} catch (e: Exception) {
|
|
129
|
+
Log.w(TAG, "expo-network could not unregister network callback during teardown", e)
|
|
130
|
+
} finally {
|
|
131
|
+
isNetworkCallbackRegistered = false
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
AsyncFunction("getNetworkStateAsync") {
|
|
137
|
+
return@AsyncFunction fetchNetworkState()
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
AsyncFunction<String>("getIpAddressAsync") {
|
|
141
|
+
return@AsyncFunction rawIpToString(wifiInfo.ipAddress)
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
AsyncFunction<Boolean>("isAirplaneModeEnabledAsync") {
|
|
145
|
+
return@AsyncFunction Settings.Global.getInt(context.contentResolver, Settings.Global.AIRPLANE_MODE_ON, 0) != 0
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
enum class NetworkStateType(val value: String) {
|
|
150
|
+
NONE("NONE"),
|
|
151
|
+
UNKNOWN("UNKNOWN"),
|
|
152
|
+
CELLULAR("CELLULAR"),
|
|
153
|
+
WIFI("WIFI"),
|
|
154
|
+
BLUETOOTH("BLUETOOTH"),
|
|
155
|
+
ETHERNET("ETHERNET"),
|
|
156
|
+
WIMAX("WIMAX"),
|
|
157
|
+
VPN("VPN"),
|
|
158
|
+
OTHER("OTHER");
|
|
159
|
+
|
|
160
|
+
val isDefined: Boolean
|
|
161
|
+
get() = this.value != "NONE" && this.value != "UNKNOWN"
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
private fun emitNetworkState() {
|
|
165
|
+
try {
|
|
166
|
+
val networkState = fetchNetworkState()
|
|
167
|
+
sendEvent(NETWORK_STATE_EVENT_NAME, networkState)
|
|
168
|
+
} catch (e: SecurityException) {
|
|
169
|
+
Log.w(TAG, "expo-network could not read network state: missing ACCESS_NETWORK_STATE permission", e)
|
|
170
|
+
} catch (e: Exception) {
|
|
171
|
+
// The runnable may outlive the module if the React context is torn down between the
|
|
172
|
+
// ConnectivityManager callback firing and this runnable executing.
|
|
173
|
+
Log.w(TAG, "expo-network dropped a delayed network state update during teardown (the module or React context is no longer available)", e)
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Emits the network state with a delay to prevent a race condition.
|
|
179
|
+
* This delay ensures we read the actual current network state rather than stale information.
|
|
180
|
+
* Debounced: rapid successive calls collapse into a single emission.
|
|
181
|
+
*/
|
|
182
|
+
private fun asyncEmitNetworkState(delay: Int) {
|
|
183
|
+
mainHandler.removeCallbacks(emitRunnable)
|
|
184
|
+
mainHandler.postDelayed(emitRunnable, delay.toLong())
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
private fun fetchNetworkState(): Bundle {
|
|
188
|
+
val result = Bundle()
|
|
189
|
+
|
|
190
|
+
try {
|
|
191
|
+
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) { // use getActiveNetworkInfo before api level 29
|
|
192
|
+
val netInfo = connectivityManager.activeNetworkInfo
|
|
193
|
+
val connectionType = getConnectionType(netInfo)
|
|
194
|
+
val isInternetReachable = isInternetReachable(connectivityManager)
|
|
195
|
+
|
|
196
|
+
result.apply {
|
|
197
|
+
putBoolean("isInternetReachable", isInternetReachable)
|
|
198
|
+
putString("type", connectionType.value)
|
|
199
|
+
putBoolean("isConnected", connectionType.isDefined)
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
return result
|
|
203
|
+
} else {
|
|
204
|
+
val network = connectivityManager.activeNetwork
|
|
205
|
+
val isInternetReachable = isInternetReachable(connectivityManager)
|
|
206
|
+
|
|
207
|
+
val connectionType = if (network != null) {
|
|
208
|
+
val netCapabilities = connectivityManager.getNetworkCapabilities(network)
|
|
209
|
+
getConnectionType(netCapabilities)
|
|
210
|
+
} else {
|
|
211
|
+
null
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
result.apply {
|
|
215
|
+
putString("type", connectionType?.value ?: NetworkStateType.NONE.value)
|
|
216
|
+
putBoolean("isInternetReachable", isInternetReachable)
|
|
217
|
+
putBoolean("isConnected", connectionType != null && connectionType.isDefined)
|
|
218
|
+
}
|
|
219
|
+
return result
|
|
220
|
+
}
|
|
221
|
+
} catch (e: Exception) {
|
|
222
|
+
result.apply {
|
|
223
|
+
putString("type", NetworkStateType.UNKNOWN.value)
|
|
224
|
+
putBoolean("isInternetReachable", false)
|
|
225
|
+
putBoolean("isConnected", false)
|
|
226
|
+
}
|
|
227
|
+
return result
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
private val wifiInfo: WifiInfo
|
|
232
|
+
get() = try {
|
|
233
|
+
val manager = context.getSystemService(Context.WIFI_SERVICE) as WifiManager
|
|
234
|
+
manager.connectionInfo
|
|
235
|
+
} catch (e: Exception) {
|
|
236
|
+
Log.e(TAG, e.message ?: "expo-network could not acquire Wi-Fi information")
|
|
237
|
+
throw NetworkWifiException(e)
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
private fun getConnectionType(netInfo: NetworkInfo?): NetworkStateType = when (netInfo?.type) {
|
|
241
|
+
ConnectivityManager.TYPE_MOBILE,
|
|
242
|
+
ConnectivityManager.TYPE_MOBILE_DUN -> NetworkStateType.CELLULAR
|
|
243
|
+
ConnectivityManager.TYPE_WIFI -> NetworkStateType.WIFI
|
|
244
|
+
ConnectivityManager.TYPE_BLUETOOTH -> NetworkStateType.BLUETOOTH
|
|
245
|
+
ConnectivityManager.TYPE_ETHERNET -> NetworkStateType.ETHERNET
|
|
246
|
+
ConnectivityManager.TYPE_WIMAX -> NetworkStateType.WIMAX
|
|
247
|
+
ConnectivityManager.TYPE_VPN -> NetworkStateType.VPN
|
|
248
|
+
else -> NetworkStateType.UNKNOWN
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
private fun getConnectionType(netCapabilities: NetworkCapabilities?): NetworkStateType =
|
|
252
|
+
when {
|
|
253
|
+
netCapabilities == null -> NetworkStateType.UNKNOWN
|
|
254
|
+
netCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) -> NetworkStateType.CELLULAR
|
|
255
|
+
netCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) || netCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI_AWARE) -> NetworkStateType.WIFI
|
|
256
|
+
netCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_BLUETOOTH) -> NetworkStateType.BLUETOOTH
|
|
257
|
+
netCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET) -> NetworkStateType.ETHERNET
|
|
258
|
+
netCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_VPN) -> NetworkStateType.VPN
|
|
259
|
+
else -> NetworkStateType.UNKNOWN
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
private fun rawIpToString(ipAddress: Int): String {
|
|
263
|
+
// Convert little-endian to big-endian if needed
|
|
264
|
+
val ip = if (ByteOrder.nativeOrder() == ByteOrder.LITTLE_ENDIAN) {
|
|
265
|
+
Integer.reverseBytes(ipAddress)
|
|
266
|
+
} else {
|
|
267
|
+
ipAddress
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
var ipByteArray = BigInteger.valueOf(ip.toLong()).toByteArray()
|
|
271
|
+
if (ipByteArray.size < 4) {
|
|
272
|
+
ipByteArray = frontPadWithZeros(ipByteArray)
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
return try {
|
|
276
|
+
InetAddress.getByAddress(ipByteArray).hostAddress as String
|
|
277
|
+
} catch (e: UnknownHostException) {
|
|
278
|
+
"0.0.0.0"
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
package expo.modules.network
|
|
2
|
+
|
|
3
|
+
import android.net.ConnectivityManager
|
|
4
|
+
import android.net.NetworkCapabilities
|
|
5
|
+
import android.net.NetworkInfo
|
|
6
|
+
import android.os.Build
|
|
7
|
+
import android.util.Log
|
|
8
|
+
|
|
9
|
+
private val TAG = NetworkModule::class.java.simpleName
|
|
10
|
+
|
|
11
|
+
internal fun frontPadWithZeros(inputArray: ByteArray): ByteArray {
|
|
12
|
+
val newByteArray = byteArrayOf(0, 0, 0, 0)
|
|
13
|
+
System.arraycopy(inputArray, 0, newByteArray, 4 - inputArray.size, inputArray.size)
|
|
14
|
+
return newByteArray
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Returns whether the device can reach the Internet.
|
|
19
|
+
* Checks that the active network has both the INTERNET and VALIDATED
|
|
20
|
+
* capabilities, has a usable connection state, and (for VPN connections)
|
|
21
|
+
* has non-zero downstream bandwidth.
|
|
22
|
+
*/
|
|
23
|
+
internal fun isInternetReachable(
|
|
24
|
+
connectivityManager: ConnectivityManager,
|
|
25
|
+
sdkInt: Int = Build.VERSION.SDK_INT
|
|
26
|
+
): Boolean {
|
|
27
|
+
val network = connectivityManager.activeNetwork ?: return false
|
|
28
|
+
val capabilities = connectivityManager.getNetworkCapabilities(network) ?: return false
|
|
29
|
+
|
|
30
|
+
val hasUsableConnectionState = if (sdkInt >= Build.VERSION_CODES.Q) {
|
|
31
|
+
capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED)
|
|
32
|
+
} else {
|
|
33
|
+
val networkInfo = try {
|
|
34
|
+
connectivityManager.getNetworkInfo(network)
|
|
35
|
+
} catch (e: SecurityException) {
|
|
36
|
+
Log.w(TAG, "expo-network could not read network state: missing ACCESS_NETWORK_STATE permission", e)
|
|
37
|
+
null
|
|
38
|
+
}
|
|
39
|
+
networkInfo?.detailedState == NetworkInfo.DetailedState.CONNECTED
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
var isReachable =
|
|
43
|
+
capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) &&
|
|
44
|
+
capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED) &&
|
|
45
|
+
hasUsableConnectionState
|
|
46
|
+
|
|
47
|
+
if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_VPN)) {
|
|
48
|
+
isReachable = isReachable && capabilities.linkDownstreamBandwidthKbps != 0
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return isReachable
|
|
52
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ExpoNetwork.d.ts","sourceRoot":"","sources":["../src/ExpoNetwork.ts"],"names":[],"mappings":";AAEA,wBAAkD"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ExpoNetwork.js","sourceRoot":"","sources":["../src/ExpoNetwork.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAExD,eAAe,mBAAmB,CAAC,aAAa,CAAC,CAAC","sourcesContent":["import { requireNativeModule } from 'expo-modules-core';\n\nexport default requireNativeModule('ExpoNetwork');\n"]}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { NativeModule } from 'expo-modules-core';
|
|
2
|
+
import type { NetworkEvents, NetworkState } from './Network.types';
|
|
3
|
+
declare class ExpoNetworkModule extends NativeModule<NetworkEvents> {
|
|
4
|
+
eventListener?: () => void;
|
|
5
|
+
updateNetworkState(): void;
|
|
6
|
+
getIpAddressAsync(): Promise<string>;
|
|
7
|
+
getNetworkStateAsync(): Promise<NetworkState>;
|
|
8
|
+
isAirplaneModeEnabledAsync(): Promise<boolean>;
|
|
9
|
+
startObserving(): void;
|
|
10
|
+
stopObserving(): void;
|
|
11
|
+
}
|
|
12
|
+
declare const _default: typeof ExpoNetworkModule;
|
|
13
|
+
export default _default;
|
|
14
|
+
//# sourceMappingURL=ExpoNetwork.web.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ExpoNetwork.web.d.ts","sourceRoot":"","sources":["../src/ExpoNetwork.web.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAqB,MAAM,mBAAmB,CAAC;AAEpE,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAcnE,cAAM,iBAAkB,SAAQ,YAAY,CAAC,aAAa,CAAC;IACzD,aAAa,CAAC,EAAE,MAAM,IAAI,CAAC;IAC3B,kBAAkB;IAKZ,iBAAiB,IAAI,OAAO,CAAC,MAAM,CAAC;IASpC,oBAAoB,IAAI,OAAO,CAAC,YAAY,CAAC;IAG7C,0BAA0B,IAAI,OAAO,CAAC,OAAO,CAAC;IAGpD,cAAc;IAKd,aAAa;CAMd;;AAED,wBAAmE"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { NativeModule, registerWebModule } from 'expo-modules-core';
|
|
2
|
+
import { NetworkStateType } from './Network.types';
|
|
3
|
+
const onNetworkStateEventName = 'onNetworkStateChanged';
|
|
4
|
+
function getNetworkState() {
|
|
5
|
+
const isOnline = typeof navigator !== 'undefined' && navigator.onLine;
|
|
6
|
+
return {
|
|
7
|
+
type: isOnline ? NetworkStateType.UNKNOWN : NetworkStateType.NONE,
|
|
8
|
+
isConnected: isOnline,
|
|
9
|
+
isInternetReachable: isOnline,
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
class ExpoNetworkModule extends NativeModule {
|
|
13
|
+
eventListener;
|
|
14
|
+
updateNetworkState() {
|
|
15
|
+
const state = getNetworkState();
|
|
16
|
+
this.emit(onNetworkStateEventName, state);
|
|
17
|
+
}
|
|
18
|
+
async getIpAddressAsync() {
|
|
19
|
+
try {
|
|
20
|
+
const resp = await fetch('https://api.ipify.org?format=json');
|
|
21
|
+
const data = await resp.json();
|
|
22
|
+
return data.ip;
|
|
23
|
+
}
|
|
24
|
+
catch (e) {
|
|
25
|
+
throw e;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
async getNetworkStateAsync() {
|
|
29
|
+
return getNetworkState();
|
|
30
|
+
}
|
|
31
|
+
async isAirplaneModeEnabledAsync() {
|
|
32
|
+
return false;
|
|
33
|
+
}
|
|
34
|
+
startObserving() {
|
|
35
|
+
this.eventListener = () => this.updateNetworkState();
|
|
36
|
+
window.addEventListener('online', this.eventListener);
|
|
37
|
+
window.addEventListener('offline', this.eventListener);
|
|
38
|
+
}
|
|
39
|
+
stopObserving() {
|
|
40
|
+
if (this.eventListener) {
|
|
41
|
+
window.removeEventListener('online', this.eventListener);
|
|
42
|
+
window.removeEventListener('offline', this.eventListener);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
export default registerWebModule(ExpoNetworkModule, 'ExpoNetwork');
|
|
47
|
+
//# sourceMappingURL=ExpoNetwork.web.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ExpoNetwork.web.js","sourceRoot":"","sources":["../src/ExpoNetwork.web.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAGpE,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAEnD,MAAM,uBAAuB,GAAG,uBAAuB,CAAC;AAExD,SAAS,eAAe;IACtB,MAAM,QAAQ,GAAG,OAAO,SAAS,KAAK,WAAW,IAAI,SAAS,CAAC,MAAM,CAAC;IACtE,OAAO;QACL,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC,CAAC,gBAAgB,CAAC,IAAI;QACjE,WAAW,EAAE,QAAQ;QACrB,mBAAmB,EAAE,QAAQ;KAC9B,CAAC;AACJ,CAAC;AAED,MAAM,iBAAkB,SAAQ,YAA2B;IACzD,aAAa,CAAc;IAC3B,kBAAkB;QAChB,MAAM,KAAK,GAAG,eAAe,EAAE,CAAC;QAChC,IAAI,CAAC,IAAI,CAAC,uBAAuB,EAAE,KAAK,CAAC,CAAC;IAC5C,CAAC;IAED,KAAK,CAAC,iBAAiB;QACrB,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,KAAK,CAAC,mCAAmC,CAAC,CAAC;YAC9D,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,IAAI,EAAE,CAAC;YAC/B,OAAO,IAAI,CAAC,EAAE,CAAC;QACjB,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,MAAM,CAAC,CAAC;QACV,CAAC;IACH,CAAC;IACD,KAAK,CAAC,oBAAoB;QACxB,OAAO,eAAe,EAAE,CAAC;IAC3B,CAAC;IACD,KAAK,CAAC,0BAA0B;QAC9B,OAAO,KAAK,CAAC;IACf,CAAC;IACD,cAAc;QACZ,IAAI,CAAC,aAAa,GAAG,GAAG,EAAE,CAAC,IAAI,CAAC,kBAAkB,EAAE,CAAC;QACrD,MAAM,CAAC,gBAAgB,CAAC,QAAQ,EAAE,IAAI,CAAC,aAAa,CAAC,CAAC;QACtD,MAAM,CAAC,gBAAgB,CAAC,SAAS,EAAE,IAAI,CAAC,aAAa,CAAC,CAAC;IACzD,CAAC;IACD,aAAa;QACX,IAAI,IAAI,CAAC,aAAa,EAAE,CAAC;YACvB,MAAM,CAAC,mBAAmB,CAAC,QAAQ,EAAE,IAAI,CAAC,aAAa,CAAC,CAAC;YACzD,MAAM,CAAC,mBAAmB,CAAC,SAAS,EAAE,IAAI,CAAC,aAAa,CAAC,CAAC;QAC5D,CAAC;IACH,CAAC;CACF;AAED,eAAe,iBAAiB,CAAC,iBAAiB,EAAE,aAAa,CAAC,CAAC","sourcesContent":["import { NativeModule, registerWebModule } from 'expo-modules-core';\n\nimport type { NetworkEvents, NetworkState } from './Network.types';\nimport { NetworkStateType } from './Network.types';\n\nconst onNetworkStateEventName = 'onNetworkStateChanged';\n\nfunction getNetworkState(): NetworkState {\n const isOnline = typeof navigator !== 'undefined' && navigator.onLine;\n return {\n type: isOnline ? NetworkStateType.UNKNOWN : NetworkStateType.NONE,\n isConnected: isOnline,\n isInternetReachable: isOnline,\n };\n}\n\nclass ExpoNetworkModule extends NativeModule<NetworkEvents> {\n eventListener?: () => void;\n updateNetworkState() {\n const state = getNetworkState();\n this.emit(onNetworkStateEventName, state);\n }\n\n async getIpAddressAsync(): Promise<string> {\n try {\n const resp = await fetch('https://api.ipify.org?format=json');\n const data = await resp.json();\n return data.ip;\n } catch (e) {\n throw e;\n }\n }\n async getNetworkStateAsync(): Promise<NetworkState> {\n return getNetworkState();\n }\n async isAirplaneModeEnabledAsync(): Promise<boolean> {\n return false;\n }\n startObserving() {\n this.eventListener = () => this.updateNetworkState();\n window.addEventListener('online', this.eventListener);\n window.addEventListener('offline', this.eventListener);\n }\n stopObserving() {\n if (this.eventListener) {\n window.removeEventListener('online', this.eventListener);\n window.removeEventListener('offline', this.eventListener);\n }\n }\n}\n\nexport default registerWebModule(ExpoNetworkModule, 'ExpoNetwork');\n"]}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { type EventSubscription } from 'expo-modules-core';
|
|
2
|
+
import type { NetworkState, NetworkStateEvent } from './Network.types';
|
|
3
|
+
export { type NetworkState, type NetworkStateEvent, NetworkStateType } from './Network.types';
|
|
4
|
+
/**
|
|
5
|
+
* Gets the device's current network connection state.
|
|
6
|
+
*
|
|
7
|
+
* On web, `navigator.connection.type` is not available on browsers. So if there is an active
|
|
8
|
+
* network connection, the field `type` returns `NetworkStateType.UNKNOWN`. Otherwise, it returns
|
|
9
|
+
* `NetworkStateType.NONE`.
|
|
10
|
+
* @return A `Promise` that fulfils with a `NetworkState` object.
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```ts
|
|
14
|
+
* await Network.getNetworkStateAsync();
|
|
15
|
+
* // {
|
|
16
|
+
* // type: NetworkStateType.CELLULAR,
|
|
17
|
+
* // isConnected: true,
|
|
18
|
+
* // isInternetReachable: true,
|
|
19
|
+
* // }
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
export declare function getNetworkStateAsync(): Promise<NetworkState>;
|
|
23
|
+
/**
|
|
24
|
+
* Gets the device's current IPv4 address. Returns `0.0.0.0` if the IP address could not be retrieved.
|
|
25
|
+
*
|
|
26
|
+
* On web, this method uses the third-party [`ipify service`](https://www.ipify.org/) to get the
|
|
27
|
+
* public IP address of the current device.
|
|
28
|
+
* @return A `Promise` that fulfils with a `string` of the current IP address of the device's main
|
|
29
|
+
* network interface. Can only be IPv4 address.
|
|
30
|
+
*
|
|
31
|
+
* @example
|
|
32
|
+
* ```ts
|
|
33
|
+
* await Network.getIpAddressAsync();
|
|
34
|
+
* // "92.168.32.44"
|
|
35
|
+
* ```
|
|
36
|
+
*/
|
|
37
|
+
export declare function getIpAddressAsync(): Promise<string>;
|
|
38
|
+
/**
|
|
39
|
+
* Tells if the device is in airplane mode.
|
|
40
|
+
* @return Returns a `Promise` that fulfils with a `boolean` value for whether the device is in
|
|
41
|
+
* airplane mode or not.
|
|
42
|
+
* @platform android
|
|
43
|
+
*
|
|
44
|
+
* @example
|
|
45
|
+
* ```ts
|
|
46
|
+
* await Network.isAirplaneModeEnabledAsync();
|
|
47
|
+
* // false
|
|
48
|
+
* ```
|
|
49
|
+
*/
|
|
50
|
+
export declare function isAirplaneModeEnabledAsync(): Promise<boolean>;
|
|
51
|
+
/**
|
|
52
|
+
* Adds a listener that will fire whenever the network state changes.
|
|
53
|
+
*
|
|
54
|
+
* @param listener Callback to execute when the network state changes. The callback is provided with
|
|
55
|
+
* a single argument that is an object containing information about the network state.
|
|
56
|
+
*
|
|
57
|
+
* @example
|
|
58
|
+
* ```ts
|
|
59
|
+
* const subscription = addNetworkStateListener(({ type, isConnected, isInternetReachable }) => {
|
|
60
|
+
* console.log(`Network type: ${type}, Connected: ${isConnected}, Internet Reachable: ${isInternetReachable}`);
|
|
61
|
+
* });
|
|
62
|
+
* ```
|
|
63
|
+
*
|
|
64
|
+
* @returns A subscription object with a remove function to unregister the listener.
|
|
65
|
+
*/
|
|
66
|
+
export declare function addNetworkStateListener(listener: (event: NetworkStateEvent) => void): EventSubscription;
|
|
67
|
+
/**
|
|
68
|
+
* Returns the current network state of the device. This method
|
|
69
|
+
* initiates a listener for network state changes and cleans up before unmounting.
|
|
70
|
+
*
|
|
71
|
+
* @example
|
|
72
|
+
* ```ts
|
|
73
|
+
* const networkState = useNetworkState();
|
|
74
|
+
* console.log(`Current network type: ${networkState.type}`);
|
|
75
|
+
* ```
|
|
76
|
+
*
|
|
77
|
+
* @return The current network state of the device, including connectivity and type.
|
|
78
|
+
*/
|
|
79
|
+
export declare function useNetworkState(): NetworkState;
|
|
80
|
+
//# sourceMappingURL=Network.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Network.d.ts","sourceRoot":"","sources":["../src/Network.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,iBAAiB,EAAuB,MAAM,mBAAmB,CAAC;AAIhF,OAAO,KAAK,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAEvE,OAAO,EAAE,KAAK,YAAY,EAAE,KAAK,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAK9F;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAsB,oBAAoB,IAAI,OAAO,CAAC,YAAY,CAAC,CAKlE;AAGD;;;;;;;;;;;;;GAaG;AACH,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,MAAM,CAAC,CAKzD;AAGD;;;;;;;;;;;GAWG;AACH,wBAAsB,0BAA0B,IAAI,OAAO,CAAC,OAAO,CAAC,CAKnE;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,uBAAuB,CACrC,QAAQ,EAAE,CAAC,KAAK,EAAE,iBAAiB,KAAK,IAAI,GAC3C,iBAAiB,CAEnB;AAGD;;;;;;;;;;;GAWG;AACH,wBAAgB,eAAe,IAAI,YAAY,CAU9C"}
|
package/build/Network.js
ADDED
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { UnavailabilityError } from 'expo-modules-core';
|
|
2
|
+
import { useEffect, useState } from 'react';
|
|
3
|
+
import ExpoNetwork from './ExpoNetwork';
|
|
4
|
+
export { NetworkStateType } from './Network.types';
|
|
5
|
+
const onNetworkStateEventName = 'onNetworkStateChanged';
|
|
6
|
+
// @needsAudit
|
|
7
|
+
/**
|
|
8
|
+
* Gets the device's current network connection state.
|
|
9
|
+
*
|
|
10
|
+
* On web, `navigator.connection.type` is not available on browsers. So if there is an active
|
|
11
|
+
* network connection, the field `type` returns `NetworkStateType.UNKNOWN`. Otherwise, it returns
|
|
12
|
+
* `NetworkStateType.NONE`.
|
|
13
|
+
* @return A `Promise` that fulfils with a `NetworkState` object.
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```ts
|
|
17
|
+
* await Network.getNetworkStateAsync();
|
|
18
|
+
* // {
|
|
19
|
+
* // type: NetworkStateType.CELLULAR,
|
|
20
|
+
* // isConnected: true,
|
|
21
|
+
* // isInternetReachable: true,
|
|
22
|
+
* // }
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
export async function getNetworkStateAsync() {
|
|
26
|
+
if (!ExpoNetwork.getNetworkStateAsync) {
|
|
27
|
+
throw new UnavailabilityError('expo-network', 'getNetworkStateAsync');
|
|
28
|
+
}
|
|
29
|
+
return await ExpoNetwork.getNetworkStateAsync();
|
|
30
|
+
}
|
|
31
|
+
// @needsAudit
|
|
32
|
+
/**
|
|
33
|
+
* Gets the device's current IPv4 address. Returns `0.0.0.0` if the IP address could not be retrieved.
|
|
34
|
+
*
|
|
35
|
+
* On web, this method uses the third-party [`ipify service`](https://www.ipify.org/) to get the
|
|
36
|
+
* public IP address of the current device.
|
|
37
|
+
* @return A `Promise` that fulfils with a `string` of the current IP address of the device's main
|
|
38
|
+
* network interface. Can only be IPv4 address.
|
|
39
|
+
*
|
|
40
|
+
* @example
|
|
41
|
+
* ```ts
|
|
42
|
+
* await Network.getIpAddressAsync();
|
|
43
|
+
* // "92.168.32.44"
|
|
44
|
+
* ```
|
|
45
|
+
*/
|
|
46
|
+
export async function getIpAddressAsync() {
|
|
47
|
+
if (!ExpoNetwork.getIpAddressAsync) {
|
|
48
|
+
throw new UnavailabilityError('expo-network', 'getIpAddressAsync');
|
|
49
|
+
}
|
|
50
|
+
return await ExpoNetwork.getIpAddressAsync();
|
|
51
|
+
}
|
|
52
|
+
// @needsAudit
|
|
53
|
+
/**
|
|
54
|
+
* Tells if the device is in airplane mode.
|
|
55
|
+
* @return Returns a `Promise` that fulfils with a `boolean` value for whether the device is in
|
|
56
|
+
* airplane mode or not.
|
|
57
|
+
* @platform android
|
|
58
|
+
*
|
|
59
|
+
* @example
|
|
60
|
+
* ```ts
|
|
61
|
+
* await Network.isAirplaneModeEnabledAsync();
|
|
62
|
+
* // false
|
|
63
|
+
* ```
|
|
64
|
+
*/
|
|
65
|
+
export async function isAirplaneModeEnabledAsync() {
|
|
66
|
+
if (!ExpoNetwork.isAirplaneModeEnabledAsync) {
|
|
67
|
+
throw new UnavailabilityError('expo-network', 'isAirplaneModeEnabledAsync');
|
|
68
|
+
}
|
|
69
|
+
return await ExpoNetwork.isAirplaneModeEnabledAsync();
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Adds a listener that will fire whenever the network state changes.
|
|
73
|
+
*
|
|
74
|
+
* @param listener Callback to execute when the network state changes. The callback is provided with
|
|
75
|
+
* a single argument that is an object containing information about the network state.
|
|
76
|
+
*
|
|
77
|
+
* @example
|
|
78
|
+
* ```ts
|
|
79
|
+
* const subscription = addNetworkStateListener(({ type, isConnected, isInternetReachable }) => {
|
|
80
|
+
* console.log(`Network type: ${type}, Connected: ${isConnected}, Internet Reachable: ${isInternetReachable}`);
|
|
81
|
+
* });
|
|
82
|
+
* ```
|
|
83
|
+
*
|
|
84
|
+
* @returns A subscription object with a remove function to unregister the listener.
|
|
85
|
+
*/
|
|
86
|
+
export function addNetworkStateListener(listener) {
|
|
87
|
+
return ExpoNetwork.addListener(onNetworkStateEventName, listener);
|
|
88
|
+
}
|
|
89
|
+
// @needsAudit
|
|
90
|
+
/**
|
|
91
|
+
* Returns the current network state of the device. This method
|
|
92
|
+
* initiates a listener for network state changes and cleans up before unmounting.
|
|
93
|
+
*
|
|
94
|
+
* @example
|
|
95
|
+
* ```ts
|
|
96
|
+
* const networkState = useNetworkState();
|
|
97
|
+
* console.log(`Current network type: ${networkState.type}`);
|
|
98
|
+
* ```
|
|
99
|
+
*
|
|
100
|
+
* @return The current network state of the device, including connectivity and type.
|
|
101
|
+
*/
|
|
102
|
+
export function useNetworkState() {
|
|
103
|
+
const [networkState, setNetworkState] = useState({});
|
|
104
|
+
useEffect(() => {
|
|
105
|
+
getNetworkStateAsync().then(setNetworkState);
|
|
106
|
+
const listener = addNetworkStateListener((networkState) => setNetworkState(networkState));
|
|
107
|
+
return () => listener.remove();
|
|
108
|
+
}, []);
|
|
109
|
+
return networkState;
|
|
110
|
+
}
|
|
111
|
+
//# sourceMappingURL=Network.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Network.js","sourceRoot":"","sources":["../src/Network.ts"],"names":[],"mappings":"AAAA,OAAO,EAA0B,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAChF,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAE5C,OAAO,WAAW,MAAM,eAAe,CAAC;AAGxC,OAAO,EAA6C,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAE9F,MAAM,uBAAuB,GAAG,uBAAuB,CAAC;AAExD,cAAc;AACd;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,CAAC,KAAK,UAAU,oBAAoB;IACxC,IAAI,CAAC,WAAW,CAAC,oBAAoB,EAAE,CAAC;QACtC,MAAM,IAAI,mBAAmB,CAAC,cAAc,EAAE,sBAAsB,CAAC,CAAC;IACxE,CAAC;IACD,OAAO,MAAM,WAAW,CAAC,oBAAoB,EAAE,CAAC;AAClD,CAAC;AAED,cAAc;AACd;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB;IACrC,IAAI,CAAC,WAAW,CAAC,iBAAiB,EAAE,CAAC;QACnC,MAAM,IAAI,mBAAmB,CAAC,cAAc,EAAE,mBAAmB,CAAC,CAAC;IACrE,CAAC;IACD,OAAO,MAAM,WAAW,CAAC,iBAAiB,EAAE,CAAC;AAC/C,CAAC;AAED,cAAc;AACd;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,KAAK,UAAU,0BAA0B;IAC9C,IAAI,CAAC,WAAW,CAAC,0BAA0B,EAAE,CAAC;QAC5C,MAAM,IAAI,mBAAmB,CAAC,cAAc,EAAE,4BAA4B,CAAC,CAAC;IAC9E,CAAC;IACD,OAAO,MAAM,WAAW,CAAC,0BAA0B,EAAE,CAAC;AACxD,CAAC;AAED;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,uBAAuB,CACrC,QAA4C;IAE5C,OAAO,WAAW,CAAC,WAAW,CAAC,uBAAuB,EAAE,QAAQ,CAAC,CAAC;AACpE,CAAC;AAED,cAAc;AACd;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,eAAe;IAC7B,MAAM,CAAC,YAAY,EAAE,eAAe,CAAC,GAAG,QAAQ,CAAe,EAAE,CAAC,CAAC;IAEnE,SAAS,CAAC,GAAG,EAAE;QACb,oBAAoB,EAAE,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;QAC7C,MAAM,QAAQ,GAAG,uBAAuB,CAAC,CAAC,YAAY,EAAE,EAAE,CAAC,eAAe,CAAC,YAAY,CAAC,CAAC,CAAC;QAC1F,OAAO,GAAG,EAAE,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC;IACjC,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,OAAO,YAAY,CAAC;AACtB,CAAC","sourcesContent":["import { type EventSubscription, UnavailabilityError } from 'expo-modules-core';\nimport { useEffect, useState } from 'react';\n\nimport ExpoNetwork from './ExpoNetwork';\nimport type { NetworkState, NetworkStateEvent } from './Network.types';\n\nexport { type NetworkState, type NetworkStateEvent, NetworkStateType } from './Network.types';\n\nconst onNetworkStateEventName = 'onNetworkStateChanged';\n\n// @needsAudit\n/**\n * Gets the device's current network connection state.\n *\n * On web, `navigator.connection.type` is not available on browsers. So if there is an active\n * network connection, the field `type` returns `NetworkStateType.UNKNOWN`. Otherwise, it returns\n * `NetworkStateType.NONE`.\n * @return A `Promise` that fulfils with a `NetworkState` object.\n *\n * @example\n * ```ts\n * await Network.getNetworkStateAsync();\n * // {\n * // type: NetworkStateType.CELLULAR,\n * // isConnected: true,\n * // isInternetReachable: true,\n * // }\n * ```\n */\nexport async function getNetworkStateAsync(): Promise<NetworkState> {\n if (!ExpoNetwork.getNetworkStateAsync) {\n throw new UnavailabilityError('expo-network', 'getNetworkStateAsync');\n }\n return await ExpoNetwork.getNetworkStateAsync();\n}\n\n// @needsAudit\n/**\n * Gets the device's current IPv4 address. Returns `0.0.0.0` if the IP address could not be retrieved.\n *\n * On web, this method uses the third-party [`ipify service`](https://www.ipify.org/) to get the\n * public IP address of the current device.\n * @return A `Promise` that fulfils with a `string` of the current IP address of the device's main\n * network interface. Can only be IPv4 address.\n *\n * @example\n * ```ts\n * await Network.getIpAddressAsync();\n * // \"92.168.32.44\"\n * ```\n */\nexport async function getIpAddressAsync(): Promise<string> {\n if (!ExpoNetwork.getIpAddressAsync) {\n throw new UnavailabilityError('expo-network', 'getIpAddressAsync');\n }\n return await ExpoNetwork.getIpAddressAsync();\n}\n\n// @needsAudit\n/**\n * Tells if the device is in airplane mode.\n * @return Returns a `Promise` that fulfils with a `boolean` value for whether the device is in\n * airplane mode or not.\n * @platform android\n *\n * @example\n * ```ts\n * await Network.isAirplaneModeEnabledAsync();\n * // false\n * ```\n */\nexport async function isAirplaneModeEnabledAsync(): Promise<boolean> {\n if (!ExpoNetwork.isAirplaneModeEnabledAsync) {\n throw new UnavailabilityError('expo-network', 'isAirplaneModeEnabledAsync');\n }\n return await ExpoNetwork.isAirplaneModeEnabledAsync();\n}\n\n/**\n * Adds a listener that will fire whenever the network state changes.\n *\n * @param listener Callback to execute when the network state changes. The callback is provided with\n * a single argument that is an object containing information about the network state.\n *\n * @example\n * ```ts\n * const subscription = addNetworkStateListener(({ type, isConnected, isInternetReachable }) => {\n * console.log(`Network type: ${type}, Connected: ${isConnected}, Internet Reachable: ${isInternetReachable}`);\n * });\n * ```\n *\n * @returns A subscription object with a remove function to unregister the listener.\n */\nexport function addNetworkStateListener(\n listener: (event: NetworkStateEvent) => void\n): EventSubscription {\n return ExpoNetwork.addListener(onNetworkStateEventName, listener);\n}\n\n// @needsAudit\n/**\n * Returns the current network state of the device. This method\n * initiates a listener for network state changes and cleans up before unmounting.\n *\n * @example\n * ```ts\n * const networkState = useNetworkState();\n * console.log(`Current network type: ${networkState.type}`);\n * ```\n *\n * @return The current network state of the device, including connectivity and type.\n */\nexport function useNetworkState(): NetworkState {\n const [networkState, setNetworkState] = useState<NetworkState>({});\n\n useEffect(() => {\n getNetworkStateAsync().then(setNetworkState);\n const listener = addNetworkStateListener((networkState) => setNetworkState(networkState));\n return () => listener.remove();\n }, []);\n\n return networkState;\n}\n"]}
|