【问题标题】:Swift - Get device's WIFI IP AddressSwift - 获取设备的 WIFI IP 地址
【发布时间】:2023-03-03 20:01:01
【问题描述】:

我需要在 Swift 中获取 iOS 设备的 IP 地址。这与其他有关此问题的问题不重复!如果没有 wifi IP 地址,我只需要获取 WiFi IP 地址 - 我需要处理它。 Stack Overflow 上有几个关于它的问题,但只有返回 ip 地址的函数。例如(来自How to get Ip address in swift):

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
}

在这里我得到 2 个值 - 来自移动互联网的地址(我认为)和我需要的 WiFi 地址。有没有其他方法可以只获取 WiFi IP 地址?

【问题讨论】:

    标签: ios swift network-programming


    【解决方案1】:

    创建桥接头并在其中包含#include &lt;ifaddrs.h&gt;

    那就写这个方法

    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() 这样在我的 viewController 中调用这个方法时,我会在我的控制台中得到完美的响应,比如

    IP :( “10.0.0.94” )

    从这个数组你可以在任何你想要的地方访问它。 希望对你有帮助

    【讨论】:

    • 它返回数组f地址,如何从那里获取wifi地址?
    • 你可以轻松地从数组中访问你想要的......不是吗?
    • "then write this method ..." –这就是OP在问题中所写的,您的代码是精确副本(也与此处发布的代码相同: stackoverflow.com/a/25627545/1187415)。
    • 嗨。我在尝试 UInt8(...) 方法时崩溃了,有人可以帮忙吗? stackoverflow.com/questions/55491986/…
    【解决方案2】:

    根据几个 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 地址列表。它可以很容易地修改为只返回 IP 地址 “en0”接口,实际上这就是我最初所拥有的 在那个线程上回答(这只是对 回复how to get ip address of iphone programmatically):

    // 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 更新:除了采用代码 many changes in Swift 3, 遍历所有接口现在可以使用新的泛化 sequence()函数:

    不要忘记在您的桥接头中添加#include &lt;ifaddrs.h&gt;

    // 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。

    guard let wifiIp = getAddress(for: .wifi) else { return }

    &

    guard let cellularIp = getAddress(for: .cellular) else { return }

    【讨论】:

    • @Martin R,C 风格的 for 语句已弃用,将在 Swift 的未来版本中删除。你能在你的答案中解决它吗?
    • @MartinR 非常感谢,伙计。 :)
    • @MartinR 我创建了一个桥接头文件,然后在该文件中包含 #include ,并将您的 swift3 代码粘贴到我的视图控制器中,但是 getifaddrs() 、 ifaddrs 、 freeifaddrs 有错误,怎么解决?
    • @JayprakashDubey:此代码专用于 WiFi(“en0”)地址。请参阅 stackoverflow.com/a/25627545/1187415 获取检索所有正在运行的接口的 IP 地址的代码(并且在我的测试中与蜂窝网络一起使用)。
    • @MegaManX: fe80::10ec:6bd9:1d19:ac29%en0 是"scoped literal IPv6 address“
    【解决方案3】:

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

    注意:我使用了可达性,以便在 WiFi 更改为另一个时捕获新的 IP 地址。

    1. Podfile 文件中

      pod 'ReachabilitySwift' 然后install pod

    2. AppDelegate.swift 文件中import ReachabilitySwift

      注意:如果提示找不到 ReachabilitySwift 模块的错误,则只需复制并粘贴即可。有效!

    3. didFinishLaunchingOptions函数

      NotificationCenter.default.addObserver(self, selector: #selector(self.reachabilityChanged), name: ReachabilityChangedNotification, object: reachability)
      
      do{
          try reachability.startNotifier()
      }
      catch {
          print("could not start reachability notifier")
      } 
      
    4. 然后将下面的代码复制粘贴到AppDelegate文件中

      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. 将此添加到桥接头文件#include&lt;ifaddrs.h&gt;

      如果你没有这个文件,那么你可以创建它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. 如果你想移除观察者,那么:

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

    【讨论】:

      【解决方案4】:
      func getIPAddress() -> String {
          var address: String = "error"
      
          var interfaces: ifaddrs? = nil
      
          var temp_addr: ifaddrs? = nil
          var success: Int = 0
          // retrieve the current interfaces - returns 0 on success
          success = getifaddrs(interfaces)
          if success == 0 {
              // Loop through linked list of interfaces
              temp_addr = interfaces
              while temp_addr != nil {
                  if temp_addr?.ifa_addr?.sa_family == AF_INET {
                      // Check if interface is en0 which is the wifi connection on the iPhone
                      if (String(utf8String: temp_addr?.ifa_name) == "en0") {
                          // Get NSString from C String
                          address = String(utf8String: inet_ntoa((temp_addr?.ifa_addr as? sockaddr_in)?.sin_addr))
                      }
                  }
                  temp_addr = temp_addr?.ifa_next
              }
          }
              // Free memory
          freeifaddrs(interfaces)
          return address
      }
      

      【讨论】:

        【解决方案5】:

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

        在您的桥接头中添加#include&lt;ifaddrs.h&gt;

        这是获取 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
        }
        

        【讨论】:

        • 获取“用于检查可选项的“字符串”类型的非可选表达式”警告。
        • 当我激活我的个人热点时,我的地址 === " "(即为空)但是当我的设备被激活到外部热点时工作正常。我正在使用 iOS 12.1.4
        • 嗨。我在尝试 UInt8(...) 方法时崩溃了,有人可以帮忙吗? stackoverflow.com/questions/55491986/…
        【解决方案6】:

        这里的所有答案都只提供 wifi 的 IP 地址,而不是有线或蜂窝。以下 sn-p 可用于 wifi/有线/蜂窝案例:

        func getIPAddressForCellOrWireless()-> String? {
        
            let WIFI_IF : [String] = ["en0"]
            let KNOWN_WIRED_IFS : [String] = ["en2", "en3", "en4"]
            let KNOWN_CELL_IFS : [String] = ["pdp_ip0","pdp_ip1","pdp_ip2","pdp_ip3"]
        
            var addresses : [String : String] = ["wireless":"",
                                                 "wired":"",
                                                 "cell":""]
        
            var address: String?
            var ifaddr: UnsafeMutablePointer<ifaddrs>? = nil
            if getifaddrs(&ifaddr) == 0 {
        
                var ptr = ifaddr
                while ptr != nil {
                    defer { ptr = ptr?.pointee.ifa_next } // memory has been renamed to pointee in swift 3 so changed memory to pointee
        
                    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)!), (WIFI_IF.contains(name) || KNOWN_WIRED_IFS.contains(name) || KNOWN_CELL_IFS.contains(name)) {
        
                            // String.fromCString() is deprecated in Swift 3. So use the following code inorder to get the exact IP Address.
                            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)
                            if WIFI_IF.contains(name){
                                addresses["wireless"] =  address
                            }else if KNOWN_WIRED_IFS.contains(name){
                                addresses["wired"] =  address
                            }else if KNOWN_CELL_IFS.contains(name){
                                addresses["cell"] =  address
                            }
                        }
        
                    }
                }
            }
            freeifaddrs(ifaddr)
        
            var ipAddressString : String?
            let wirelessString = addresses["wireless"]
            let wiredString = addresses["wired"]
            let cellString = addresses["cell"]
            if let wirelessString = wirelessString, wirelessString.count > 0{
                ipAddressString = wirelessString
            }else if let wiredString = wiredString, wiredString.count > 0{
                ipAddressString = wiredString
            }else if let cellString = cellString, cellString.count > 0{
                ipAddressString = cellString
            }
            return ipAddressString
        }
        

        【讨论】:

        • 请注意,该问题专门询问“我只需要获取 WiFi IP 地址...”
        【解决方案7】:

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

        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 任何解决方案????
        • 这是一个 v6 IP @SreekanthG 并且是预期的。
        • 我在我的设备上获取这种地址 2409:4043:986:e121:6449:eae9:c78f:1042。对吗???
        【解决方案8】:

        如果您只想将 IPv4 响应作为输出,只需修改 Martin R 的解决方案。

         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) {  // **ipv6 committed
                if addrFamily == UInt8(AF_INET){
        
                    // 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
        }
        

        用法:

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

        【讨论】:

        • 当我激活我的个人热点时,我的address === " "(即为空)但是当我的设备被激活到外部热点时工作正常。我正在使用 iOS 12.1.4。
        • 不确定这个问题,我有 4 个设备 ios 12.1,1 个设备 12.2,然后 2 个设备出错 -> stackoverflow.com/questions/55491986/…
        【解决方案9】:

        对于 Mac 上的 Swift - Swift 4: 这样您还可以从 Wifi 中找出 ip(不仅是以太网)

        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)
                    } else if name == "en1" {
                        // 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(1), NI_NUMERICHOST)
                        address = String(cString: hostname)
                    }
                }
            }
            freeifaddrs(ifaddr)
        
            return address
        }
        

        【讨论】:

          【解决方案10】:

          获取 wifi、有线和蜂窝网络的 IPAddress - 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>
          

          【讨论】:

          • 没有错误,没有警告,完美运行。感谢您在 cmets 中提供更多信息。
          • 欢迎......快乐编码
          • 在模拟器中试一次,我想我在真机上测试过。
          • 在设备上我得到这种地址 2409:4043:986:e121:6449:eae9:c78f:1042 是否正确???
          • 我不必将它包含在我的桥接头中
          【解决方案11】:

          另一种方法有点不同的解决方案是使用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)
          }
          

          【讨论】:

            【解决方案12】:

            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 地址
            【解决方案13】:

            基于上述部分答案的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

            【讨论】:

              【解决方案14】:

              支持 IPV4 和 IPV6

              使其成为 UIDevice 的扩展并使用 UIDevice.current.getIPAdress() 调用

              private struct Interfaces {
                  // INTERFACCIE SUPPORT
                  static let wifi = ["en0"]
                  static let cellular = ["pdp_ip0","pdp_ip1","pdp_ip2","pdp_ip3"]
                  static let supported = wifi + cellular
              }
              
              
              func getIPAdress() -> (String?,String?)? {
                  var ip4Adress: String?
                  var ip6Adress: String?
                  var hasAdress: UnsafeMutablePointer<ifaddrs>?
              
              
                  if getifaddrs(&hasAdress) == 0 {
                      var pointer = hasAdress
              
                      while pointer != nil {
                          defer { pointer = pointer?.pointee.ifa_next}
              
                          guard let interface = pointer?.pointee else {continue}
              
                          // SEARCH FOR IPV4 OR IPV6 IN THE INTERFACE OF THE NODE
                          // HERE I'M ALREADY LOOSING MY MIND
                          // PRIORITY FOR IPV4 THAN IPV6
                          if  interface.ifa_addr.pointee.sa_family == UInt8(AF_INET) {
                              guard let ip4 = processInterface(interface: interface) else {
                                  continue
                              }
                              ip4Adress = ip4
                          }
              
                          if interface.ifa_addr.pointee.sa_family == UInt8(AF_INET6) {
                              guard let ip6 = processInterface(interface: interface) else {
                                  continue
                              }
                              ip6Adress = ip6
                          }
                      }
                      freeifaddrs(hasAdress)
                  }
                  return (ip4Adress, ip6Adress)
              }
              
              
              
              func processInterface(interface: ifaddrs) -> String? {
              
                  var ipAdress: String = ""
                  guard
                      let interfaceName = interface.ifa_name else {return nil}
                                     guard
                                         let interfaceNameFormatted = String(cString: interfaceName, encoding: .utf8) else {return nil}
                  guard Interfaces.supported.contains(interfaceNameFormatted) else {return nil}
              
                                     var hostname = [CChar](repeating: 0, count: Int(NI_MAXHOST))
              
                                     print(interfaceNameFormatted)
              
                                     // CONVERT THE SOCKET ADRESS TO A CORRESPONDING HOST AND SERVICE
                                     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 formattedIpAdress = String(cString: hostname, encoding: .utf8) else {return nil}
                                     if !formattedIpAdress.isEmpty {
                                         ipAdress = formattedIpAdress
                                     }
                  return ipAdress
              }
              

              【讨论】:

                【解决方案15】:
                enum Network: String {
                    case wifi = "en0"
                    case cellular = "pdp_ip0"
                //    case en1 = "en1"
                //    case lo = "lo0"
                }
                
                // get ipv4 or ipv6 address
                extension UIDevice {
                    
                    func address(family: Int32, for network: Network) -> 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:
                                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
                    }
                    
                    func ipv4(for network: Network) -> String? {
                        self.address(family: AF_INET, for: network)
                    }
                    
                    func ipv6(for network: Network) -> String? {
                        self.address(family: AF_INET6, for: network)
                    }
                    
                    // get all addresses
                    func getIFAddresses() -> [String] {
                        var addresses = [String]()
                        
                        // Get list of all interfaces on the local machine:
                        var ifaddr : UnsafeMutablePointer<ifaddrs>?
                        guard getifaddrs(&ifaddr) == 0 else { return [] }
                        guard let firstAddr = ifaddr else { return [] }
                        
                        // For each interface ...
                        for ptr in sequence(first: firstAddr, next: { $0.pointee.ifa_next }) {
                            let flags = Int32(ptr.pointee.ifa_flags)
                            let addr = ptr.pointee.ifa_addr.pointee
                            
                            // 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](repeating: 0, count: Int(NI_MAXHOST))
                                    if (getnameinfo(ptr.pointee.ifa_addr, socklen_t(addr.sa_len), &hostname, socklen_t(hostname.count),
                                                    nil, socklen_t(0), NI_NUMERICHOST) == 0) {
                                        let address = String(cString: hostname)
                                        addresses.append(address)
                                    }
                                }
                            }
                        }
                        
                        freeifaddrs(ifaddr)
                        
                        return addresses
                    }
                }
                

                如何使用

                // for wifi
                  let wifi = UIDevice.current.ipv4(for: .wifi) # ipv4
                  let wifi6 = UIDevice.current.ipv6(for: .wifi) # ipv6
                
                // for cellular
                  let cellular = UIDevice.current.ipv4(for: .cellular) # ipv4
                  let cellular6 = UIDevice.current.ipv6(for: .cellular) # ipv6
                

                【讨论】:

                  【解决方案16】:

                  鉴于您已经拥有套接字的文件描述符,这是 Swift 5.2 的解决方案。

                  // Depending on your case get the socket's file descriptor
                  // the way you want
                  let socketFd = foo()
                  
                  // Get the remote address for that file descriptor
                  var addr: sockaddr_storage = sockaddr_storage()
                  var addr_len: socklen_t = socklen_t(MemoryLayout.size(ofValue: addr))
                  
                  var hostBuffer = [CChar](repeating: 0, count: Int(NI_MAXHOST))
                  
                  // Make local copy to avoid: "Overlapping accesses to 'addr', 
                  // but modification requires exclusive access; consider copying
                  // to a local variable"
                  let addrLen = addr.ss_len
                  
                  withUnsafeMutablePointer(to: &addr) {
                      $0.withMemoryRebound(to: sockaddr.self, capacity: 1) {
                          if getpeername(socketFd, $0, &addr_len) != 0 { return }
                          
                          getnameinfo($0, socklen_t(addrLen), &hostBuffer, socklen_t(hostBuffer.count), nil, 0, NI_NUMERICHOST)
                      }
                  }
                  
                  let connectedHost = String(cString: hostBuffer, encoding: .utf8)
                  

                  【讨论】:

                    【解决方案17】:

                    该类使用 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
                        }
                    }
                    

                    【讨论】:

                      猜你喜欢
                      • 2013-12-14
                      • 2020-09-14
                      • 1970-01-01
                      • 1970-01-01
                      • 2013-06-29
                      • 1970-01-01
                      • 2019-02-09
                      • 1970-01-01
                      • 2013-05-19
                      相关资源
                      最近更新 更多