How to get iOS device's WiFi IP address?
Asked Answered
C

19

99

I need to get the IP address of an iOS device in Swift. This is not a duplicate of other questions about this! I need to get only WiFi IP address. If there is no WiFi IP address, I need to handle it. There are a few questions about it on Stack Overflow, but there are only functions that return IP addresses. For example (from 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 Internet (I think) and WiFi address I need. Is there any other way to get ONLY WiFi IP address?

Crossexamine answered 10/6, 2015 at 6:16 Comment(0)
A
148

According to several SO threads (e.g. 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".

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. 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):

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

Do NOT forget to add #include <ifaddrs.h> in your bridging header

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

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.

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

&

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

Adornment answered 10/6, 2015 at 10:52 Comment(12)
@MartinR i created a bridging header file and then included #include <ifaddrs.h> in that file , and pasted your swift3 code in my viewcontroller but there are errors of getifaddrs() , ifaddrs , freeifaddrs , how to solve it ?Grigson
@Tigerdeveloper: On a Mac: https://mcmap.net/q/218348/-manage-ifaddrs-to-return-mac-addresses-as-well-in-swift. On an iOS device it is not possible.Adornment
@MartinR : This code does not gives IP address if Mobile Data is connected.Kocher
@JayprakashDubey: If you copy that code to your blog, don't forget to add a source reference for proper attribution :)Adornment
@MartinR I'm getting nil when running this code. Do you know why?Foyer
@Ramakrishna: Try this https://mcmap.net/q/218346/-how-to-get-ip-address-in-swift, it returns all interface addresses.Adornment
@MartinR I am getting address ok, but one of the interfaces returns address in this format - fe80::10ec:6bd9:1d19:ac29%en0. I am curious what is this used for, what this address means?Herrmann
@MegaManX: That is an IPv6 address. If you want to ignore that then remove the addrFamily == UInt8(AF_INET6) check.Adornment
@MegaManX: fe80::10ec:6bd9:1d19:ac29%en0 is a "scoped literal IPv6 address“Adornment
@HirenRathod: In Xcode 10 it seems to be sufficient to add import Darwin to the Swift file.Adornment
@HirenRathod: I don't have Xcode 9.2 anymore, but I have double-checked it with Xcode 10.1 and an iOS 12 iPhone. It works for me. Is WiFi enabled on your device? This code specifically checks for the WiFi ("en0") device.Adornment
I use the github.com/Shmoopi/iOS-System-Services repo to achieve the task. Additionally you can add an observer to monitor the changes in the active connections.Grayling
S
49

To get IPAddress for wifi , wired, and cellular - 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

#include<ifaddrs.h>
Stricker answered 28/5, 2019 at 12:12 Comment(3)
I didn't have to include that inside my bridging headerDarden
Is there a way to filter out IPv6 and only get IPv4 addresses, beside a regex?Saraann
Hi @Saraann I will check this, and update you for the same.Stricker
U
21

Create bridging header and Include #include <ifaddrs.h> in it.

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

IP :( "10.0.0.94" )

from this array you can access it where ever u want. Hope it helps

Unsphere answered 10/6, 2015 at 6:22 Comment(3)
It returns array f addresses, how to get wifi address from there?Crossexamine
u can easily access from array what u want..isn't it?.Unsphere
"then write this method ..." – That is what OP wrote in the question, your code is an exact copy (and also identical to the code posted here: https://mcmap.net/q/218346/-how-to-get-ip-address-in-swift).Adornment
D
20

Swift 4.2 UIDevice extension that avoids force unwraps and supports cellular and wired ip addresses:

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()
Daisy answered 28/11, 2018 at 22:6 Comment(0)
S
16

Swift 4 - Get device's IP Address:

Add #include<ifaddrs.h> in your bridging header.

This is the framework needed to get IP address.

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
}
Sandman answered 13/10, 2017 at 7:24 Comment(2)
Getting a "Non-optional expression of type 'String' used in a check for optionals" warning.Favata
when I activate my personal hotspot, my address === " " (i.e empty) but when my device is activate to external hotspot is working ok. I am working with iOS 12.1.4Vuong
T
8

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

Heres their Swift example:

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)
}
Tribune answered 16/10, 2019 at 15:32 Comment(0)
K
6

