BuySellAds.com

Our DNA is written in Objective-C
Jump

Detect Roaming

hhyyy9 asks:

It’s possible to detect when device goes on roaming or out of home network and turn on / turn off the data connection?

Well, yes and no. Yes to the part of the question about detecting. No to changing a system setting.

You have no direct access at all to roaming or home network information. Probably via a private framework but Apple does not approve of apps using those. Though you could infer the currently used data network from the IP address range you get from the currently active cellular connection. Each provider will have certain IP ranges and if you collect these ranges then you could build up a database to detect such network switching.

Also wheres the point? There already IS a setting that allows you to disable data roaming.

general network

The fact remains that you still cannot mess with the data system setting, but only work within your app.

But this would not be an worthy Dr. Touch post if I didn’t share some cool knowledge, this time how you can get all the current IP addresses of your device. Something like “IPCONFIG /ALL” on Windows or “IFCONFIG” on Unix.

The following code I found in the HTTP server project which I used for MyAppSales:

localhostAddresses.h:

//
//  This class was created by Nonnus,
//  who graciously decided to share it with the CocoaHTTPServer community.
//
 
#import 
 
 
@interface localhostAdresses : NSObject {
 
}
 
+ (void)list;
 
@end

localhostAddresses.m:

//
//  This class was created by Nonnus,
//  who graciously decided to share it with the CocoaHTTPServer community.
//
 
#import "localhostAdresses.h"
 
#import 
#import 
#import 
 
@implementation localhostAdresses
 
+ (void)list
{
	NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
 
	NSMutableDictionary* result = [NSMutableDictionary dictionary];
	struct ifaddrs*	addrs;
	BOOL success = (getifaddrs(&addrs) == 0);
	if (success)
	{
		const struct ifaddrs* cursor = addrs;
		while (cursor != NULL)
		{
			NSMutableString* ip;
			if (cursor->ifa_addr->sa_family == AF_INET)
			{
				const struct sockaddr_in* dlAddr = (const struct sockaddr_in*)cursor->ifa_addr;
				const uint8_t* base = (const uint8_t*)&dlAddr->sin_addr;
				ip = [[NSMutableString new] autorelease];
				for (int i = 0; i ifa_name]];
			}
			cursor = cursor->ifa_next;
		}
		freeifaddrs(addrs);
	}
 
	// www address
 
	NSURL *netIPURL = [NSURL URLWithString:@"http://whatismyip.org"];
	NSString *netIP = [NSString stringWithContentsOfURL:netIPURL encoding:NSUTF8StringEncoding error:nil];
	if (netIP)
		[result setObject:netIP forKey:@"www"];
 
	[[NSNotificationCenter defaultCenter] postNotificationName:@"LocalhostAdressesResolved" object:result];
 
	[pool release];
}
 
@end

And in a convenient place, like the app delegate:

// at the top: #import "localhostAdresses.h"
 
- (void)applicationDidFinishLaunching:(UIApplication *)application
{
	// other code omitted
 
	[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(addressesResolved:) name:@"LocalhostAdressesResolved" object:nil];
	[localhostAdresses performSelectorInBackground:@selector(list) withObject:nil];
}

This starts the address resolution process on a background thread which in turn will send an app-wide notification LocalhostAdressesResolved which we are going to subscribe to. And yes, I know that Address is spelled incorrectly with only one D, but that’s the way it’s in the original code, the person who added the comment probably was German because they really write addresses there without the second D. I left this in intentionally to demonstrate that you should always prefer to steal good code.

The notification returns when the resolution is complete. This might take a some time because it’s using whatsmyip.org to resolve the WAN address.

- (void)addressesResolved:(NSNotification *) notification
{
	if(notification)
	{
		NSDictionary *addresses = [notification object];
		NSLog(@"addresses: %@", addresses);
	}
}

The object that you get returned holds the short name of the network connection and the contain objects are IP address strings. It looks like this when dumped with NSLog, you get the picture.

addresses: {
    en1 = "10.0.1.2";
    lo0 = "127.0.0.1";
    vmnet1 = "192.168.107.1";
    vmnet8 = "172.16.20.1";
    www = "85.127.114.124";
}

Do you have a keen eye? Can you tell if this is the result from running the code on iPhone Simulator or the device?

The answer is sim, because you also see the two virtual interfaces from my VMware Fusion setup. And more specifically I’m on WLAN on my MacBook where this is interface “en1″. Since the iPhone does not have a wired network interface the WLAN there is “en0″.

So to get the correct one you’ll have to do some code trickery. This is what I have to do in MyAppSales, that’s why I know this.

#if TARGET_IPHONE_SIMULATOR
	NSString *curAddress = [addresses objectForKey:@"en1"];
#else
	NSString *curAddress = [addresses objectForKey:@"en0"];
#endif

The www address you get would have to be queried on whois or maybe your own database to get the name of the network you are currently on.


Categories: Q&A

%d bloggers like this: