Swift - 获取设备的WIFI IP地址

95

我需要在Swift中获取iOS设备的IP地址。这不是其他关于此问题的重复!我只需要获取WiFi IP地址,如果没有WiFi IP地址-我需要处理它。 Stack Overflow上有一些关于此的问题,但只有返回IP地址的函数。例如(来自如何在Swift中获取IP地址):

func getIFAddresses() -> [String] {
    var addresses = [String]()

    // Get list of all interfaces on the local machine:
    var ifaddr : UnsafeMutablePointer<ifaddrs> = nil
    if getifaddrs(&ifaddr) == 0 {

        // For each interface ...
        for (var ptr = ifaddr; ptr != nil; ptr = ptr.memory.ifa_next) {
            let flags = Int32(ptr.memory.ifa_flags)
            var addr = ptr.memory.ifa_addr.memory

            // Check for running IPv4, IPv6 interfaces. Skip the loopback interface.
            if (flags & (IFF_UP|IFF_RUNNING|IFF_LOOPBACK)) == (IFF_UP|IFF_RUNNING) {
                if addr.sa_family == UInt8(AF_INET) || addr.sa_family == UInt8(AF_INET6) {

                    // Convert interface address to a human readable string:
                    var hostname = [CChar](count: Int(NI_MAXHOST), repeatedValue: 0)
                    if (getnameinfo(&addr, socklen_t(addr.sa_len), &hostname, socklen_t(hostname.count),
                        nil, socklen_t(0), NI_NUMERICHOST) == 0) {
                            if let address = String.fromCString(hostname) {
                                addresses.append(address)
                            }
                    }
                }
            }
        }
        freeifaddrs(ifaddr)
    }

    return addresses
}

我这里得到了两个值——来自手机网络(我想是)的地址和我需要的WiFi地址。是否有其他方法只获取WiFi IP地址?

18个回答

144
根据一些SO线程(例如,What exactly means iOS networking interface name? what's pdp_ip ? what's ap?),iOS设备上的WiFi接口始终具有名称"en0"。
您的代码(似乎是我在How to get Ip address in swift中所回答的 :) )检索所有运行中网络接口的IP地址列表。它可以轻松地修改为仅返回“en0”接口的IP地址,并且实际上这就是我最初在该线程中回答的内容(这只是how to get ip address of iphone programmatically答案的Swift翻译)。
// Return IP address of WiFi interface (en0) as a String, or `nil`
func getWiFiAddress() -> String? {
    var address : String?

    // Get list of all interfaces on the local machine:
    var ifaddr : UnsafeMutablePointer<ifaddrs> = nil
    if getifaddrs(&ifaddr) == 0 {

        // For each interface ...
        var ptr = ifaddr
        while ptr != nil {
            defer { ptr = ptr.memory.ifa_next }

            let interface = ptr.memory

            // Check for IPv4 or IPv6 interface:
            let addrFamily = interface.ifa_addr.memory.sa_family
            if addrFamily == UInt8(AF_INET) || addrFamily == UInt8(AF_INET6) {

                // Check interface name:
                if let name = String.fromCString(interface.ifa_name) where name == "en0" {

                    // Convert interface address to a human readable string:
                    var hostname = [CChar](count: Int(NI_MAXHOST), repeatedValue: 0)
                    getnameinfo(interface.ifa_addr, socklen_t(interface.ifa_addr.memory.sa_len),
                                &hostname, socklen_t(hostname.count),
                                nil, socklen_t(0), NI_NUMERICHOST)
                    address = String.fromCString(hostname)
                }
            }
        }
        freeifaddrs(ifaddr)
    }

    return address
}

使用方法:

if let addr = getWiFiAddress() {
    print(addr)
} else {
    print("No WiFi address")
}

Swift 3更新:除了将代码适应Swift 3中的许多更改之外,现在迭代所有接口可以使用新的泛化sequence()函数:

不要忘记在你的桥接头文件中添加#include <ifaddrs.h>

// Return IP address of WiFi interface (en0) as a String, or `nil`
func getWiFiAddress() -> String? {
    var address : String?

    // Get list of all interfaces on the local machine:
    var ifaddr : UnsafeMutablePointer<ifaddrs>?
    guard getifaddrs(&ifaddr) == 0 else { return nil }
    guard let firstAddr = ifaddr else { return nil }

    // For each interface ...
    for ifptr in sequence(first: firstAddr, next: { $0.pointee.ifa_next }) {
        let interface = ifptr.pointee

        // Check for IPv4 or IPv6 interface:
        let addrFamily = interface.ifa_addr.pointee.sa_family
        if addrFamily == UInt8(AF_INET) || addrFamily == UInt8(AF_INET6) {

            // Check interface name:
            let name = String(cString: interface.ifa_name)
            if  name == "en0" {

                // Convert interface address to a human readable string:
                var hostname = [CChar](repeating: 0, count: Int(NI_MAXHOST))
                getnameinfo(interface.ifa_addr, socklen_t(interface.ifa_addr.pointee.sa_len),
                            &hostname, socklen_t(hostname.count),
                            nil, socklen_t(0), NI_NUMERICHOST)
                address = String(cString: hostname)
            }
        }
    }
    freeifaddrs(ifaddr)

    return address
}

对于那些不仅仅想要WIFI IP的人,你可以稍微修改一下这段代码

func getAddress(for network: Network) -> String? {
    var address: String?

    // Get list of all interfaces on the local machine:
    var ifaddr: UnsafeMutablePointer<ifaddrs>?
    guard getifaddrs(&ifaddr) == 0 else { return nil }
    guard let firstAddr = ifaddr else { return nil }

    // For each interface ...
    for ifptr in sequence(first: firstAddr, next: { $0.pointee.ifa_next }) {
        let interface = ifptr.pointee

        // Check for IPv4 or IPv6 interface:
        let addrFamily = interface.ifa_addr.pointee.sa_family
        if addrFamily == UInt8(AF_INET) || addrFamily == UInt8(AF_INET6) {

            // Check interface name:
            let name = String(cString: interface.ifa_name)
            if name == network.rawValue {

                // Convert interface address to a human readable string:
                var hostname = [CChar](repeating: 0, count: Int(NI_MAXHOST))
                getnameinfo(interface.ifa_addr, socklen_t(interface.ifa_addr.pointee.sa_len),
                            &hostname, socklen_t(hostname.count),
                            nil, socklen_t(0), NI_NUMERICHOST)
                address = String(cString: hostname)
            }
        }
    }
    freeifaddrs(ifaddr)

    return address
}
enum Network: String {
    case wifi = "en0"
    case cellular = "pdp_ip0"
    //... case ipv4 = "ipv4"
    //... case ipv6 = "ipv6"
}

那么我们也可以访问移动设备的IP地址。

如果无法获取WiFi IP地址,则保护该代码:guard let wifiIp = getAddress(for: .wifi) else { return }

&

如果无法获取蜂窝网络IP地址,则保护该代码:guard let cellularIp = getAddress(for: .cellular) else { return }