You can fetch IP address using the code below:

Note : I've used reachability so that it captures new IP address in case WiFi is changed to another.

  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)
    
Kocher answered 9/3, 2017 at 7:42 Comment(0)
U
6

Swift 5 Cleanup

I updated an answer above to eliminate any force unwrapping and some SwiftLint cleanup.

 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
    }
Underestimate answered 13/3, 2020 at 14:40 Comment(1)
This favors IPV6 and does not always return IPV4 addressesBlaine
S
6

An extension for NWInterface.InterfaceType based on some of the above answers:

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

Semimonthly answered 1/7, 2020 at 18:2 Comment(1)
I like this approach, but you should be aware that it probably won't catch Ethernet addresses for USB-attached hubs with a LAN port, I think due to a different name than en# -> I stand corrected, maybe it's just mine that was odd... from ifconfig in Terminal I gathered that it's en5, so I just need to add more cases. Also, I'll add en1 too, as I'm not sure why is not included.Saraann
B
5

This class monitors the device interfaces with 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

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
    }
}
Bagpipe answered 8/12, 2020 at 16:14 Comment(0)
D
4

All the answers here gives only ip address for wifi and not wired or cellular. Following snippet can be used for wifi/wired/cellular case:

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
}
Deucalion answered 19/11, 2018 at 6:46 Comment(1)
Note that the question specifically asks "I need to get only WiFi IP address ..."Adornment
C
3
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
}
Columbic answered 14/6, 2017 at 12:14 Comment(0)
S
3

SUPPORT FOR IPV4 & IPV6

Make it an extension of UIDevice and call using 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
            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
}
Soiree answered 3/7, 2020 at 16:16 Comment(0)
B
2

If you want only IPv4 response as output just modify the solution by 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")
}
Basseterre answered 30/11, 2018 at 11:12 Comment(1)
when I activate my personal hotspot, my address === " " (i.e empty) but when my device is activate to external hotspot is working ok. I am working with iOS 12.1.4.Vuong
A
1
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
Ala answered 5/8, 2020 at 8:35 Comment(0)
P
0

For Swift on Mac - Swift 4 : This way you can also find out the ip from the Wifi (not only Ethernet)

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
}
Psychognosis answered 19/3, 2019 at 10:4 Comment(0)
A
0

Given you already have the socket's file descriptor this is a solution for 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)
Ample answered 9/11, 2020 at 19:6 Comment(0)
H
0

If you're just trying to identify where requests are coming from, you can get the public facing ip address from an external service. It will give you something like 120.20.62.149

This is no different than opening your web browser to checkip.amazonaws.com or whatismyip.com. Multiple devices on your network will share this address, so it's not helpful if you're trying to ping your device from an external location.

@MainActor func getIpAddress() async -> String? {
  do {
    guard let url = URL(string: "https://checkip.amazonaws.com") else {
      return nil
    }

    let (data, _) = try await URLSession.shared.data(from: url)
    
    return String(
      data: data, 
      encoding: .utf8
    )?.trimmingCharacters(in: .whitespacesAndNewlines)
  } catch {
    return nil
  }
}

Usage

Task {
  let ip = await getIpAddress() // "120.20.62.149"
}
Hydraulics answered 30/4 at 16:6 Comment(0)
C
-1
enum Network: String {
case wifi = "en0"
case cellular = "pdp_ip0"
case hotspot = "bridge100"
}

if use hotspot get ip

Cindycine answered 10/1, 2023 at 3:2 Comment(2)
As it’s currently written, your answer is unclear. Please edit to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers in the help center.Asis
This answer does not adress the question on how to obtain the ip. Recommend deletion.Diopside

© 2022 - 2024 — McMap. All rights reserved.