rnww-plugin-wifi 1.0.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/README.md +841 -0
- package/lib/bridge/background-bridge.d.ts +22 -0
- package/lib/bridge/background-bridge.d.ts.map +1 -0
- package/lib/bridge/background-bridge.js +493 -0
- package/lib/bridge/index.d.ts +6 -0
- package/lib/bridge/index.d.ts.map +1 -0
- package/lib/bridge/index.js +23 -0
- package/lib/bridge/wifi-bridge.d.ts +16 -0
- package/lib/bridge/wifi-bridge.d.ts.map +1 -0
- package/lib/bridge/wifi-bridge.js +202 -0
- package/lib/modules/index.d.ts +41 -0
- package/lib/modules/index.d.ts.map +1 -0
- package/lib/modules/index.js +150 -0
- package/lib/types/background-module.d.ts +291 -0
- package/lib/types/background-module.d.ts.map +1 -0
- package/lib/types/background-module.js +5 -0
- package/lib/types/bridge.d.ts +22 -0
- package/lib/types/bridge.d.ts.map +1 -0
- package/lib/types/bridge.js +5 -0
- package/lib/types/index.d.ts +7 -0
- package/lib/types/index.d.ts.map +1 -0
- package/lib/types/index.js +5 -0
- package/lib/types/platform.d.ts +10 -0
- package/lib/types/platform.d.ts.map +1 -0
- package/lib/types/platform.js +2 -0
- package/lib/types/wifi-module.d.ts +146 -0
- package/lib/types/wifi-module.d.ts.map +1 -0
- package/lib/types/wifi-module.js +6 -0
- package/package.json +42 -0
- package/src/modules/android/build.gradle +64 -0
- package/src/modules/android/src/main/AndroidManifest.xml +28 -0
- package/src/modules/android/src/main/java/expo/modules/customwifi/WifiModule.kt +517 -0
- package/src/modules/android/src/main/java/expo/modules/customwifi/WifiStateReceiver.kt +46 -0
- package/src/modules/expo-module.config.json +9 -0
- package/src/modules/index.ts +166 -0
- package/src/modules/ios/WifiModule.swift +399 -0
|
@@ -0,0 +1,517 @@
|
|
|
1
|
+
package expo.modules.customwifi
|
|
2
|
+
|
|
3
|
+
import android.Manifest
|
|
4
|
+
import android.content.BroadcastReceiver
|
|
5
|
+
import android.content.Context
|
|
6
|
+
import android.content.Intent
|
|
7
|
+
import android.content.IntentFilter
|
|
8
|
+
import android.content.pm.PackageManager
|
|
9
|
+
import android.net.ConnectivityManager
|
|
10
|
+
import android.net.Network
|
|
11
|
+
import android.net.NetworkCapabilities
|
|
12
|
+
import android.net.NetworkRequest
|
|
13
|
+
import android.net.wifi.ScanResult
|
|
14
|
+
import android.net.wifi.WifiConfiguration
|
|
15
|
+
import android.net.wifi.WifiInfo
|
|
16
|
+
import android.net.wifi.WifiManager
|
|
17
|
+
import android.net.wifi.WifiNetworkSpecifier
|
|
18
|
+
import android.os.Build
|
|
19
|
+
import android.util.Log
|
|
20
|
+
import androidx.core.content.ContextCompat
|
|
21
|
+
import expo.modules.kotlin.Promise
|
|
22
|
+
import expo.modules.kotlin.modules.Module
|
|
23
|
+
import expo.modules.kotlin.modules.ModuleDefinition
|
|
24
|
+
import expo.modules.kotlin.exception.Exceptions
|
|
25
|
+
|
|
26
|
+
class WifiModule : Module() {
|
|
27
|
+
companion object {
|
|
28
|
+
private const val TAG = "CustomWifi"
|
|
29
|
+
private const val EVENT_WIFI_STATE_CHANGE = "onWifiStateChange"
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
private val context: Context
|
|
33
|
+
get() = appContext.reactContext ?: throw Exceptions.ReactContextLost()
|
|
34
|
+
|
|
35
|
+
private val wifiManager: WifiManager
|
|
36
|
+
get() = context.applicationContext.getSystemService(Context.WIFI_SERVICE) as WifiManager
|
|
37
|
+
|
|
38
|
+
private val connectivityManager: ConnectivityManager
|
|
39
|
+
get() = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
|
|
40
|
+
|
|
41
|
+
private var wifiStateReceiver: BroadcastReceiver? = null
|
|
42
|
+
private var networkCallback: ConnectivityManager.NetworkCallback? = null
|
|
43
|
+
|
|
44
|
+
override fun definition() = ModuleDefinition {
|
|
45
|
+
Name("CustomWifi")
|
|
46
|
+
|
|
47
|
+
Events(EVENT_WIFI_STATE_CHANGE)
|
|
48
|
+
|
|
49
|
+
OnCreate {
|
|
50
|
+
registerWifiStateReceiver()
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
OnDestroy {
|
|
54
|
+
unregisterWifiStateReceiver()
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// 현재 WiFi 정보 조회
|
|
58
|
+
AsyncFunction("getCurrentWifiInfo") { promise: Promise ->
|
|
59
|
+
try {
|
|
60
|
+
if (!hasLocationPermission()) {
|
|
61
|
+
promise.resolve(mapOf(
|
|
62
|
+
"success" to false,
|
|
63
|
+
"error" to "Location permission required for WiFi info",
|
|
64
|
+
"errorCode" to "PERMISSION_DENIED"
|
|
65
|
+
))
|
|
66
|
+
return@AsyncFunction
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
val wifiInfo = getWifiInfo()
|
|
70
|
+
promise.resolve(mapOf(
|
|
71
|
+
"success" to true,
|
|
72
|
+
"data" to wifiInfo
|
|
73
|
+
))
|
|
74
|
+
} catch (e: Exception) {
|
|
75
|
+
Log.e(TAG, "Error getting WiFi info", e)
|
|
76
|
+
promise.resolve(mapOf(
|
|
77
|
+
"success" to false,
|
|
78
|
+
"error" to (e.message ?: "Unknown error"),
|
|
79
|
+
"errorCode" to "UNKNOWN"
|
|
80
|
+
))
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// WiFi 목록 스캔
|
|
85
|
+
AsyncFunction("getWifiList") { promise: Promise ->
|
|
86
|
+
try {
|
|
87
|
+
if (!hasLocationPermission()) {
|
|
88
|
+
promise.resolve(mapOf(
|
|
89
|
+
"success" to false,
|
|
90
|
+
"error" to "Location permission required for WiFi scanning",
|
|
91
|
+
"errorCode" to "PERMISSION_DENIED"
|
|
92
|
+
))
|
|
93
|
+
return@AsyncFunction
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
if (!wifiManager.isWifiEnabled) {
|
|
97
|
+
promise.resolve(mapOf(
|
|
98
|
+
"success" to false,
|
|
99
|
+
"error" to "WiFi is disabled",
|
|
100
|
+
"errorCode" to "WIFI_DISABLED"
|
|
101
|
+
))
|
|
102
|
+
return@AsyncFunction
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
wifiManager.startScan()
|
|
106
|
+
val scanResults = wifiManager.scanResults
|
|
107
|
+
val networks = scanResults.map { result ->
|
|
108
|
+
mapOf(
|
|
109
|
+
"ssid" to result.SSID,
|
|
110
|
+
"bssid" to result.BSSID,
|
|
111
|
+
"rssi" to result.level,
|
|
112
|
+
"signalLevel" to WifiManager.calculateSignalLevel(result.level, 100),
|
|
113
|
+
"frequency" to result.frequency,
|
|
114
|
+
"security" to getSecurityType(result),
|
|
115
|
+
"channel" to frequencyToChannel(result.frequency)
|
|
116
|
+
)
|
|
117
|
+
}.filter { it["ssid"] != "" }
|
|
118
|
+
|
|
119
|
+
promise.resolve(mapOf(
|
|
120
|
+
"success" to true,
|
|
121
|
+
"data" to networks
|
|
122
|
+
))
|
|
123
|
+
} catch (e: Exception) {
|
|
124
|
+
Log.e(TAG, "Error scanning WiFi", e)
|
|
125
|
+
promise.resolve(mapOf(
|
|
126
|
+
"success" to false,
|
|
127
|
+
"error" to (e.message ?: "Unknown error"),
|
|
128
|
+
"errorCode" to "UNKNOWN"
|
|
129
|
+
))
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// WiFi 활성화 상태 확인
|
|
134
|
+
AsyncFunction("isWifiEnabled") { promise: Promise ->
|
|
135
|
+
try {
|
|
136
|
+
val isEnabled = wifiManager.isWifiEnabled
|
|
137
|
+
val wifiState = when (wifiManager.wifiState) {
|
|
138
|
+
WifiManager.WIFI_STATE_DISABLED -> "DISABLED"
|
|
139
|
+
WifiManager.WIFI_STATE_DISABLING -> "DISABLING"
|
|
140
|
+
WifiManager.WIFI_STATE_ENABLED -> "ENABLED"
|
|
141
|
+
WifiManager.WIFI_STATE_ENABLING -> "ENABLING"
|
|
142
|
+
else -> "UNKNOWN"
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
promise.resolve(mapOf(
|
|
146
|
+
"success" to true,
|
|
147
|
+
"isEnabled" to isEnabled,
|
|
148
|
+
"wifiState" to wifiState
|
|
149
|
+
))
|
|
150
|
+
} catch (e: Exception) {
|
|
151
|
+
Log.e(TAG, "Error checking WiFi state", e)
|
|
152
|
+
promise.resolve(mapOf(
|
|
153
|
+
"success" to false,
|
|
154
|
+
"error" to (e.message ?: "Unknown error"),
|
|
155
|
+
"errorCode" to "UNKNOWN"
|
|
156
|
+
))
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// WiFi 연결
|
|
161
|
+
AsyncFunction("connectToWifi") { options: Map<String, Any?>, promise: Promise ->
|
|
162
|
+
try {
|
|
163
|
+
val ssid = options["ssid"] as? String
|
|
164
|
+
if (ssid.isNullOrEmpty()) {
|
|
165
|
+
promise.resolve(mapOf(
|
|
166
|
+
"success" to false,
|
|
167
|
+
"error" to "SSID is required",
|
|
168
|
+
"errorCode" to "INVALID_SSID"
|
|
169
|
+
))
|
|
170
|
+
return@AsyncFunction
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
val password = options["password"] as? String
|
|
174
|
+
val isHidden = options["isHidden"] as? Boolean ?: false
|
|
175
|
+
|
|
176
|
+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
|
177
|
+
// Android 10+ uses WifiNetworkSpecifier
|
|
178
|
+
connectWifiAndroid10(ssid, password, isHidden, promise)
|
|
179
|
+
} else {
|
|
180
|
+
// Legacy connection method
|
|
181
|
+
connectWifiLegacy(ssid, password, isHidden, promise)
|
|
182
|
+
}
|
|
183
|
+
} catch (e: Exception) {
|
|
184
|
+
Log.e(TAG, "Error connecting to WiFi", e)
|
|
185
|
+
promise.resolve(mapOf(
|
|
186
|
+
"success" to false,
|
|
187
|
+
"error" to (e.message ?: "Unknown error"),
|
|
188
|
+
"errorCode" to "CONNECTION_FAILED"
|
|
189
|
+
))
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// WiFi 연결 해제
|
|
194
|
+
AsyncFunction("disconnect") { promise: Promise ->
|
|
195
|
+
try {
|
|
196
|
+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
|
197
|
+
// Android 10+ - unregister network callback
|
|
198
|
+
networkCallback?.let {
|
|
199
|
+
connectivityManager.unregisterNetworkCallback(it)
|
|
200
|
+
networkCallback = null
|
|
201
|
+
}
|
|
202
|
+
promise.resolve(mapOf("success" to true))
|
|
203
|
+
} else {
|
|
204
|
+
@Suppress("DEPRECATION")
|
|
205
|
+
val result = wifiManager.disconnect()
|
|
206
|
+
promise.resolve(mapOf("success" to result))
|
|
207
|
+
}
|
|
208
|
+
} catch (e: Exception) {
|
|
209
|
+
Log.e(TAG, "Error disconnecting WiFi", e)
|
|
210
|
+
promise.resolve(mapOf(
|
|
211
|
+
"success" to false,
|
|
212
|
+
"error" to (e.message ?: "Unknown error"),
|
|
213
|
+
"errorCode" to "UNKNOWN"
|
|
214
|
+
))
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// 권한 확인
|
|
219
|
+
AsyncFunction("checkPermission") { promise: Promise ->
|
|
220
|
+
try {
|
|
221
|
+
val fineLocation = ContextCompat.checkSelfPermission(
|
|
222
|
+
context, Manifest.permission.ACCESS_FINE_LOCATION
|
|
223
|
+
) == PackageManager.PERMISSION_GRANTED
|
|
224
|
+
|
|
225
|
+
val coarseLocation = ContextCompat.checkSelfPermission(
|
|
226
|
+
context, Manifest.permission.ACCESS_COARSE_LOCATION
|
|
227
|
+
) == PackageManager.PERMISSION_GRANTED
|
|
228
|
+
|
|
229
|
+
val requiredPermissions = mutableListOf<String>()
|
|
230
|
+
if (!fineLocation) {
|
|
231
|
+
requiredPermissions.add(Manifest.permission.ACCESS_FINE_LOCATION)
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
promise.resolve(mapOf(
|
|
235
|
+
"locationGranted" to fineLocation,
|
|
236
|
+
"canAccessWifiInfo" to fineLocation,
|
|
237
|
+
"requiredPermissions" to requiredPermissions,
|
|
238
|
+
"details" to mapOf(
|
|
239
|
+
"fineLocation" to fineLocation,
|
|
240
|
+
"coarseLocation" to coarseLocation
|
|
241
|
+
)
|
|
242
|
+
))
|
|
243
|
+
} catch (e: Exception) {
|
|
244
|
+
Log.e(TAG, "Error checking permission", e)
|
|
245
|
+
promise.resolve(mapOf(
|
|
246
|
+
"locationGranted" to false,
|
|
247
|
+
"canAccessWifiInfo" to false,
|
|
248
|
+
"requiredPermissions" to listOf(Manifest.permission.ACCESS_FINE_LOCATION)
|
|
249
|
+
))
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
// 권한 요청
|
|
254
|
+
AsyncFunction("requestPermission") { promise: Promise ->
|
|
255
|
+
try {
|
|
256
|
+
val permissions = appContext.permissions
|
|
257
|
+
if (permissions == null) {
|
|
258
|
+
promise.resolve(mapOf(
|
|
259
|
+
"locationGranted" to false,
|
|
260
|
+
"canAccessWifiInfo" to false,
|
|
261
|
+
"requiredPermissions" to listOf(Manifest.permission.ACCESS_FINE_LOCATION)
|
|
262
|
+
))
|
|
263
|
+
return@AsyncFunction
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
permissions.askForPermissions(
|
|
267
|
+
{ result ->
|
|
268
|
+
val granted = result[Manifest.permission.ACCESS_FINE_LOCATION]?.granted ?: false
|
|
269
|
+
promise.resolve(mapOf(
|
|
270
|
+
"locationGranted" to granted,
|
|
271
|
+
"canAccessWifiInfo" to granted,
|
|
272
|
+
"requiredPermissions" to if (granted) emptyList<String>()
|
|
273
|
+
else listOf(Manifest.permission.ACCESS_FINE_LOCATION)
|
|
274
|
+
))
|
|
275
|
+
},
|
|
276
|
+
Manifest.permission.ACCESS_FINE_LOCATION
|
|
277
|
+
)
|
|
278
|
+
} catch (e: Exception) {
|
|
279
|
+
Log.e(TAG, "Error requesting permission", e)
|
|
280
|
+
promise.resolve(mapOf(
|
|
281
|
+
"locationGranted" to false,
|
|
282
|
+
"canAccessWifiInfo" to false,
|
|
283
|
+
"requiredPermissions" to listOf(Manifest.permission.ACCESS_FINE_LOCATION)
|
|
284
|
+
))
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
private fun hasLocationPermission(): Boolean {
|
|
290
|
+
return ContextCompat.checkSelfPermission(
|
|
291
|
+
context, Manifest.permission.ACCESS_FINE_LOCATION
|
|
292
|
+
) == PackageManager.PERMISSION_GRANTED
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
private fun getWifiInfo(): Map<String, Any?> {
|
|
296
|
+
@Suppress("DEPRECATION")
|
|
297
|
+
val wifiInfo: WifiInfo? = wifiManager.connectionInfo
|
|
298
|
+
val isConnected = isWifiConnected()
|
|
299
|
+
|
|
300
|
+
if (wifiInfo == null || !isConnected) {
|
|
301
|
+
return mapOf(
|
|
302
|
+
"ssid" to null,
|
|
303
|
+
"bssid" to null,
|
|
304
|
+
"rssi" to null,
|
|
305
|
+
"signalLevel" to null,
|
|
306
|
+
"frequency" to null,
|
|
307
|
+
"linkSpeed" to null,
|
|
308
|
+
"ipAddress" to null,
|
|
309
|
+
"isConnected" to false
|
|
310
|
+
)
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
val ssid = wifiInfo.ssid?.replace("\"", "")?.let {
|
|
314
|
+
if (it == "<unknown ssid>") null else it
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
return mapOf(
|
|
318
|
+
"ssid" to ssid,
|
|
319
|
+
"bssid" to wifiInfo.bssid,
|
|
320
|
+
"rssi" to wifiInfo.rssi,
|
|
321
|
+
"signalLevel" to WifiManager.calculateSignalLevel(wifiInfo.rssi, 100),
|
|
322
|
+
"frequency" to wifiInfo.frequency,
|
|
323
|
+
"linkSpeed" to wifiInfo.linkSpeed,
|
|
324
|
+
"ipAddress" to intToIp(wifiInfo.ipAddress),
|
|
325
|
+
"isConnected" to isConnected,
|
|
326
|
+
"networkId" to wifiInfo.networkId
|
|
327
|
+
)
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
private fun isWifiConnected(): Boolean {
|
|
331
|
+
val network = connectivityManager.activeNetwork ?: return false
|
|
332
|
+
val capabilities = connectivityManager.getNetworkCapabilities(network) ?: return false
|
|
333
|
+
return capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
private fun intToIp(ip: Int): String {
|
|
337
|
+
return "${ip and 0xFF}.${ip shr 8 and 0xFF}.${ip shr 16 and 0xFF}.${ip shr 24 and 0xFF}"
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
private fun getSecurityType(scanResult: ScanResult): String {
|
|
341
|
+
val capabilities = scanResult.capabilities
|
|
342
|
+
return when {
|
|
343
|
+
capabilities.contains("WPA3") -> "WPA3"
|
|
344
|
+
capabilities.contains("WPA2") && capabilities.contains("WPA3") -> "WPA2_WPA3"
|
|
345
|
+
capabilities.contains("WPA2") -> "WPA2"
|
|
346
|
+
capabilities.contains("WPA") && capabilities.contains("WPA2") -> "WPA_WPA2"
|
|
347
|
+
capabilities.contains("WPA") -> "WPA"
|
|
348
|
+
capabilities.contains("WEP") -> "WEP"
|
|
349
|
+
else -> "OPEN"
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
private fun frequencyToChannel(frequency: Int): Int {
|
|
354
|
+
return when {
|
|
355
|
+
frequency in 2412..2484 -> (frequency - 2412) / 5 + 1
|
|
356
|
+
frequency in 5170..5825 -> (frequency - 5170) / 5 + 34
|
|
357
|
+
else -> -1
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
private fun connectWifiAndroid10(ssid: String, password: String?, isHidden: Boolean, promise: Promise) {
|
|
362
|
+
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
|
|
363
|
+
promise.resolve(mapOf(
|
|
364
|
+
"success" to false,
|
|
365
|
+
"error" to "Android 10+ required",
|
|
366
|
+
"errorCode" to "NOT_SUPPORTED"
|
|
367
|
+
))
|
|
368
|
+
return
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
val specifierBuilder = WifiNetworkSpecifier.Builder()
|
|
372
|
+
.setSsid(ssid)
|
|
373
|
+
.setIsHiddenSsid(isHidden)
|
|
374
|
+
|
|
375
|
+
if (!password.isNullOrEmpty()) {
|
|
376
|
+
specifierBuilder.setWpa2Passphrase(password)
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
val networkRequest = NetworkRequest.Builder()
|
|
380
|
+
.addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
|
|
381
|
+
.setNetworkSpecifier(specifierBuilder.build())
|
|
382
|
+
.build()
|
|
383
|
+
|
|
384
|
+
networkCallback = object : ConnectivityManager.NetworkCallback() {
|
|
385
|
+
override fun onAvailable(network: Network) {
|
|
386
|
+
super.onAvailable(network)
|
|
387
|
+
connectivityManager.bindProcessToNetwork(network)
|
|
388
|
+
val wifiInfo = getWifiInfo()
|
|
389
|
+
promise.resolve(mapOf(
|
|
390
|
+
"success" to true,
|
|
391
|
+
"wifiInfo" to wifiInfo
|
|
392
|
+
))
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
override fun onUnavailable() {
|
|
396
|
+
super.onUnavailable()
|
|
397
|
+
promise.resolve(mapOf(
|
|
398
|
+
"success" to false,
|
|
399
|
+
"error" to "Network unavailable",
|
|
400
|
+
"errorCode" to "CONNECTION_FAILED"
|
|
401
|
+
))
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
connectivityManager.requestNetwork(networkRequest, networkCallback!!)
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
@Suppress("DEPRECATION")
|
|
409
|
+
private fun connectWifiLegacy(ssid: String, password: String?, isHidden: Boolean, promise: Promise) {
|
|
410
|
+
val wifiConfig = WifiConfiguration().apply {
|
|
411
|
+
SSID = "\"$ssid\""
|
|
412
|
+
hiddenSSID = isHidden
|
|
413
|
+
|
|
414
|
+
if (password.isNullOrEmpty()) {
|
|
415
|
+
allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE)
|
|
416
|
+
} else {
|
|
417
|
+
preSharedKey = "\"$password\""
|
|
418
|
+
allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK)
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
val networkId = wifiManager.addNetwork(wifiConfig)
|
|
423
|
+
if (networkId == -1) {
|
|
424
|
+
promise.resolve(mapOf(
|
|
425
|
+
"success" to false,
|
|
426
|
+
"error" to "Failed to add network configuration",
|
|
427
|
+
"errorCode" to "CONNECTION_FAILED"
|
|
428
|
+
))
|
|
429
|
+
return
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
wifiManager.disconnect()
|
|
433
|
+
val enabled = wifiManager.enableNetwork(networkId, true)
|
|
434
|
+
val reconnected = wifiManager.reconnect()
|
|
435
|
+
|
|
436
|
+
if (enabled && reconnected) {
|
|
437
|
+
val wifiInfo = getWifiInfo()
|
|
438
|
+
promise.resolve(mapOf(
|
|
439
|
+
"success" to true,
|
|
440
|
+
"wifiInfo" to wifiInfo
|
|
441
|
+
))
|
|
442
|
+
} else {
|
|
443
|
+
promise.resolve(mapOf(
|
|
444
|
+
"success" to false,
|
|
445
|
+
"error" to "Failed to connect to network",
|
|
446
|
+
"errorCode" to "CONNECTION_FAILED"
|
|
447
|
+
))
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
private fun registerWifiStateReceiver() {
|
|
452
|
+
if (wifiStateReceiver != null) return
|
|
453
|
+
|
|
454
|
+
wifiStateReceiver = object : BroadcastReceiver() {
|
|
455
|
+
override fun onReceive(context: Context?, intent: Intent?) {
|
|
456
|
+
when (intent?.action) {
|
|
457
|
+
WifiManager.WIFI_STATE_CHANGED_ACTION -> {
|
|
458
|
+
val state = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE, WifiManager.WIFI_STATE_UNKNOWN)
|
|
459
|
+
val wifiState = when (state) {
|
|
460
|
+
WifiManager.WIFI_STATE_DISABLED -> "DISABLED"
|
|
461
|
+
WifiManager.WIFI_STATE_DISABLING -> "DISABLING"
|
|
462
|
+
WifiManager.WIFI_STATE_ENABLED -> "ENABLED"
|
|
463
|
+
WifiManager.WIFI_STATE_ENABLING -> "ENABLING"
|
|
464
|
+
else -> "UNKNOWN"
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
sendEvent(EVENT_WIFI_STATE_CHANGE, mapOf(
|
|
468
|
+
"type" to "WIFI_STATE_CHANGED",
|
|
469
|
+
"wifiState" to wifiState,
|
|
470
|
+
"timestamp" to System.currentTimeMillis()
|
|
471
|
+
))
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
WifiManager.NETWORK_STATE_CHANGED_ACTION -> {
|
|
475
|
+
val wifiInfo = getWifiInfo()
|
|
476
|
+
val connectionState = if (wifiInfo["isConnected"] == true) "CONNECTED" else "DISCONNECTED"
|
|
477
|
+
|
|
478
|
+
sendEvent(EVENT_WIFI_STATE_CHANGE, mapOf(
|
|
479
|
+
"type" to "CONNECTION_STATE_CHANGED",
|
|
480
|
+
"connectionState" to connectionState,
|
|
481
|
+
"wifiInfo" to wifiInfo,
|
|
482
|
+
"timestamp" to System.currentTimeMillis()
|
|
483
|
+
))
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
val intentFilter = IntentFilter().apply {
|
|
490
|
+
addAction(WifiManager.WIFI_STATE_CHANGED_ACTION)
|
|
491
|
+
addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION)
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
context.registerReceiver(wifiStateReceiver, intentFilter)
|
|
495
|
+
Log.d(TAG, "WiFi state receiver registered")
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
private fun unregisterWifiStateReceiver() {
|
|
499
|
+
wifiStateReceiver?.let {
|
|
500
|
+
try {
|
|
501
|
+
context.unregisterReceiver(it)
|
|
502
|
+
} catch (e: Exception) {
|
|
503
|
+
Log.e(TAG, "Error unregistering receiver", e)
|
|
504
|
+
}
|
|
505
|
+
wifiStateReceiver = null
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
networkCallback?.let {
|
|
509
|
+
try {
|
|
510
|
+
connectivityManager.unregisterNetworkCallback(it)
|
|
511
|
+
} catch (e: Exception) {
|
|
512
|
+
Log.e(TAG, "Error unregistering network callback", e)
|
|
513
|
+
}
|
|
514
|
+
networkCallback = null
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
package expo.modules.customwifi
|
|
2
|
+
|
|
3
|
+
import android.content.BroadcastReceiver
|
|
4
|
+
import android.content.Context
|
|
5
|
+
import android.content.Intent
|
|
6
|
+
import android.net.wifi.WifiManager
|
|
7
|
+
import android.util.Log
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* WiFi 상태 변경을 감지하는 BroadcastReceiver
|
|
11
|
+
* AndroidManifest.xml에 등록되어 시스템 레벨에서 WiFi 상태 변경을 수신
|
|
12
|
+
*/
|
|
13
|
+
class WifiStateReceiver : BroadcastReceiver() {
|
|
14
|
+
companion object {
|
|
15
|
+
private const val TAG = "WifiStateReceiver"
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
override fun onReceive(context: Context?, intent: Intent?) {
|
|
19
|
+
if (context == null || intent == null) return
|
|
20
|
+
|
|
21
|
+
when (intent.action) {
|
|
22
|
+
WifiManager.WIFI_STATE_CHANGED_ACTION -> {
|
|
23
|
+
val state = intent.getIntExtra(
|
|
24
|
+
WifiManager.EXTRA_WIFI_STATE,
|
|
25
|
+
WifiManager.WIFI_STATE_UNKNOWN
|
|
26
|
+
)
|
|
27
|
+
val stateName = when (state) {
|
|
28
|
+
WifiManager.WIFI_STATE_DISABLED -> "DISABLED"
|
|
29
|
+
WifiManager.WIFI_STATE_DISABLING -> "DISABLING"
|
|
30
|
+
WifiManager.WIFI_STATE_ENABLED -> "ENABLED"
|
|
31
|
+
WifiManager.WIFI_STATE_ENABLING -> "ENABLING"
|
|
32
|
+
else -> "UNKNOWN"
|
|
33
|
+
}
|
|
34
|
+
Log.d(TAG, "WiFi state changed: $stateName")
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
WifiManager.NETWORK_STATE_CHANGED_ACTION -> {
|
|
38
|
+
Log.d(TAG, "Network state changed")
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
"android.net.conn.CONNECTIVITY_CHANGE" -> {
|
|
42
|
+
Log.d(TAG, "Connectivity changed")
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|