munim-wifi 0.1.1 → 0.1.3
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/ios/HybridMunimWifi.swift +146 -66
- package/package.json +1 -1
|
@@ -9,6 +9,7 @@ import Foundation
|
|
|
9
9
|
import NetworkExtension
|
|
10
10
|
import CoreLocation
|
|
11
11
|
import SystemConfiguration.CaptiveNetwork
|
|
12
|
+
import NitroModules
|
|
12
13
|
|
|
13
14
|
class HybridMunimWifi: HybridMunimWifiSpec {
|
|
14
15
|
private var locationManager: CLLocationManager?
|
|
@@ -19,21 +20,27 @@ class HybridMunimWifi: HybridMunimWifiSpec {
|
|
|
19
20
|
// CoreWLAN is macOS only - not available on iOS
|
|
20
21
|
// iOS can only get SSID/BSSID, not RSSI, channel, or frequency
|
|
21
22
|
|
|
22
|
-
func isWifiEnabled() throws -> Bool {
|
|
23
|
+
func isWifiEnabled() throws -> Promise<Bool> {
|
|
24
|
+
let promise = Promise<Bool>()
|
|
23
25
|
// On iOS, we can't directly check if Wi-Fi is enabled
|
|
24
26
|
// We can infer it by checking if we can get current network
|
|
25
27
|
if let _ = try? getCurrentNetworkSync() {
|
|
26
|
-
|
|
28
|
+
promise.resolve(withResult: true)
|
|
29
|
+
} else {
|
|
30
|
+
promise.resolve(withResult: false)
|
|
27
31
|
}
|
|
28
|
-
return
|
|
32
|
+
return promise
|
|
29
33
|
}
|
|
30
34
|
|
|
31
|
-
func requestWifiPermission() throws -> Bool {
|
|
35
|
+
func requestWifiPermission() throws -> Promise<Bool> {
|
|
36
|
+
let promise = Promise<Bool>()
|
|
32
37
|
let locationManager = CLLocationManager()
|
|
33
38
|
self.locationManager = locationManager
|
|
34
39
|
|
|
35
40
|
let status = locationManager.authorizationStatus
|
|
36
|
-
|
|
41
|
+
let hasPermission = status == .authorizedWhenInUse || status == .authorizedAlways
|
|
42
|
+
promise.resolve(withResult: hasPermission)
|
|
43
|
+
return promise
|
|
37
44
|
}
|
|
38
45
|
|
|
39
46
|
// Helper to get current network synchronously
|
|
@@ -43,9 +50,15 @@ class HybridMunimWifi: HybridMunimWifiSpec {
|
|
|
43
50
|
|
|
44
51
|
NEHotspotNetwork.fetchCurrent { network in
|
|
45
52
|
if let network = network {
|
|
53
|
+
// Get IP address
|
|
54
|
+
let ipAddress = self.getIPAddressSync()
|
|
46
55
|
result = CurrentNetworkInfo(
|
|
47
56
|
ssid: network.ssid,
|
|
48
|
-
bssid: network.bssid ?? ""
|
|
57
|
+
bssid: network.bssid ?? "",
|
|
58
|
+
ipAddress: ipAddress,
|
|
59
|
+
subnetMask: nil,
|
|
60
|
+
gateway: nil,
|
|
61
|
+
dnsServers: nil
|
|
49
62
|
)
|
|
50
63
|
}
|
|
51
64
|
semaphore.signal()
|
|
@@ -55,7 +68,40 @@ class HybridMunimWifi: HybridMunimWifiSpec {
|
|
|
55
68
|
return result
|
|
56
69
|
}
|
|
57
70
|
|
|
58
|
-
|
|
71
|
+
// Helper to get IP address synchronously
|
|
72
|
+
private func getIPAddressSync() -> String? {
|
|
73
|
+
var address: String?
|
|
74
|
+
var ifaddr: UnsafeMutablePointer<ifaddrs>?
|
|
75
|
+
|
|
76
|
+
guard getifaddrs(&ifaddr) == 0 else { return nil }
|
|
77
|
+
defer { freeifaddrs(ifaddr) }
|
|
78
|
+
|
|
79
|
+
guard var ptr = ifaddr else { return nil }
|
|
80
|
+
|
|
81
|
+
while ptr != nil {
|
|
82
|
+
defer { ptr = ptr.pointee.ifa_next }
|
|
83
|
+
|
|
84
|
+
let interface = ptr.pointee
|
|
85
|
+
let addrFamily = interface.ifa_addr.pointee.sa_family
|
|
86
|
+
|
|
87
|
+
if addrFamily == UInt8(AF_INET) {
|
|
88
|
+
let name = String(cString: interface.ifa_name)
|
|
89
|
+
if name == "en0" || name == "en1" {
|
|
90
|
+
var hostname = [CChar](repeating: 0, count: Int(NI_MAXHOST))
|
|
91
|
+
getnameinfo(interface.ifa_addr, socklen_t(interface.ifa_addr.pointee.sa_len),
|
|
92
|
+
&hostname, socklen_t(hostname.count),
|
|
93
|
+
nil, socklen_t(0), NI_NUMERICHOST)
|
|
94
|
+
address = String(cString: hostname)
|
|
95
|
+
break
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
return address
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
func scanNetworks(options: ScanOptions?) throws -> Promise<[WifiNetwork]> {
|
|
104
|
+
let promise = Promise<[WifiNetwork]>()
|
|
59
105
|
// iOS limitation: Cannot scan for networks directly
|
|
60
106
|
// Only can get current connected network
|
|
61
107
|
// For scanning, we can only return the current network if connected
|
|
@@ -70,17 +116,18 @@ class HybridMunimWifi: HybridMunimWifiSpec {
|
|
|
70
116
|
channel: nil, // Not available on iOS
|
|
71
117
|
capabilities: nil,
|
|
72
118
|
isSecure: nil,
|
|
73
|
-
timestamp:
|
|
119
|
+
timestamp: Date().timeIntervalSince1970 * 1000
|
|
74
120
|
)
|
|
75
121
|
scanResults = [network]
|
|
76
|
-
|
|
122
|
+
promise.resolve(withResult: [network])
|
|
123
|
+
} else {
|
|
124
|
+
// Return empty array if not connected
|
|
125
|
+
promise.resolve(withResult: [])
|
|
77
126
|
}
|
|
78
|
-
|
|
79
|
-
// Return empty array if not connected
|
|
80
|
-
return []
|
|
127
|
+
return promise
|
|
81
128
|
}
|
|
82
129
|
|
|
83
|
-
func startScan(
|
|
130
|
+
func startScan(options: ScanOptions?) throws {
|
|
84
131
|
isScanning = true
|
|
85
132
|
// iOS limitation: Cannot continuously scan
|
|
86
133
|
// Just get current network once
|
|
@@ -93,7 +140,7 @@ class HybridMunimWifi: HybridMunimWifiSpec {
|
|
|
93
140
|
channel: nil,
|
|
94
141
|
capabilities: nil,
|
|
95
142
|
isSecure: nil,
|
|
96
|
-
timestamp:
|
|
143
|
+
timestamp: Date().timeIntervalSince1970 * 1000
|
|
97
144
|
)
|
|
98
145
|
scanResults = [network]
|
|
99
146
|
}
|
|
@@ -104,44 +151,73 @@ class HybridMunimWifi: HybridMunimWifiSpec {
|
|
|
104
151
|
isScanning = false
|
|
105
152
|
}
|
|
106
153
|
|
|
107
|
-
func getSSIDs() throws -> [String] {
|
|
154
|
+
func getSSIDs() throws -> Promise<[String]> {
|
|
155
|
+
let promise = Promise<[String]>()
|
|
108
156
|
// iOS limitation: Can only get current network SSID
|
|
109
157
|
if let current = try? getCurrentNetworkSync() {
|
|
110
|
-
|
|
158
|
+
promise.resolve(withResult: [current.ssid])
|
|
159
|
+
} else {
|
|
160
|
+
promise.resolve(withResult: [])
|
|
111
161
|
}
|
|
112
|
-
return
|
|
162
|
+
return promise
|
|
113
163
|
}
|
|
114
164
|
|
|
115
|
-
func getWifiFingerprint() throws -> WifiFingerprint {
|
|
165
|
+
func getWifiFingerprint() throws -> Promise<WifiFingerprint> {
|
|
166
|
+
let promise = Promise<WifiFingerprint>()
|
|
116
167
|
// iOS limitation: Can only get current network, no RSSI/channel/frequency
|
|
117
|
-
|
|
168
|
+
var networks: [WifiNetwork] = scanResults
|
|
169
|
+
if networks.isEmpty {
|
|
170
|
+
if let current = try? getCurrentNetworkSync() {
|
|
171
|
+
networks = [WifiNetwork(
|
|
172
|
+
ssid: current.ssid,
|
|
173
|
+
bssid: current.bssid,
|
|
174
|
+
rssi: nil,
|
|
175
|
+
frequency: nil,
|
|
176
|
+
channel: nil,
|
|
177
|
+
capabilities: nil,
|
|
178
|
+
isSecure: nil,
|
|
179
|
+
timestamp: Date().timeIntervalSince1970 * 1000
|
|
180
|
+
)]
|
|
181
|
+
}
|
|
182
|
+
}
|
|
118
183
|
|
|
119
|
-
|
|
184
|
+
let fingerprint = WifiFingerprint(
|
|
120
185
|
networks: networks,
|
|
121
|
-
timestamp:
|
|
186
|
+
timestamp: Date().timeIntervalSince1970 * 1000,
|
|
187
|
+
location: nil
|
|
122
188
|
)
|
|
189
|
+
promise.resolve(withResult: fingerprint)
|
|
190
|
+
return promise
|
|
123
191
|
}
|
|
124
192
|
|
|
125
|
-
func getRSSI(ssid: String) throws ->
|
|
193
|
+
func getRSSI(ssid: String) throws -> Promise<Variant_NullType_Double> {
|
|
194
|
+
let promise = Promise<Variant_NullType_Double>()
|
|
126
195
|
// iOS limitation: RSSI not available for scanned networks
|
|
127
|
-
|
|
196
|
+
promise.resolve(withResult: .first(margelo.nitro.NullType.null))
|
|
197
|
+
return promise
|
|
128
198
|
}
|
|
129
199
|
|
|
130
|
-
func getBSSID(ssid: String) throws ->
|
|
200
|
+
func getBSSID(ssid: String) throws -> Promise<Variant_NullType_String> {
|
|
201
|
+
let promise = Promise<Variant_NullType_String>()
|
|
131
202
|
if let current = try? getCurrentNetworkSync(), current.ssid == ssid {
|
|
132
|
-
|
|
203
|
+
promise.resolve(withResult: .second(current.bssid))
|
|
204
|
+
} else {
|
|
205
|
+
promise.resolve(withResult: .first(margelo.nitro.NullType.null))
|
|
133
206
|
}
|
|
134
|
-
return
|
|
207
|
+
return promise
|
|
135
208
|
}
|
|
136
209
|
|
|
137
|
-
func getChannelInfo(ssid: String) throws ->
|
|
210
|
+
func getChannelInfo(ssid: String) throws -> Promise<Variant_NullType_ChannelInfo> {
|
|
211
|
+
let promise = Promise<Variant_NullType_ChannelInfo>()
|
|
138
212
|
// iOS limitation: Channel and frequency not available
|
|
139
|
-
|
|
213
|
+
promise.resolve(withResult: .first(margelo.nitro.NullType.null))
|
|
214
|
+
return promise
|
|
140
215
|
}
|
|
141
216
|
|
|
142
|
-
func getNetworkInfo(ssid: String) throws ->
|
|
217
|
+
func getNetworkInfo(ssid: String) throws -> Promise<Variant_NullType_WifiNetwork> {
|
|
218
|
+
let promise = Promise<Variant_NullType_WifiNetwork>()
|
|
143
219
|
if let current = try? getCurrentNetworkSync(), current.ssid == ssid {
|
|
144
|
-
|
|
220
|
+
let network = WifiNetwork(
|
|
145
221
|
ssid: current.ssid,
|
|
146
222
|
bssid: current.bssid,
|
|
147
223
|
rssi: nil, // Not available on iOS
|
|
@@ -149,31 +225,48 @@ class HybridMunimWifi: HybridMunimWifiSpec {
|
|
|
149
225
|
channel: nil, // Not available on iOS
|
|
150
226
|
capabilities: nil,
|
|
151
227
|
isSecure: nil,
|
|
152
|
-
timestamp:
|
|
228
|
+
timestamp: Date().timeIntervalSince1970 * 1000
|
|
153
229
|
)
|
|
230
|
+
promise.resolve(withResult: .second(network))
|
|
231
|
+
} else {
|
|
232
|
+
promise.resolve(withResult: .first(margelo.nitro.NullType.null))
|
|
154
233
|
}
|
|
155
|
-
return
|
|
234
|
+
return promise
|
|
156
235
|
}
|
|
157
236
|
|
|
158
|
-
func getCurrentNetwork() throws ->
|
|
159
|
-
|
|
237
|
+
func getCurrentNetwork() throws -> Promise<Variant_NullType_CurrentNetworkInfo> {
|
|
238
|
+
let promise = Promise<Variant_NullType_CurrentNetworkInfo>()
|
|
160
239
|
let semaphore = DispatchSemaphore(value: 0)
|
|
240
|
+
var result: CurrentNetworkInfo? = nil
|
|
161
241
|
|
|
162
242
|
NEHotspotNetwork.fetchCurrent { network in
|
|
163
243
|
if let network = network {
|
|
244
|
+
// Get IP address
|
|
245
|
+
let ipAddress = self.getIPAddressSync()
|
|
164
246
|
result = CurrentNetworkInfo(
|
|
165
247
|
ssid: network.ssid,
|
|
166
|
-
bssid: network.bssid ?? ""
|
|
248
|
+
bssid: network.bssid ?? "",
|
|
249
|
+
ipAddress: ipAddress,
|
|
250
|
+
subnetMask: nil,
|
|
251
|
+
gateway: nil,
|
|
252
|
+
dnsServers: nil
|
|
167
253
|
)
|
|
168
254
|
}
|
|
169
255
|
semaphore.signal()
|
|
170
256
|
}
|
|
171
257
|
|
|
172
258
|
_ = semaphore.wait(timeout: .now() + 5)
|
|
173
|
-
|
|
259
|
+
|
|
260
|
+
if let result = result {
|
|
261
|
+
promise.resolve(withResult: .second(result))
|
|
262
|
+
} else {
|
|
263
|
+
promise.resolve(withResult: .first(margelo.nitro.NullType.null))
|
|
264
|
+
}
|
|
265
|
+
return promise
|
|
174
266
|
}
|
|
175
267
|
|
|
176
|
-
func connectToNetwork(options: ConnectionOptions) throws {
|
|
268
|
+
func connectToNetwork(options: ConnectionOptions) throws -> Promise<Void> {
|
|
269
|
+
let promise = Promise<Void>()
|
|
177
270
|
let configuration: NEHotspotConfiguration
|
|
178
271
|
|
|
179
272
|
if let password = options.password {
|
|
@@ -199,11 +292,15 @@ class HybridMunimWifi: HybridMunimWifiSpec {
|
|
|
199
292
|
_ = semaphore.wait(timeout: .now() + 30)
|
|
200
293
|
|
|
201
294
|
if let error = error {
|
|
202
|
-
|
|
295
|
+
promise.reject(withError: error)
|
|
296
|
+
} else {
|
|
297
|
+
promise.resolve()
|
|
203
298
|
}
|
|
299
|
+
return promise
|
|
204
300
|
}
|
|
205
301
|
|
|
206
|
-
func disconnect() throws {
|
|
302
|
+
func disconnect() throws -> Promise<Void> {
|
|
303
|
+
let promise = Promise<Void>()
|
|
207
304
|
// On iOS, we can't directly disconnect from Wi-Fi
|
|
208
305
|
// We can only remove saved configurations
|
|
209
306
|
// This is an iOS limitation
|
|
@@ -211,37 +308,20 @@ class HybridMunimWifi: HybridMunimWifiSpec {
|
|
|
211
308
|
if let current = try? getCurrentNetworkSync() {
|
|
212
309
|
NEHotspotConfigurationManager.shared.removeConfiguration(forSSID: current.ssid)
|
|
213
310
|
}
|
|
311
|
+
promise.resolve()
|
|
312
|
+
return promise
|
|
214
313
|
}
|
|
215
314
|
|
|
216
|
-
func getIPAddress() throws ->
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
guard getifaddrs(&ifaddr) == 0 else { return nil }
|
|
221
|
-
defer { freeifaddrs(ifaddr) }
|
|
315
|
+
func getIPAddress() throws -> Promise<Variant_NullType_String> {
|
|
316
|
+
let promise = Promise<Variant_NullType_String>()
|
|
317
|
+
let address = getIPAddressSync()
|
|
222
318
|
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
let interface = ptr.pointee
|
|
229
|
-
let addrFamily = interface.ifa_addr.pointee.sa_family
|
|
230
|
-
|
|
231
|
-
if addrFamily == UInt8(AF_INET) {
|
|
232
|
-
let name = String(cString: interface.ifa_name)
|
|
233
|
-
if name == "en0" || name == "en1" {
|
|
234
|
-
var hostname = [CChar](repeating: 0, count: Int(NI_MAXHOST))
|
|
235
|
-
getnameinfo(interface.ifa_addr, socklen_t(interface.ifa_addr.pointee.sa_len),
|
|
236
|
-
&hostname, socklen_t(hostname.count),
|
|
237
|
-
nil, socklen_t(0), NI_NUMERICHOST)
|
|
238
|
-
address = String(cString: hostname)
|
|
239
|
-
break
|
|
240
|
-
}
|
|
241
|
-
}
|
|
319
|
+
if let address = address {
|
|
320
|
+
promise.resolve(withResult: .second(address))
|
|
321
|
+
} else {
|
|
322
|
+
promise.resolve(withResult: .first(margelo.nitro.NullType.null))
|
|
242
323
|
}
|
|
243
|
-
|
|
244
|
-
return address
|
|
324
|
+
return promise
|
|
245
325
|
}
|
|
246
326
|
|
|
247
327
|
func addListener(eventName: String) throws {
|