1
@MartinR 我创建了一个桥接头文件,然后在该文件中包含了 #include <ifaddrs.h>,并将您的 Swift3 代码粘贴到我的视图控制器中,但是出现了 getifaddrs()、ifaddrs 和 freeifaddrs 的错误,请问如何解决? - narahari_arjun
2
@JayprakashDubey:这段代码特别针对WiFi(“en0”)地址。请参考https://dev59.com/EV8e5IYBdhLWcg3wja_5#25627545获取所有正在运行接口的IP地址(在我的测试中与移动网络一起使用)。 - Martin R
@Ramakrishna:尝试一下这个 https://dev59.com/EV8e5IYBdhLWcg3wja_5#25627545,它会返回*所有*接口地址。 - Martin R
1
@MegaManX:fe80::10ec:6bd9:1d19:ac29%en0 是一个“作用域限定的字面量IPv6地址”(https://en.wikipedia.org/wiki/IPv6_address#Scoped_literal_IPv6_addresses)。 - Martin R
@HirenRathod:我不再有Xcode 9.2了,但我已经使用Xcode 10.1和iOS 12的iPhone进行了双重检查。 它对我有效。 您的设备上启用了WiFi吗? 此代码特别检查WiFi(“en0”)设备。 - Martin R
显示剩余27条评论

48

获取wifi、有线和蜂窝网络的IP地址 - Swift 5

func getIPAddress() -> String {
    var address: String?
    var ifaddr: UnsafeMutablePointer<ifaddrs>? = nil
    if getifaddrs(&ifaddr) == 0 {
        var ptr = ifaddr
        while ptr != nil {
            defer { ptr = ptr?.pointee.ifa_next }

            guard let interface = ptr?.pointee else { return "" }
            let addrFamily = interface.ifa_addr.pointee.sa_family
            if addrFamily == UInt8(AF_INET) || addrFamily == UInt8(AF_INET6) {

                // wifi = ["en0"]
                // wired = ["en2", "en3", "en4"]
                // cellular = ["pdp_ip0","pdp_ip1","pdp_ip2","pdp_ip3"]

                let name: String = String(cString: (interface.ifa_name))
                if  name == "en0" || name == "en2" || name == "en3" || name == "en4" || name == "pdp_ip0" || name == "pdp_ip1" || name == "pdp_ip2" || name == "pdp_ip3" {
                    var hostname = [CChar](repeating: 0, count: Int(NI_MAXHOST))
                    getnameinfo(interface.ifa_addr, socklen_t((interface.ifa_addr.pointee.sa_len)), &hostname, socklen_t(hostname.count), nil, socklen_t(0), NI_NUMERICHOST)
                    address = String(cString: hostname)
                }
            }
        }
        freeifaddrs(ifaddr)
    }
    return address ?? ""
}

如何使用

let strIPAddress : String = self.getIPAddress()
print("IPAddress :: \(strIPAddress)")

注意:请将以下内容添加到您项目的“Bridging-Header”文件中

#include<ifaddrs.h>

没有错误,没有警告,完美运行。感谢评论中提供的额外信息。 - Sravan
设备上显示的地址是这样的: 2409:4043:986:e121:6449:eae9:c78f:1042 它正确吗? - shelen
6
我不必在我的桥接头文件中包含那个。 - Lance Samaria
有没有一种方法可以过滤掉IPv6地址,只获取IPv4地址,而不使用正则表达式? - undefined
1
嗨 @cdf1982,我会检查这个,并向你更新相关情况。 - undefined
显示剩余3条评论

20

创建桥接头文件并在其中包含#include <ifaddrs.h>

然后编写此方法。

func getIFAddresses() -> [String] {
var addresses = [String]()

// Get list of all interfaces on the local machine:
var ifaddr : UnsafeMutablePointer<ifaddrs> = nil
if getifaddrs(&ifaddr) == 0 {

    // For each interface ...
    for (var ptr = ifaddr; ptr != nil; ptr = ptr.memory.ifa_next) {
        let flags = Int32(ptr.memory.ifa_flags)
        var addr = ptr.memory.ifa_addr.memory

        // Check for running IPv4, IPv6 interfaces. Skip the loopback interface.
        if (flags & (IFF_UP|IFF_RUNNING|IFF_LOOPBACK)) == (IFF_UP|IFF_RUNNING) {
            if addr.sa_family == UInt8(AF_INET) || addr.sa_family == UInt8(AF_INET6) {

                // Convert interface address to a human readable string:
                var hostname = [CChar](count: Int(NI_MAXHOST), repeatedValue: 0)
                if (getnameinfo(&addr, socklen_t(addr.sa_len), &hostname, socklen_t(hostname.count),
                    nil, socklen_t(0), NI_NUMERICHOST) == 0) {
                        if let address = String.fromCString(hostname) {
                            addresses.append(address)
                        }
                }
            }
        }
    }
    freeifaddrs(ifaddr)
}

  return addresses
}

当我在我的视图控制器中像这样调用这个方法 var arr : NSArray = self.getIFAddresses(),我在控制台上得到了完美的响应,像这样:

IP :( "10.0.0.94" )

从这个数组中,你可以在任何地方访问它。 希望这有所帮助。


它返回地址数组f,如何从中获取wifi地址? - Nikita Zernov
你可以轻松地从数组中访问你想要的内容,不是吗? - iAnurag
"然后编写这个方法..." - 这是OP在问题中写的,你的代码是完全一样的副本(也和这里发布的代码完全相同:https://dev59.com/EV8e5IYBdhLWcg3wja_5#25627545)。" - Martin R
嗨,当我尝试使用方法UInt8(...)时,我的程序崩溃了,有人可以帮忙吗?https://stackoverflow.com/questions/55491986/swift-crash-when-getcurrentip-address-fixedwidthinteger-inita - famfamfam

20

避免使用强制解包并支持蜂窝和有线IP地址的UIDevice扩展Swift 4.2:

import UIKit

extension UIDevice {

    private struct InterfaceNames {
        static let wifi = ["en0"]
        static let wired = ["en2", "en3", "en4"]
        static let cellular = ["pdp_ip0","pdp_ip1","pdp_ip2","pdp_ip3"]
        static let supported = wifi + wired + cellular
    }

    func ipAddress() -> String? {
        var ipAddress: String?
        var ifaddr: UnsafeMutablePointer<ifaddrs>?

        if getifaddrs(&ifaddr) == 0 {
            var pointer = ifaddr

            while pointer != nil {
                defer { pointer = pointer?.pointee.ifa_next }

                guard
                    let interface = pointer?.pointee,
                    interface.ifa_addr.pointee.sa_family == UInt8(AF_INET) || interface.ifa_addr.pointee.sa_family == UInt8(AF_INET6),
                    let interfaceName = interface.ifa_name,
                    let interfaceNameFormatted = String(cString: interfaceName, encoding: .utf8),
                    InterfaceNames.supported.contains(interfaceNameFormatted)
                    else { continue }

                var hostname = [CChar](repeating: 0, count: Int(NI_MAXHOST))

                getnameinfo(interface.ifa_addr,
                            socklen_t(interface.ifa_addr.pointee.sa_len),
                            &hostname,
                            socklen_t(hostname.count),
                            nil,
                            socklen_t(0),
                            NI_NUMERICHOST)

                guard
                    let formattedIpAddress = String(cString: hostname, encoding: .utf8),
                    !formattedIpAddress.isEmpty
                    else { continue }

                ipAddress = formattedIpAddress
                break
            }

            freeifaddrs(ifaddr)
        }

        return ipAddress
    }

}

使用方法:

UIDevice.current.ipAddress()

我得到的是这样的 fe60::1341:942f:eb20:ff0%en0,有什么解决方案吗? - Sreekanth G
那是一个v6 IP @SreekanthG,这是预期的。 - Daniel Storm
我在我的设备上得到了这样的地址 2409:4043:986:e121:6449:eae9:c78f:1042。它正确吗? - shelen

16

Swift 4 - 获取设备的IP地址:

在您的桥接头文件中添加#include<ifaddrs.h>

这是获取IP地址所需的框架。

class func getIPAddress() -> String? {
        var address: String?
        var ifaddr: UnsafeMutablePointer<ifaddrs>? = nil
        if getifaddrs(&ifaddr) == 0 {
            var ptr = ifaddr
            while ptr != nil {
                defer { ptr = ptr?.pointee.ifa_next }

                let interface = ptr?.pointee
                let addrFamily = interface?.ifa_addr.pointee.sa_family
                if addrFamily == UInt8(AF_INET) || addrFamily == UInt8(AF_INET6) {

                    if let name: String = String(cString: (interface?.ifa_name)!), name == "en0" {
                        var hostname = [CChar](repeating: 0, count: Int(NI_MAXHOST))
                        getnameinfo(interface?.ifa_addr, socklen_t((interface?.ifa_addr.pointee.sa_len)!), &hostname, socklen_t(hostname.count), nil, socklen_t(0), NI_NUMERICHOST)
                        address = String(cString: hostname)
                    }
                }
            }
            freeifaddrs(ifaddr)
        }
        return address
}

收到“在对可选项进行检查时使用了类型为'String'的非可选表达式”的警告。 - Jonny
当我激活个人热点时,我的地址 === ""(即为空),但当我的设备连接到外部热点时正常工作。我正在使用iOS 12.1.4。 - b-asaf
嗨,当我尝试使用方法UInt8(...)时,我的程序崩溃了,有人可以帮忙吗?https://stackoverflow.com/questions/55491986/swift-crash-when-getcurrentip-address-fixedwidthinteger-inita - famfamfam

8
另一种有些不同的解决方案是使用免费的轻量级服务Ipify,您可以ping它以获取您的IP地址。
这里是他们提供的Swift示例:
let url = URL(string: "https://api.ipify.org")

do {
    if let url = url {
        let ipAddress = try String(contentsOf: url)
        print("My public IP address is: " + ipAddress)
    }
} catch let error {
    print(error)
}

6

Swift 5 清理

我更新了上面的答案,消除了任何强制解包和一些 SwiftLint 的清理。

 class func getIPAddress() -> String? {
        var address: String?
        var ifaddr: UnsafeMutablePointer<ifaddrs>?
        if getifaddrs(&ifaddr) == 0 {
            var ptr = ifaddr
            while ptr != nil {
                defer { ptr = ptr?.pointee.ifa_next }
                let interface = ptr?.pointee
                let addrFamily = interface?.ifa_addr.pointee.sa_family
                if addrFamily == UInt8(AF_INET) || addrFamily == UInt8(AF_INET6),
                    let cString = interface?.ifa_name,
                    String(cString: cString) == "en0",
                    let saLen = (interface?.ifa_addr.pointee.sa_len) {
                    var hostname = [CChar](repeating: 0, count: Int(NI_MAXHOST))
                    let ifaAddr = interface?.ifa_addr
                    getnameinfo(ifaAddr,
                                socklen_t(saLen),
                                &hostname,
                                socklen_t(hostname.count),
                                nil,
                                socklen_t(0),
                                NI_NUMERICHOST)
                    address = String(cString: hostname)
                }
            }
            freeifaddrs(ifaddr)
        }
        return address
    }

这更倾向于IPV6,并不总是返回IPV4地址。 - Ryan Daulton

6
您可以使用以下代码获取IP地址:

注意:我已经使用了reachability,以便在WiFi更改到另一个网络时捕获新的IP地址。

  1. In Podfile file

    pod 'ReachabilitySwift' and then install pod

  2. In AppDelegate.swift file import ReachabilitySwift

    Note : If it prompts an error that Could not find ReachabilitySwift module then simply copy and paste this. It works!

  3. didFinishLaunchingOptions function

    NotificationCenter.default.addObserver(self, selector: #selector(self.reachabilityChanged), name: ReachabilityChangedNotification, object: reachability)
    
    do{
        try reachability.startNotifier()
    }
    catch {
        print("could not start reachability notifier")
    } 
    
  4. Then copy paste below code in AppDelegate file

    func reachabilityChanged(note: NSNotification) {
    
        let reachability = note.object as! Reachability
    
        if reachability.isReachable {
            if reachability.isReachableViaWiFi {
                print("Reachable via WiFi")
            } else {
                print("Reachable via Cellular")
            }
    
            setIPAddress()
        } else {
            ipAddress = "" // No IP captures
            print("Network not reachable")
        }
    }
    
    func setIPAddress() {
        if let addr = self.getWiFiAddress() {
            print("ipAddress : \(addr)")
            ipAddress = addr
        } else {
            ipAddress = "" // No IP captures
            print("No WiFi address")
        }
    }
    
    // Return IP address of WiFi interface (en0) as a String, or `nil`
    func getWiFiAddress() -> String? {
        var address : String?
    
        // Get list of all interfaces on the local machine:
        var ifaddr : UnsafeMutablePointer<ifaddrs>?
        guard getifaddrs(&ifaddr) == 0 else { return nil }
        guard let firstAddr = ifaddr else { return nil }
    
        // For each interface ...
        for ifptr in sequence(first: firstAddr, next: { $0.pointee.ifa_next }) {
            let interface = ifptr.pointee
    
            // Check for IPv4 or IPv6 interface:
            let addrFamily = interface.ifa_addr.pointee.sa_family
            if addrFamily == UInt8(AF_INET) || addrFamily == UInt8(AF_INET6) {
    
                // Check interface name:
                let name = String(cString: interface.ifa_name)
                if  name == "en0" {
    
                    // Convert interface address to a human readable string:
                    var addr = interface.ifa_addr.pointee
                    var hostname = [CChar](repeating: 0, count: Int(NI_MAXHOST))
                    getnameinfo(&addr, socklen_t(interface.ifa_addr.pointee.sa_len),
                                &hostname, socklen_t(hostname.count),
                                nil, socklen_t(0), NI_NUMERICHOST)
                    address = String(cString: hostname)
                }
            }
        }
        freeifaddrs(ifaddr)
    
        return address
    }
    
  5. Add this in Bridging-Header file #include<ifaddrs.h>

    In case you don't have this file then you can create it Check this link

6.

func applicationWillEnterForeground(_ application: UIApplication) {
        // Post notification
        NotificationCenter.default.post(name: ReachabilityChangedNotification, object: reachability)
        // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
    }
  1. If you want to remove observer, then:

    reachability.stopNotifier()  
    
    NSNotificationCenter.defaultCenter().removeObserver(self,name: ReachabilityChangedNotification,object: reachability)
    

5

基于上述答案中的一些内容,为 NWInterface.InterfaceType 提供了一个扩展:

import Network

extension NWInterface.InterfaceType {
    var names : [String]? {
        switch self {
        case .wifi: return ["en0"]
        case .wiredEthernet: return ["en2", "en3", "en4"]
        case .cellular: return ["pdp_ip0","pdp_ip1","pdp_ip2","pdp_ip3"]
        default: return nil
        }
    }

    func address(family: Int32) -> String?
    {
        guard let names = names else { return nil }
        var address : String?
        for name in names {
            guard let nameAddress = self.address(family: family, name: name) else { continue }
            address = nameAddress
            break
        }
        return address
    }

    func address(family: Int32, name: String) -> String? {
        var address: String?

        // Get list of all interfaces on the local machine:
        var ifaddr: UnsafeMutablePointer<ifaddrs>?
        guard getifaddrs(&ifaddr) == 0, let firstAddr = ifaddr else { return nil }

        // For each interface ...
        for ifptr in sequence(first: firstAddr, next: { $0.pointee.ifa_next }) {
            let interface = ifptr.pointee

            let addrFamily = interface.ifa_addr.pointee.sa_family
            if addrFamily == UInt8(family)
            {
                // Check interface name:
                if name == String(cString: interface.ifa_name) {
                    // Convert interface address to a human readable string:
                    var hostname = [CChar](repeating: 0, count: Int(NI_MAXHOST))
                    getnameinfo(interface.ifa_addr, socklen_t(interface.ifa_addr.pointee.sa_len),
                                &hostname, socklen_t(hostname.count),
                                nil, socklen_t(0), NI_NUMERICHOST)
                    address = String(cString: hostname)
                }
            }
        }
        freeifaddrs(ifaddr)

        return address
    }

    var ipv4 : String? { self.address(family: AF_INET) }
    var ipv6 : String? { self.address(family: AF_INET6) }
}

用法:

对于移动蜂窝网络的IPv4地址:NWInterface.InterfaceType.cellular.ipv4


1
这应该是被接受的答案。 - Skwiggs
我喜欢这种方法,但你应该知道,它可能无法捕获带有LAN端口的USB连接的集线器的以太网地址,我认为这是因为它们的名称与en#不同。我纠正一下,也许只是我的设备有点奇怪...从终端的ifconfig命令中,我得知它是en5,所以我只需要添加更多的情况。另外,我也会添加en1,因为我不确定为什么它没有被包括进去。 - undefined

5

此类使用NWPathMonitor监视设备的接口。您可以设置一个updatehandler来通知您有关接口状态更改的信息。选择要跟踪的ipv4或ipv6,并检查status.interfaceType == .wifi,以查看您的活动接口是否为wifi。

用法:

let monitor = IPMonitor(ipType: .ipv4) 
monitor.pathUpdateHandler = { status in 
  print("\(status.debugDescription)")
}

类:

import Foundation
import Network

class IPMonitor {
    
    enum InterfaceType: String {
        case cellular = "cellular"
        case wifi = "wifi"
        case wired = "wired"
        case loopback = "loopback"
        case other = "other"
        case notFound = "not found"
    }
    
    enum IPType: String {
        case ipv4 = "IPv4"
        case ipv6 = "ipV6"
        case unknown = "unknown"
    }
    
    struct Status {
        var name = "unknown"
        var interfaceType: InterfaceType = InterfaceType.notFound
        var ip: [String] = []
        var ipType: IPType = IPType.unknown
        
        var debugDescription: String {
            let result = "Interface: \(name)/\(interfaceType.rawValue), \(ipType.rawValue)\(ip.debugDescription)"
            return result
        }
    }
    
    private let monitor = NWPathMonitor()
    private let queue = DispatchQueue(label: "ip_monitor_queue")
    
    final var pathUpdateHandler: ((Status) -> Void)?
    
    init(ipType: IPType) {
        monitor.pathUpdateHandler = { path in
            let name = self.getInterfaceName(path: path)
            let type = self.getInterfaceType(path: path)
            let ip = self.getIPAddresses(interfaceName: name, ipType: ipType)
            let status = Status(name: name, interfaceType: type, ip: ip, ipType: ipType)
            //print("\(status)")
            self.pathUpdateHandler?(status)
        }
        monitor.start(queue: queue)
    }
    
    private func getInterfaceName(path: NWPath) -> String {
        if let name = path.availableInterfaces.first?.name {
            return name
        }
        return "unknown"
    }
    
    private func getInterfaceType(path: NWPath) -> InterfaceType {
        if let type = path.availableInterfaces.first?.type {
            switch type {
            case NWInterface.InterfaceType.cellular:
                return InterfaceType.cellular
            case NWInterface.InterfaceType.wifi:
                return InterfaceType.wifi
            case NWInterface.InterfaceType.wiredEthernet:
                return InterfaceType.wired
            case NWInterface.InterfaceType.loopback:
                return InterfaceType.loopback
            default:
                return InterfaceType.other
            }
        }
        
        return InterfaceType.notFound
    }
    
    private func getIPAddresses(interfaceName: String, ipType: IPType)-> [String]{
        var addresses: [String] = []
        var ifaddr: UnsafeMutablePointer<ifaddrs>? = nil
        if getifaddrs(&ifaddr) == 0 {
            var ptr = ifaddr
            while ptr != nil {
                defer { ptr = ptr?.pointee.ifa_next }
                let interface = ptr?.pointee
                let addrFamily = interface?.ifa_addr.pointee.sa_family
                if (addrFamily == UInt8(AF_INET) && ipType == .ipv4)
                    || (addrFamily == UInt8(AF_INET6) && ipType == .ipv6) {
                    let name = String(cString: (interface?.ifa_name)!)
                    if name == interfaceName {
                        var hostname = [CChar](repeating: 0, count: Int(NI_MAXHOST))
                        getnameinfo(interface?.ifa_addr, socklen_t((interface?.ifa_addr.pointee.sa_len)!), &hostname, socklen_t(hostname.count), nil, socklen_t(0), NI_NUMERICHOST)
                        addresses.append(String(cString: hostname))
                    }
                }
            }
        }
        freeifaddrs(ifaddr)
        
        return addresses
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接