1 import ABI48_0_0ExpoModulesCore
2 import SystemConfiguration
3 import Network
4 
5 public final class NetworkModule: Module {
6   private let monitor = NWPathMonitor()
7   private let monitorQueue = DispatchQueue.global(qos: .default)
8 
definitionnull9   public func definition() -> ModuleDefinition {
10     Name("ExpoNetwork")
11 
12     OnCreate {
13       monitor.start(queue: monitorQueue)
14     }
15 
16     AsyncFunction("getIpAddressAsync") { () -> String? in
17       return try getIPAddress()
18     }
19 
20     AsyncFunction("getNetworkStateAsync") {
21       return getNetworkStateAsync()
22     }
23 
24     OnDestroy {
25       monitor.cancel()
26     }
27   }
28 
getIPAddressnull29   private func getIPAddress() throws -> String {
30     var address = "0.0.0.0"
31     var ifaddr: UnsafeMutablePointer<ifaddrs>?
32 
33     let error = getifaddrs(&ifaddr)
34 
35     guard error == 0 else {
36       throw IpAddressException(error)
37     }
38 
39     guard let firstAddr = ifaddr else {
40       return address
41     }
42 
43     for ifptr in sequence(first: firstAddr, next: { $0.pointee.ifa_next }) {
44       let temp = ifptr.pointee
45       let family = temp.ifa_addr.pointee.sa_family
46 
47       if family == UInt8(AF_INET) {
48         let name = String(cString: temp.ifa_name)
49         if name == "en0" || name == "en1" {
50           var hostname = [CChar](repeating: 0, count: Int(NI_MAXHOST))
51           getnameinfo(
52             temp.ifa_addr,
53             socklen_t(temp.ifa_addr.pointee.sa_len),
54             &hostname,
55             socklen_t(hostname.count),
56             nil,
57             socklen_t(0),
58             NI_NUMERICHOST)
59           address = String(cString: hostname)
60         }
61       }
62     }
63 
64     freeifaddrs(ifaddr)
65     return address
66   }
67 
getNetworkStateAsyncnull68   private func getNetworkStateAsync() -> [String: Any] {
69     let path = monitor.currentPath
70     let isConnected = path.status == .satisfied
71     var currentNetworkType = NetworkType.unknown
72 
73     if !isConnected {
74       return [
75         "type": NetworkType.none.description,
76         "isConnected": isConnected,
77         "isInternetReachable": isConnected
78       ]
79     }
80 
81     let connectionType = NWInterface
82       .InterfaceType
83       .allCases
84       .filter { path.usesInterfaceType($0) }
85       .first
86 
87     switch connectionType {
88     case .wifi:
89       currentNetworkType = .wifi
90     case .cellular:
91       currentNetworkType = .cellular
92     default:
93       currentNetworkType = .unknown
94     }
95 
96     return [
97       "type": currentNetworkType.description,
98       "isConnected": isConnected,
99       "isInternetReachable": isConnected
100     ]
101   }
102 }
103