We need to use C function to get those values. And then we check the values with command ifconfig
and understand which to which.
Get Local MACs and IP Addresses
private func getLocalIPAndMACAdress() {
var address : String?
// Get list of all interfaces on the local machine:
var ifaddr:UnsafeMutablePointer<ifaddrs>!
if getifaddrs(&ifaddr) == 0 {
// For each interface ...
var ptr:UnsafeMutablePointer<ifaddrs>! = ifaddr
var networkLinkDictionary = [String:[String]]()
repeat {
defer { ptr = ptr.pointee.ifa_next}
let interface = ptr.pointee
// Check interface name:
let 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)
var values = networkLinkDictionary[name] ?? []
values.append(address!)
networkLinkDictionary.updateValue(values, forKey: name)
} while ptr != nil
freeifaddrs(ifaddr)
set(networkLinkDictionary: networkLinkDictionary)
#if DEBUG
networkLinkDictionary.keys.sorted().forEach { key in
print(key, "\t", networkLinkDictionary[key]!)
}
#endif
}
}
private func set(networkLinkDictionary:[String:[String]]) {
networkLinkDictionary.keys.sorted().forEach {
switch $0 {
// for iMac 5K, en0 is ethernet; en1 is WiFi
case "en0":
enthernet = getNetworkLink(values: networkLinkDictionary["en0"] ?? [])
#if DEBUG
debugPrint(enthernet)
#endif
case "en1":
wifi = getNetworkLink(values: networkLinkDictionary["en1"] ?? [])
#if DEBUG
debugPrint(wifi)
#endif
default:
break
}
}
}
private func getNetworkLink(values:[String]) -> NetworkLink {
let networkLink:NetworkLink
switch values.count {
case 1:
networkLink = NetworkLink(MAC: values[0])
case 2:
networkLink = NetworkLink(MAC: values[0], ipv6: values[1])
case 3:
networkLink = NetworkLink(MAC: values[0], ipv6: values[1], ipv4: values[2])
default:
networkLink = NetworkLink(MAC: "")
}
return networkLink
}
public struct NetworkLink:Equatable {
public init(MAC:String, ipv6:String? = nil, ipv4:String? = nil){
self.MAC = MAC
self.ipv6 = ipv6
self.ipv4 = ipv4
}
public let MAC:String
public var ipv6:String? = nil
public var ipv4:String? = nil
}
Get Internet IP Addresses
We use ipify.org to get internet IP addresses.
Don't use URLSession.share
Create a new URLSession each time your own. If you use URLSession.share, you app won't detect internet IP changes, it will always show the IP when the app starts.
I had tried 3 different frameworks on github.com. They all has the above issue. So I write the code myself.
private func setInterIP(type:IPType) async {
let url:URL
if !reachable {
switch type {
case .ipv4:
internetIPV4 = NSLocalizedString("Inactive", bundle: .module, comment: "")
case .ipv6:
internetIPV6 = NSLocalizedString("Inactive", bundle: .module, comment: "")
}
return
}
switch type {
case .ipv4:
url = URL(string: "https://api.ipify.org?format=json")!
if internetIPV4.isEmpty {
internetIPV4 = "..."
}
case .ipv6:
url = URL(string: "https://api64.ipify.org?format=json")!
if internetIPV6.isEmpty {
internetIPV6 = "..."
}
}
let urlSessionConfiguration = URLSessionConfiguration.default
let urlSession = URLSession(configuration: urlSessionConfiguration)
do {
let (data, urlResponse) = try await urlSession.data(from: url)
DispatchQueue.main.async { [self] in
if let httpResponse = urlResponse as? HTTPURLResponse, httpResponse.statusCode == 200 {
if let dic = try? JSONSerialization.jsonObject(with: data, options: []) as? [String:String] {
switch type {
case .ipv4:
internetIPV4 = dic["ip"]!
#if DEBUG
debugPrint(internetIPV4)
#endif
case .ipv6:
internetIPV6 = dic["ip"]!
#if DEBUG
debugPrint(internetIPV6)
#endif
}
}
} else {
#if DEBUG
debugPrint(urlResponse)
#endif
}
}
} catch {
print(error)
}
}