iOS - Get device's WIFI IP Address - ios

I need to get the device IP of the WiFi interface.
According to several StackOverflow threads, we could assume that "en0" corresponds to the Wi-Fi interface name :
https://stackoverflow.com/a/30754194/12866797
However, this feels like some kind of convention, not a standard.
Is there any consistent/standard way to retrieve the WiFi interface or the device WiFi IP address, using the iOS SDK ?
It would be nice if the API is available starting from iOS 11 but I won't be picky.
My best attempt was to use NWPathMonitor (iOS 12+) and monitor network changes corresponding to WiFi interfaces (NWInterface.InterfaceType.wifi) :
- (void) MonitorWifiInterface
{
m_pathMonitor = nw_path_monitor_create_with_type(nw_interface_type_wifi);
nw_path_monitor_set_update_handler(m_pathMonitor, ^(nw_path_t _Nonnull path) {
NSLog(#"[NetInterfaceUtilies] Network path changed");
nw_path_enumerate_interfaces(path, ^ bool (nw_interface_t _Nonnull itf)
{
NSLog(#"[NetInterfaceUtilies] Name : %s , Index : %u", nw_interface_get_name(itf), nw_interface_get_index(itf));
return true; // In order to continue the enumeration
});
});
nw_path_monitor_start(m_pathMonitor);
}
But I am not happy with it for the following reasons :
NWPathMonitor is supposed to be used for monitoring network changes : I haven't managed to get network information whenever I wanted, but only when WiFi has been set on/off.
I only managed to get the network interface name. But I can combine this data with the network interfaces retrieved with getifaddrs() in order to deduce the correct interface and IP : it's a step forward ?
It's "only" available starting from iOS 12.

Related

How to support low data mode in iOS 13?

"Low Data Mode" is introduced in iOS 13. See "Settings" section Apple's iOS 13 overview:
I couldn't find any developer documentation on this.
Is this something third party app developers can opt into, as suggested by MacRumors? Or is will it just suspend background activity when not connected to Wi-Fi, as suggested by AppleInsider?
To determine if iOS is currently in Low Data mode, you can use the Network library:
import Network // Put this on top of your class
let monitor = NWPathMonitor()
monitor.pathUpdateHandler = { path in
if path.isConstrained {
// Path uses an interface in Low Data Mode.
}
else if path.isExpensive {
// Path uses an interface that is considered expensive, such as Cellular or a Personal Hotspot.
}
}
monitor.start(queue: DispatchQueue.global(qos: .background))
URLSession supports LowData mode in iOS 13.
Steps
Provide two different resources for high resolution and low resolution(low data mode)
If statusCode == 200 (low data mode is disabled in setting).
If error.networkAvailableReason == .constrained (low data mode is enable in settings)
Check out Advances in Networking, Part 1 from WWDC 2019 from 16:00 for a demo and sample code. You can use Combine to make the code simpler, but this is not required.
First of all, you need to configure your URLSession (NSURLSession) to either allow or disallow expensive or constrained network connections to be opened.
You can do that by changing URLSession's respective properties allowsExpensiveNetworkAccess or allowsConstrainedNetworkAccess to false (NO).
If a URLSessionTask results in an error that is either an NSURLErrorNotConnectedToInternet error containing NSURLErrorNetworkUnavailableReasonKey entry in userInfo (Objective-C) or an URLError with a non-nil NetworkUnavailableReason property set (Swift), then you need to act accordingly.
Those reasons can be:
expensive
constrained
cellular
The cellular reason has sort of been there since iOS 7, so it's not new, but the entire reason enumeration is, as Apple streamlined connection type handling a bit this year.
Here is the solution in Xamarin, for those interested:
NWPathMonitor monitor = new NWPathMonitor();
monitor.SetUpdatedSnapshotHandler(path =>
{
if (path.Status == NWPathStatus.Satisfied)
{
if(path.IsConstrained)
{
// Path uses an interface in Low Data Mode.
}
}
});
monitor.SetQueue(CoreFoundation.DispatchQueue.DefaultGlobalQueue);
monitor.Start();

What devices does CBCentralManager.retrieveConnectedPeripherals() return?

I want to check which Bluetooth Devices my iPhone is connected to. In order to do that, I use CBCentralManager.retrieveConnectedPeripherals() like this:
let connectedPerphs = centralManager.retrieveConnectedPeripherals(withServices: []);
My problem is that even if my iPhone is connected to a BluetoothDongle (it explicitly says "connected" in the settings), the list that is returned by retriveConnectedPeripherals() is always empty. Am I using the method in a wrong way or can it not be used to detect a bluetooth connection such as the connection to to my dongle? If the latter is the case, how can I detect that connection?
Let me clear, centralManager.retrieveConnectedPeripherals always return empty or nil value, If you are not passing any value into serviceUUIDs
retrieveConnectedPeripherals(withServices:)
Returns a list of the peripherals (containing any of the specified
services) currently connected to the system.
serviceUUIDs:
A list of service UUIDs (represented by CBUUID objects).
Update:
Unfortunately this the long way to do it. You can create Array of CBUUID statically then you can pass it to the method. Please refer below code.
let aryUUID = ["1800","18811"]
var aryCBUUIDS = [CBUUID]()
for uuid in aryUUID{
let uuid = CBUUID(string: "1800")
aryCBUUIDS.append(uuid)
}
let connectedPerphs = centralManager.retrieveConnectedPeripherals(withServices: aryCBUUIDS)
List of available services
First, this works only with BLE devices, thus if your dongle is using a common BT you will not get it from here, but probably using EAAccessoryManager var connectedAccessories: [EAAccessory] method, but as far as I know your app must comply to MFI.
That is why is asking which service your devices are exposing as a filter.

NEHotspotConfigurationManager Can it get the WiFi list?

iOS released the public API NEHotspot ConfigurationManager
Inside there is a function: getConfiguredSSIDs (completionHandler: ([String]) -> Void)
Do not know the return value of this, my Code like:
Code :
[[NEHotspotConfigurationManager sharedManager] getConfiguredSSIDsWithCompletionHandler: ^ (NSArray * array) {
            
             NSLog (# "Response:% #", array);
           
         }];
However, the value is null .. Why?
Is there any way to get nearby WiFi using NEHotspotConfigurationManager without going through NEHotspotHelper?
For security reasons your app only has access to SSIDs that your app itself has configured.
To configure a wifi network you need to enable the Hotspot Configuration entitlement in your app settings and then call:
NEHotspotConfigurationManager.shared.apply()
It's also worth noting that if the user has already manually joined the wifi network outside of your app when your app tries to join that network you will get an error stating that they are already a member and it won't show up in the ConfiguredSSIDs list, so try to support this as well.

Will en0 always be Wi-Fi on an iOS device?

I’m trying to get the IP address of the wifi interface on iOS devices using getifaddrs() and searching for the en0 name. This is working fine, but it assumes that en0 is always Wi-Fi. Is there some way to ensure that the interface I’m querying is specifically Wi-Fi for future proofing?
I use the following to find the wifi information by looking for a device which has a BSSID for the wifi station. It will also have a SSID.
The following class method returns the wifi info dictionary only. It is a simple extension to also return the device label (ifname variable). It is usually en0, as you have noted, but this would work as a way to make sure you pick up the wifi if it was not en0 in the future.
+ (NSDictionary *)getWifiInfo {
NSDictionary *ret=nil;
// Get the supported interfaces.
NSArray *ifs = (__bridge_transfer id)CNCopySupportedInterfaces();
// Find one with a BSSID and return that. This should be the wifi.
for (NSString *ifnam in ifs) {
NSDictionary *info = (__bridge_transfer id)CNCopyCurrentNetworkInfo((__bridge CFStringRef)ifnam);
NSLog(#"Network device found = %#", info.description);
if (info[(__bridge NSString *)kCNNetworkInfoKeyBSSID]) {
// Return this as it should be the right one given it has a MAC address for the station
ret=info;
}
}
NSLog(#"Exit: returning wifi info = %#", ret.description);
return ret;
}
Once you have the device label based on BSSID, you can then use getifaddrs to get its IP, gateway etc knowing it is the wifi device.
NB This returns nil in the iOS simulator as there is no wifi detected, so for testing you need some workaround code to meet your needs.
A hacky option is to find the IP address with an associated MAC of 02:00:00:00:00:00. iOS hides the MAC address from coders and it has this value.

Xamarin: Detect network/host reachability

I'm experimenting with "Reachability" in Xmarin, using the Reachability class (sample here), but I cannot get the "IsHostReachable" feature to work.
I do realize that the Reachability class utilizes the NetworkReachability class but no matter which class I use the TryGetFlags() method always passes back the NetworkReachabilityFlags argument with a zero (0) value.
I started out using the Reachability class' method but while debugging I saw that the problem seems to originate in NetworkReachability. I tried the following code just to make sure:
using (var r = new NetworkReachability(host))
{
NetworkReachabilityFlags flags;
if (r.TryGetFlags(out flags)) // <-- flags is always 0 (zero)
return (flags & NetworkReachabilityFlags.Reachable) == NetworkReachabilityFlags.Reachable;
return false;
}
Like I said the flags variable is passed back with a zero (0) value, regardless of the device's current connection status. The host I'm testing against is a intranet web app that is only available when I'm on my company's WIFI. I have tested debuging the iPhone while connected and double checked by simply trying to browse to the host in Safari, which works.
The API is poorly documented but I'm suspecting I might need to initialize the NetworkReachability class somehow.
Any ideas?

Resources