简体   繁体   English

Swift - 获取设备的 WIFI IP 地址

[英]Swift - Get device's WIFI IP Address

I need to get IP Address of iOS device in Swift. This is not a duplicate of other questions about this, I need to get only WiFi IP address.我需要在 Swift 中获取 IP iOS 设备的地址。这不是关于此的其他问题的重复,我只需要获取 WiFi IP 地址。 if there is no wifi ip address - I need to handle it, There are a few questions about it on Stack Overflow.如果没有 wifi ip 地址 - 我需要处理它,Stack Overflow 上有几个关于它的问题。 but there are only functions that return ip addresses.但只有返回 ip 地址的函数。 For example (from How to get Ip address in swift ):例如(来自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
}

Here I get 2 values - address from mobile inte.net(I think) and WiFi address I need.在这里我得到 2 个值 - 来自移动互联网的地址(我认为)和我需要的 WiFi 地址。 Is there any other way to get ONLY WiFi IP Address?有没有其他方法可以只获取 WiFi IP 地址?

According to several SO threads (eg What exactly means iOS networking interface name? what's pdp_ip ? what's ap? ), the WiFi interface on an iOS device always has then name "en0".根据几个 SO 线程(例如, iOS 网络接口名称究竟是什么意思?pdp_ip 是什么?ap 是什么? ),iOS 设备上的 WiFi 接口始终具有名称“en0”。

Your code (which seems to be what I answered at How to get Ip address in swift :) retrieves a list of the IP addresses of all running network interfaces.您的代码(这似乎是我在How to get Ip address in swift 中回答的内容:)检索所有正在运行的网络接口的 IP 地址列表。 It can easily be modified to return only the IP address of the "en0" interface, and actually that is what I originally had answered at that thread (and this is just a Swift translation of the answer to how to get ip address of iphone programmatically ):它可以很容易地修改为仅返回“en0”接口的 IP 地址,实际上这就是我最初在该线程上回答的内容(这只是对如何以编程方式获取 iphone 的 ip 地址的答案的 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
}

Usage:用法:

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

Update for Swift 3: In addition to adopting the code to the many changes in Swift 3 , iterating over all interfaces can now use the new generalized sequence() function: Swift 3 的更新:除了采用Swift 3 中许多更改的代码之外,迭代所有接口现在可以使用新的通用sequence()函数:

Do NOT forget to add #include <ifaddrs.h> in your bridging header不要忘了添加#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
}

For those of you who came looking for more than the WIFI IP you could modify this code a little对于那些来寻找不仅仅是 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"
}

Then we have access to the cellular IP as well.然后我们也可以访问蜂窝 IP。

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

& &

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

To get IPAddress for wifi , wired, and cellular - swift 5获取 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 ?? ""
}

How to use如何使用

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

Note : Add this below in your project's Bridging-Header file注意:在您项目的 Bridging-Header 文件中添加以下内容

#include<ifaddrs.h>

Create bridging header and Include #include <ifaddrs.h> in it.创建桥接头并在其中包含#include <ifaddrs.h>

then write this method然后写这个方法

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
}

when I call this method in my viewController like var arr : NSArray = self.getIFAddresses() I get perfect response in my console like当我像var arr : NSArray = self.getIFAddresses()一样在 viewController 中调用此方法时var arr : NSArray = self.getIFAddresses()我在控制台中得到了完美的响应

IP :( "10.0.0.94" ) IP :(“10.0.0.94”)

from this array you can access it where ever u want.从这个数组你可以在任何你想要的地方访问它。 Hope it helps希望能帮助到你

Swift 4 - Get device's IP Address: Swift 4 - 获取设备的 IP 地址:

Add #include<ifaddrs.h> in your bridging header.在桥接头中添加#include<ifaddrs.h>

This is the framework needed to get IP address.这是获取 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
}

Swift 4.2 UIDevice extension that avoids force unwraps and supports cellular and wired ip addresses: 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
    }

}

Usage:用法:

UIDevice.current.ipAddress()

You can fetch IP address using the code below:您可以使用以下代码获取 IP 地址:

Note : I've used reachability so that it captures new IP address in case WiFi is changed to another.注意:我使用了可达性,以便在 WiFi 更改为另一个时它会捕获新的 IP 地址。

  1. In Podfile filePodfile文件中

    pod 'ReachabilitySwift' and then install pod pod 'ReachabilitySwift'然后install pod

  2. In AppDelegate.swift file import ReachabilitySwiftAppDelegate.swift文件中import ReachabilitySwift

    Note : If it prompts an error that Could not find ReachabilitySwift module then simply copy and paste this.注意:如果提示无法找到 ReachabilitySwift 模块的错误,则只需复制并粘贴即可。 It works!有用!

  3. didFinishLaunchingOptions function 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. Then copy paste below code in AppDelegate file然后将下面的代码复制粘贴到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. Add this in Bridging-Header file #include<ifaddrs.h>在 Bridging-Header 文件中添加这个#include<ifaddrs.h>

    In case you don't have this file then you can create it Check this link如果你没有这个文件,那么你可以创建它检查这个链接

6. 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)
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
}

All the answers here gives only ip address for wifi and not wired or cellular.这里的所有答案仅提供 wifi 的 ip 地址,而不是有线或蜂窝网络。 Following snippet can be used for wifi/wired/cellular case:以下代码段可用于 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
}

Swift 5 Cleanup斯威夫特 5 清理

I updated an answer above to eliminate any force unwrapping and some SwiftLint cleanup.我更新了上面的答案以消除任何强制解包和一些 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
    }

Another solution thats a bit of a different approach is using Ipify , which is a free lightweight service that you can ping to get your IP另一种有点不同方法的解决方案是使用Ipify ,这是一个免费的轻量级服务,您可以 ping 以获取您的 IP

Heres their Swift example:这是他们的 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)
}

If you want only IPv4 response as output just modify the solution by Martin R.如果您只想要 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
}

Usage:用法:

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

SUPPORT FOR IPV4 & IPV6支持 IPV4 和 IPV6

Make it an extension of UIDevice and call using UIDevice.current.getIPAdress()使其成为 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
}

This class monitors the device interfaces with NWPathMonitor.此类使用 NWPathMonitor 监视设备接口。 You can set an updatehandler that informs you about interface state changes.您可以设置一个更新处理程序,通知您有关接口状态更改的信息。 Choose if you want to track ipv4 or ipv6 and check for status.interfaceType == .wifi to see, if your active interface is wifi选择是否要跟踪 ipv4 或 ipv6 并检查 status.interfaceType == .wifi 以查看您的活动接口是否为 wifi

Usage:用法:

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

Class:班级:

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
    }
}

For Swift on Mac - Swift 4 : This way you can also find out the ip from the Wifi (not only Ethernet)对于 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
}

An extension for NWInterface.InterfaceType based on some of the above answers:基于上述一些答案的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) }
}

Usage:用法:

For ipv4 of cellular: NWInterface.InterfaceType.cellular.ipv4对于蜂窝的 ipv4: NWInterface.InterfaceType.cellular.ipv4

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
    }
}

How to use如何使用

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

Given you already have the socket's file descriptor this is a solution for Swift 5.2.鉴于您已经拥有套接字的文件描述符,这是 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)
enum Network: String {
case wifi = "en0"
case cellular = "pdp_ip0"
case hotspot = "bridge100"
}

if use hotspot get ip如果使用热点获取 ip

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM