Swift - 获取设备的 WIFI IP 地址
Posted
技术标签:
【中文标题】Swift - 获取设备的 WIFI IP 地址【英文标题】:Swift - Get device's WIFI IP Address 【发布时间】:2015-08-25 05:47:36 【问题描述】:我需要在 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 地址?
【问题讨论】:
【参考方案1】:创建桥接头并在其中包含#include <ifaddrs.h>
。
那就写这个方法
func getIFAddresses() -> [String]
var addresses = [String]()
// Get list of all interfaces on the local machine:
var ifaddr : UnsafeMutablePointer<ifaddrs> = nil
if getifaddrs(&ifaddr) == 0
// For each interface ...
for (var ptr = ifaddr; ptr != nil; ptr = ptr.memory.ifa_next)
let flags = Int32(ptr.memory.ifa_flags)
var addr = ptr.memory.ifa_addr.memory
// Check for running IPv4, IPv6 interfaces. Skip the loopback interface.
if (flags & (IFF_UP|IFF_RUNNING|IFF_LOOPBACK)) == (IFF_UP|IFF_RUNNING)
if addr.sa_family == UInt8(AF_INET) || addr.sa_family == UInt8(AF_INET6)
// Convert interface address to a human readable string:
var hostname = [CChar](count: Int(NI_MAXHOST), repeatedValue: 0)
if (getnameinfo(&addr, socklen_t(addr.sa_len), &hostname, socklen_t(hostname.count),
nil, socklen_t(0), NI_NUMERICHOST) == 0)
if let address = String.fromCString(hostname)
addresses.append(address)
freeifaddrs(ifaddr)
return addresses
当我像 var arr : NSArray = self.getIFAddresses()
这样在我的 viewController 中调用这个方法时,我会在我的控制台中得到完美的响应,比如
IP :( “10.0.0.94” )
从这个数组你可以在任何你想要的地方访问它。 希望对你有帮助
【讨论】:
它返回数组f地址,如何从那里获取wifi地址? 你可以轻松地从数组中访问你想要的......不是吗? "then write this method ..." –这就是OP在问题中所写的,您的代码是精确副本(也与此处发布的代码相同: ***.com/a/25627545/1187415)。 嗨。我在尝试 UInt8(...) 方法时崩溃了,有人可以帮忙吗? ***.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 <ifaddrs.h>
// Return IP address of WiFi interface (en0) as a String, or `nil`
func getWiFiAddress() -> String?
var address : String?
// Get list of all interfaces on the local machine:
var ifaddr : UnsafeMutablePointer<ifaddrs>?
guard getifaddrs(&ifaddr) == 0 else return nil
guard let firstAddr = ifaddr else return nil
// For each interface ...
for ifptr in sequence(first: firstAddr, next: $0.pointee.ifa_next )
let interface = ifptr.pointee
// Check for IPv4 or IPv6 interface:
let addrFamily = interface.ifa_addr.pointee.sa_family
if addrFamily == UInt8(AF_INET) || addrFamily == UInt8(AF_INET6)
// Check interface name:
let name = String(cString: interface.ifa_name)
if name == "en0"
// Convert interface address to a human readable string:
var hostname = [CChar](repeating: 0, count: Int(NI_MAXHOST))
getnameinfo(interface.ifa_addr, socklen_t(interface.ifa_addr.pointee.sa_len),
&hostname, socklen_t(hostname.count),
nil, socklen_t(0), NI_NUMERICHOST)
address = String(cString: hostname)
freeifaddrs(ifaddr)
return address
对于那些来寻找比 WIFI IP 更多的人,您可以稍微修改此代码
func getAddress(for network: Network) -> String?
var address: String?
// Get list of all interfaces on the local machine:
var ifaddr: UnsafeMutablePointer<ifaddrs>?
guard getifaddrs(&ifaddr) == 0 else return nil
guard let firstAddr = ifaddr else return nil
// For each interface ...
for ifptr in sequence(first: firstAddr, next: $0.pointee.ifa_next )
let interface = ifptr.pointee
// Check for IPv4 or IPv6 interface:
let addrFamily = interface.ifa_addr.pointee.sa_family
if addrFamily == UInt8(AF_INET) || addrFamily == UInt8(AF_INET6)
// Check interface name:
let name = String(cString: interface.ifa_name)
if name == network.rawValue
// Convert interface address to a human readable string:
var hostname = [CChar](repeating: 0, count: Int(NI_MAXHOST))
getnameinfo(interface.ifa_addr, socklen_t(interface.ifa_addr.pointee.sa_len),
&hostname, socklen_t(hostname.count),
nil, socklen_t(0), NI_NUMERICHOST)
address = String(cString: hostname)
freeifaddrs(ifaddr)
return address
enum Network: String
case wifi = "en0"
case cellular = "pdp_ip0"
//... case ipv4 = "ipv4"
//... case ipv6 = "ipv6"
那么我们也可以访问蜂窝 IP。
guard let wifiIp = getAddress(for: .wifi) else return
&
guard let cellularIp = getAddress(for: .cellular) else return
【讨论】:
@Martin R,C 风格的 for 语句已弃用,将在 Swift 的未来版本中删除。你能在你的答案中解决它吗? @MartinR 非常感谢,伙计。 :) @MartinR 我创建了一个桥接头文件,然后在该文件中包含 #include您可以使用以下代码获取 IP 地址:
注意:我使用了可达性,以便在 WiFi 更改为另一个时捕获新的 IP 地址。
在Podfile
文件中
pod 'ReachabilitySwift'
然后install pod
在AppDelegate.swift
文件中import ReachabilitySwift
注意:如果提示找不到 ReachabilitySwift 模块的错误,则只需复制并粘贴即可。有效!
didFinishLaunchingOptions
函数
NotificationCenter.default.addObserver(self, selector: #selector(self.reachabilityChanged), name: ReachabilityChangedNotification, object: reachability)
do
try reachability.startNotifier()
catch
print("could not start reachability notifier")
然后将下面的代码复制粘贴到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
将此添加到桥接头文件#include<ifaddrs.h>
如果你没有这个文件,那么你可以创建它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.
如果你想移除观察者,那么:
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<ifaddrs.h>
。
这是获取 IP 地址所需的框架。
class func getIPAddress() -> String?
var address: String?
var ifaddr: UnsafeMutablePointer<ifaddrs>? = nil
if getifaddrs(&ifaddr) == 0
var ptr = ifaddr
while ptr != nil
defer ptr = ptr?.pointee.ifa_next
let interface = ptr?.pointee
let addrFamily = interface?.ifa_addr.pointee.sa_family
if addrFamily == UInt8(AF_INET) || addrFamily == UInt8(AF_INET6)
if let name: String = String(cString: (interface?.ifa_name)!), name == "en0"
var hostname = [CChar](repeating: 0, count: Int(NI_MAXHOST))
getnameinfo(interface?.ifa_addr, socklen_t((interface?.ifa_addr.pointee.sa_len)!), &hostname, socklen_t(hostname.count), nil, socklen_t(0), NI_NUMERICHOST)
address = String(cString: hostname)
freeifaddrs(ifaddr)
return address
【讨论】:
获取“用于检查可选项的“字符串”类型的非可选表达式”警告。 当我激活我的个人热点时,我的地址 === " "(即为空)但是当我的设备被激活到外部热点时工作正常。我正在使用 iOS 12.1.4 嗨。我在尝试 UInt8(...) 方法时崩溃了,有人可以帮忙吗? ***.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 个设备出错 -> ***.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
【讨论】:
以上是关于Swift - 获取设备的 WIFI IP 地址的主要内容,如果未能解决你的问题,请参考以下文章
如何在同一网络上以编程方式获取其他支持Wifi的设备的IP地址?