快速获取设备的 WIFI IP 地址

我需要得到在迅捷的 iOS 设备的 IP 地址。这不是关于这个的其他问题的复制品!我只需要得到无线 IP 地址,如果没有无线 IP 地址-我需要处理它。在 Stack Overflow 上有一些关于它的问题,但是只有一些函数返回 ip 地址。例如(来自 怎样快速得到叶问地址) :

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


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


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


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


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


return addresses
}

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

108799 次浏览

创建桥接头并在其中包含 #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
}

当我在 viewController 中调用这个方法时,比如 var arr : NSArray = self.getIFAddresses(),我在控制台中得到了完美的响应,比如

IP: ( “10.0.0.94” )

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

根据几个 SO 线程(例如 什么是 iOS 网络接口名称的确切含义? 什么是 pdp _ ip? 什么是 ap?) ,iOS 设备上的 WiFi 接口总是命名为“ en0”。

您的代码(这似乎是我在 怎样快速得到叶问地址上回答的问题:)检索运行网络接口的 所有的 IP 地址列表。它可以很容易地进行修改,只返回 IP 地址 的“ en0”接口,实际上这就是我 最初的 回答了这个问题(这只是斯威夫特的翻译 回答 如何以编程方式获取 iPhone 的 IP 地址) :

// 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的更新: 除了将代码采用到 斯威夫特的许多变化, 迭代所有接口现在可以使用新的通用 功能:

执行 没有时忘记在桥接头中添加 #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 }

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

注意: 我已经使用可达性,以便它捕获新的 IP 地址的情况下,无线网络被更改为另一个。

  1. Podfile文件中

    然后是 install pod

  2. AppDelegate.swift文件 import ReachabilitySwift

    注意: 如果它提示一个错误,无法找到 ReachabitySwift 模块,那么只需复制并粘贴这个。成功了!

  3. didFinishLaunchingOptions功能

    NotificationCenter.default.addObserver(self, selector: #selector(self.reachabilityChanged), name: ReachabilityChangedNotification, object: reachability)
    
    
    do{
    try reachability.startNotifier()
    }
    catch {
    print("could not start reachability notifier")
    }
    
  4. 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. 如果你想删除观察者,那么:

    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
}

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
}

这里所有的答案只提供 wifi 的 ip 地址,而不是有线或蜂窝。下面的代码片段可用于 wifi/wire/蜂窝式无线网络:

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 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()

如果只希望将 IPv4响应作为输出,只需修改 MartinR 的解决方案即可。

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

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

为 wifi,有线和蜂窝5获取 IPAddress

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)")

注意: 在项目的桥接头文件中添加以下内容

#include<ifaddrs.h>

另一个有点不同的解决方案是使用 Ipify,这是一个免费的轻量级服务,您可以通过 ping 获得您的 IP

以下是他们迅速的例子:

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

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
}

基于以上一些答案的 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

支援 IPV4及 IPV6

使其成为 UIDevice 的扩展,并使用 UIDvice.current.getIPAddress ()进行调用

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

考虑到您已经有了套接字的文件描述符,这是 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)

这个类使用 NWPathMonitor 监视设备接口。可以设置通知接口状态更改的 updateHandler。选择是否要跟踪 ipv4或 ipv6并检查 status.interfaceType = = 。看看你的活动界面是否是 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
}
}