Can you pass WiFi settings from an iOS device to an ExternalAccessory object? - iphone

I've heard that iOS 5 introduced a feature in which the iOS device can share its wifi configuration with a docked accessory via the ExternalAccessory framework. The trouble is that I can't find any specific details on implementing this type of scheme in the SDK docs.
From my research, I've begun to suspect it's achieved via the 'iPhone Configuration Utility' but this still seems like a bit of a messy method to implement on a device.
Anyone got any ideas?
Once the wifi setup data is available, it should be easy enough to package it up and send it out via the ExternalAccessory framework to the device, where I'll build in protocol support accordingly.
Thanks

Yes! you certainly can. However, to use HomeKit (the library you need) you first need to be a certified MFi (Made For iDevice-iPhone-iPod-iPad) developer. This gives you the ability to allow a user to view all available wifi networks and choose to link the device.
One example of this is Withings with their Aura sleep aid. See screenshot from on boarding experience:
Then the user can then choose to share their home wifi information securely with the new device.

The user-visible UI looks like this:
http://www.theregister.co.uk/2012/07/12/pure_contour_200i_air_airplay_wireless_music_system/
https://withings.zendesk.com/hc/en-us/articles/201488707-Wi-Fi-Setup-of-the-Wireless-Scale-WS-30

A bit late but configureAccessory is the method (part of ExternalAccessory) introduced in iOS 8.0 that you can use to configure a wifi accessory:
https://developer.apple.com/documentation/externalaccessory/eawifiunconfiguredaccessorybrowser/1613907-configureaccessory
It's part of the EAWiFiUnconfiguredAccessoryBrowser class:
https://developer.apple.com/documentation/externalaccessory/eawifiunconfiguredaccessorybrowser
And showBluetoothAccessoryPicker is the one for Bluetooth products:
https://developer.apple.com/documentation/externalaccessory/eaaccessorymanager/1613913-showbluetoothaccessorypicker
which is part of the EAAccessoryManager class:
https://developer.apple.com/documentation/externalaccessory/eaaccessorymanager

I doubt Apple would ever allow for an average developer to access private data such as wifi connections settings. Maybe trusted third party accessory provider yes, but you probably no.
Wifi settings are private and contain passwords. An average (non-power) user uses more or less the same/similar password for everything including their Wifi network. If an app can easily read that it could be badly exploited.
The same way you cannot get the Apple id let alone the password.

Have you seen this: iPhone get SSID without private library
Is prompting the App user for a secured network password out of the question?
You can at least get the SSID of an unsecured network and pass it to your accessory with a getter something like:
#import <SystemConfiguration/CaptiveNetwork.h>
#implementation DeviceWifiSSID
//https://stackoverflow.com/a/5198968/614688
+(NSString *)deviceSSID
{
NSArray *ifs = (__bridge id)CNCopySupportedInterfaces();
id info = nil;
for (NSString *ifnam in ifs) {
info = (__bridge id)CNCopyCurrentNetworkInfo((__bridge CFStringRef)ifnam);
if ([info objectForKey:#"SSID"] != nil)
{
return [info objectForKey:#"SSID"];
}
}
return nil;
}
#end

Related

Getting iPhone Carrier Mobile Number in Xcode [duplicate]

Is there any way to get own phone number by standard APIs from iPhone SDK?
At the risk of getting negative marks, I want to suggest that the highest ranking solution (currently the first response) violates the latest SDK Agreement as of Nov 5, 2009. Our application was just rejected for using it. Here's the response from Apple:
"For security reasons, iPhone OS restricts an application (including its preferences and data) to a unique location in the file system. This restriction is part of the security feature known as the application's "sandbox." The sandbox is a set of fine-grained controls limiting an application's access to files, preferences, network resources, hardware, and so on."
The device's phone number is not available within your application's container. You will need to revise your application to read only within your directory container and resubmit your binary to iTunes Connect in order for your application to be reconsidered for the App Store.
This was a real disappointment since we wanted to spare the user having to enter their own phone number.
No, there's no legal and reliable way to do this.
If you find a way, it will be disabled in the future, as it has happened with every method before.
Update: capability appears to have been removed by Apple on or around iOS 4
Just to expand on an earlier answer, something like this does it for me:
NSString *num = [[NSUserDefaults standardUserDefaults] stringForKey:#"SBFormattedPhoneNumber"];
Note: This retrieves the "Phone number" that was entered during the iPhone's iTunes activation and can be null or an incorrect value. It's NOT read from the SIM card.
At least that does in 2.1. There are a couple of other interesting keys in NSUserDefaults that may also not last. (This is in my app which uses a UIWebView)
WebKitJavaScriptCanOpenWindowsAutomatically
NSInterfaceStyle
TVOutStatus
WebKitDeveloperExtrasEnabledPreferenceKey
and so on.
Not sure what, if anything, the others do.
Using Private API you can get user phone number on the following way:
extern NSString* CTSettingCopyMyPhoneNumber();
+(NSString *) phoneNumber {
NSString *phone = CTSettingCopyMyPhoneNumber();
return phone;
}
Also include CoreTelephony.framework to your project.
You cannot use iOS APIs alone to capture the phone number (even in a private app with private APIs), as all known methods of doing this have been patched and blocked as of iOS 11. Even if a new exploit is found, Apple has made clear that they will reject any apps from the app store for using private APIs to do this. See #Dylan's answer for details.
However, there is a legal way to capture the phone number without any user data entry. This is similar to what Snapchat does, but easier, as it does not require the user to type in their own phone number.
The idea is to have the app programmatically send a SMS message to a server with the app’s unique installation code. The app can then query the same server to see if it has recently received a SMS message from a device with this unique app installation code. If it has, it can read the phone number that sent it. Here’s a demo video showing the process. As you can see, it works like a charm!
This is not super easy to set up, but it be configured in a few hours at no charge on a free AWS tier with the sample code provided in the tutorial here.
As you probably all ready know if you use the following line of code, your app will be rejected by Apple
NSString *num = [[NSUserDefaults standardUserDefaults] stringForKey:#"SBFormattedPhoneNumber"];
here is a reference
http://ayeapi.blogspot.com/2009/12/sbformatphonenumber-is-lie.html
you can use the following information instead
NSString *phoneName = [[UIDevice currentDevice] name];
NSString *phoneUniqueIdentifier = [[UIDevice currentDevice] uniqueIdentifier];
and so on
#property(nonatomic,readonly,retain) NSString *name; // e.g. "My iPhone"
#property(nonatomic,readonly,retain) NSString *model; // e.g. #"iPhone", #"iPod Touch"
#property(nonatomic,readonly,retain) NSString *localizedModel; // localized version of model
#property(nonatomic,readonly,retain) NSString *systemName; // e.g. #"iPhone OS"
#property(nonatomic,readonly,retain) NSString *systemVersion; // e.g. #"2.0"
#property(nonatomic,readonly) UIDeviceOrientation orientation; // return current device orientation
#property(nonatomic,readonly,retain) NSString *uniqueIdentifier; // a string unique to each device based on various hardware info.
Hope this helps!
To get you phone number you can read a plist file. It will not work on non-jailbroken iDevices:
NSString *commcenter = #"/private/var/wireless/Library/Preferences/com.apple.commcenter.plist";
NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:commcenter];
NSString *PhoneNumber = [dict valueForKey:#"PhoneNumber"];
NSLog([NSString stringWithFormat:#"Phone number: %#",PhoneNumber]);
I don't know if Apple allow this but it works on iPhones.
No official API to do it. Using private API you can use following method:
-(NSString*) getMyNumber {
NSLog(#"Open CoreTelephony");
void *lib = dlopen("/Symbols/System/Library/Framework/CoreTelephony.framework/CoreTelephony",RTLD_LAZY);
NSLog(#"Get CTSettingCopyMyPhoneNumber from CoreTelephony");
NSString* (*pCTSettingCopyMyPhoneNumber)() = dlsym(lib, "CTSettingCopyMyPhoneNumber");
NSLog(#"Get CTSettingCopyMyPhoneNumber from CoreTelephony");
if (pCTSettingCopyMyPhoneNumber == nil) {
NSLog(#"pCTSettingCopyMyPhoneNumber is nil");
return nil;
}
NSString* ownPhoneNumber = pCTSettingCopyMyPhoneNumber();
dlclose(lib);
return ownPhoneNumber;
}
It works on iOS 6 without JB and special signing.
As mentioned creker on iOS 7 with JB you need to use entitlements to make it working.
How to do it with entitlements you can find here:
iOS 7: How to get own number via private API?
AppStore will reject it, as it's reaching outside of application container.
Apps should be self-contained in their bundles, and may not read or write data outside the designated container area
Section 2.5.2 :
https://developer.apple.com/app-store/review/guidelines/#software-requirements

Alternative to NSDistributedNotificationCenter for comms between iPhone apps

I've been looking for a way to compare timestamps between applications on the same phone in real time, and NSDistributedNotificationCenter sounded like an ideal solution since i may not know the names of the apps listening for it, but it sounds like its not available in iOS.
Is there an equivalent way of notifying multiple apps of a time-sensitive event without knowing their name?
Coding for iOS 5+ and assuming the apps in question will register for the notification.
Look at CPDistributedMessagingCenter in /System/Library/PrivateFrameworks/AppSupport.framework. However, it's a private framework (may change with OS releases, and not allowed in AppStore).
Documentation here: http://iphonedevwiki.net/index.php/CPDistributedMessagingCenter
Example codes of mine here:
https://github.com/H2CO3/PwnTube
https://github.com/H2CO3/Cereal
I'm pretty sure you can use Mach ports. They are a bit low level but work well.
i found a way to use CFNotificationCenterGetDistributedCenter() on iOS. It is exists on device, but not exports in iOS SDK
void *libHandle = dlopen("/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation", RTLD_LAZY);
CFNotificationCenterRef (*CFNotificationCenterGetDistributedCenter)() = (CFNotificationCenterRef (*)())dlsym(libHandle, "CFNotificationCenterGetDistributedCenter");
if(CFNotificationCenterGetDistributedCenter) {
CFNotificationCenterAddObserver(CFNotificationCenterGetDistributedCenter(), NULL, &NotificationUpdateApp, CFSTR("TestApp"), NULL, CFNotificationSuspensionBehaviorCoalesce);
}
dlclose(libHandle);
Not really. The closest you can do to what you’re asking, on a non-jailbroken device, is have your server talk to each other app’s server and have that server send a push notification to the app in question. Without NSDistributedNotificationCenter (which is, as you surmise, not available on iOS), you don’t really have any other option.
This question is a little bit old, but I'll post my answer just for information purposes.
NSDistributedNotificationCenter is not available for iOS yet, and unless your are developing an app that you don'd pretend to release on AppStore, you can't use AppSupport.framework because it's private.
iOS8 released App Extensions, that give us the ability to communicate with other apps. I don't know what you are trying to do exactly but I believe that if you are just trying to compare some timestamps from some other apps, it should resolve your problem.
Link to AppExtensions documentation:
https://developer.apple.com/library/ios/documentation/General/Conceptual/ExtensibilityPG/
Hope it helps somebody.
NSDistributedNotificationCenter exists on iOS, but the headers aren't made available to developers.
Create a header file in your project with the following to make the class available:
#interface NSDistributedNotificationCenter : NSNotificationCenter
+ (NSDistributedNotificationCenter *)defaultCenter;
// Returns the default distributed notification center - cover for [NSDistributedNotificationCenter notificationCenterForType:NSLocalNotificationCenterType]
- (void)postNotificationName:(NSNotificationName)name object:(nullable NSString *)object userInfo:(nullable NSDictionary *)userInfo deliverImmediately:(BOOL)deliverImmediately;
#end
This is very useful when trying to get information from an App to its UITest runner, but you should obviously NOT attempt to put this in the AppStore.
I've created a project XCTestBackChannel to show this off.

Check a Server for a matching UDID and autofill UITextField with matching Username

This is my first post on here so be nice :) I am new to coding iOS and currently coding an app which uses a login system which communicates with the server and saves a users UDID. I need to app to check the UDID is on the server and if it matches to auto fill the Username UITextField in the login form.
Please could someone help me out or point me in the right direction.
Mike
Welcome to SO.
I assume you know how to get the UDID? If not, you get it as this
NSString *udid = [[UIDevice currentDevice] uniqueIdentifier];
Send this to your server (where you have a table with UDIDs and corresponding user information). Using PHP (or whatever language you are using), check if there is an entry for this UDID on the server. If yes, get the corresponding username and set it in the text field as
[textField setText:theUserName];
If you don't know how to send requests and get response from iOS apps, ASIHTTPRequest would be a good and easy way to begin.
If you need any other specific help, I would suggest updating the question.
Welcome to both iOS and Stackoverflow!
You could build a PHP service which would verify the UDID of your device and check if this device and username are already registered at your site, asuming you are keeping track of these registrations using a MySQL database, PHP could most certainly do the trick.
After verifying the existence of this device, you could use a JSON callback to send the UDID of the device to the iPhone.
As for parsing this JSON check out SBJSONParser.
It might be hard to pull this off in 2 languages, asuming you are new to both. This task is possibly completed in more secure or easier methods, but this might be a consideration to check every part of web communication that the iPhone has to offer
Good luck!
Bryan
Mike, Apple will be phasing out UDID so you should really look at a new approach to this. I would suggest a combination of app.domain and the device MAC number.
Then, have your app talk to your server using HTTPRequest and return the data as JSON and parse that on the app side.
GitHub already has a solution to UIDevice uniqueidentifier being dropped:
https://github.com/gekitz/UIDevice-with-UniqueIdentifier-for-iOS-5
Project Description:
Description
Apple stopped supporting a unique identifier for iOS. This
source code solves the problem. It generates a unique identifier based
on the mac address of the device in combination with the bundle
identifier.
What you need to do:
copy NSString+MD5Addition and UIDevice+IdentifierAddition to your
project.
use [[UIDevice currentDevice] uniqueDeviceIdentifier] to retrieve the
unique identifier or
use [[UIDevice currentDevice] uniqueGlobalDeviceIdentifier] to
retrieve a global unique identifier (used for tracking between
different apps).
have fun and follow twitter.com/gekitz ;)
//Thanks to Erica Sadun for her UIDevice+Hardware Addition (used for
the mac address retrieval).

Can you access an iPhone's phone number via code in an app? [duplicate]

Is there any way to get own phone number by standard APIs from iPhone SDK?
At the risk of getting negative marks, I want to suggest that the highest ranking solution (currently the first response) violates the latest SDK Agreement as of Nov 5, 2009. Our application was just rejected for using it. Here's the response from Apple:
"For security reasons, iPhone OS restricts an application (including its preferences and data) to a unique location in the file system. This restriction is part of the security feature known as the application's "sandbox." The sandbox is a set of fine-grained controls limiting an application's access to files, preferences, network resources, hardware, and so on."
The device's phone number is not available within your application's container. You will need to revise your application to read only within your directory container and resubmit your binary to iTunes Connect in order for your application to be reconsidered for the App Store.
This was a real disappointment since we wanted to spare the user having to enter their own phone number.
No, there's no legal and reliable way to do this.
If you find a way, it will be disabled in the future, as it has happened with every method before.
Update: capability appears to have been removed by Apple on or around iOS 4
Just to expand on an earlier answer, something like this does it for me:
NSString *num = [[NSUserDefaults standardUserDefaults] stringForKey:#"SBFormattedPhoneNumber"];
Note: This retrieves the "Phone number" that was entered during the iPhone's iTunes activation and can be null or an incorrect value. It's NOT read from the SIM card.
At least that does in 2.1. There are a couple of other interesting keys in NSUserDefaults that may also not last. (This is in my app which uses a UIWebView)
WebKitJavaScriptCanOpenWindowsAutomatically
NSInterfaceStyle
TVOutStatus
WebKitDeveloperExtrasEnabledPreferenceKey
and so on.
Not sure what, if anything, the others do.
Using Private API you can get user phone number on the following way:
extern NSString* CTSettingCopyMyPhoneNumber();
+(NSString *) phoneNumber {
NSString *phone = CTSettingCopyMyPhoneNumber();
return phone;
}
Also include CoreTelephony.framework to your project.
You cannot use iOS APIs alone to capture the phone number (even in a private app with private APIs), as all known methods of doing this have been patched and blocked as of iOS 11. Even if a new exploit is found, Apple has made clear that they will reject any apps from the app store for using private APIs to do this. See #Dylan's answer for details.
However, there is a legal way to capture the phone number without any user data entry. This is similar to what Snapchat does, but easier, as it does not require the user to type in their own phone number.
The idea is to have the app programmatically send a SMS message to a server with the app’s unique installation code. The app can then query the same server to see if it has recently received a SMS message from a device with this unique app installation code. If it has, it can read the phone number that sent it. Here’s a demo video showing the process. As you can see, it works like a charm!
This is not super easy to set up, but it be configured in a few hours at no charge on a free AWS tier with the sample code provided in the tutorial here.
As you probably all ready know if you use the following line of code, your app will be rejected by Apple
NSString *num = [[NSUserDefaults standardUserDefaults] stringForKey:#"SBFormattedPhoneNumber"];
here is a reference
http://ayeapi.blogspot.com/2009/12/sbformatphonenumber-is-lie.html
you can use the following information instead
NSString *phoneName = [[UIDevice currentDevice] name];
NSString *phoneUniqueIdentifier = [[UIDevice currentDevice] uniqueIdentifier];
and so on
#property(nonatomic,readonly,retain) NSString *name; // e.g. "My iPhone"
#property(nonatomic,readonly,retain) NSString *model; // e.g. #"iPhone", #"iPod Touch"
#property(nonatomic,readonly,retain) NSString *localizedModel; // localized version of model
#property(nonatomic,readonly,retain) NSString *systemName; // e.g. #"iPhone OS"
#property(nonatomic,readonly,retain) NSString *systemVersion; // e.g. #"2.0"
#property(nonatomic,readonly) UIDeviceOrientation orientation; // return current device orientation
#property(nonatomic,readonly,retain) NSString *uniqueIdentifier; // a string unique to each device based on various hardware info.
Hope this helps!
To get you phone number you can read a plist file. It will not work on non-jailbroken iDevices:
NSString *commcenter = #"/private/var/wireless/Library/Preferences/com.apple.commcenter.plist";
NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:commcenter];
NSString *PhoneNumber = [dict valueForKey:#"PhoneNumber"];
NSLog([NSString stringWithFormat:#"Phone number: %#",PhoneNumber]);
I don't know if Apple allow this but it works on iPhones.
No official API to do it. Using private API you can use following method:
-(NSString*) getMyNumber {
NSLog(#"Open CoreTelephony");
void *lib = dlopen("/Symbols/System/Library/Framework/CoreTelephony.framework/CoreTelephony",RTLD_LAZY);
NSLog(#"Get CTSettingCopyMyPhoneNumber from CoreTelephony");
NSString* (*pCTSettingCopyMyPhoneNumber)() = dlsym(lib, "CTSettingCopyMyPhoneNumber");
NSLog(#"Get CTSettingCopyMyPhoneNumber from CoreTelephony");
if (pCTSettingCopyMyPhoneNumber == nil) {
NSLog(#"pCTSettingCopyMyPhoneNumber is nil");
return nil;
}
NSString* ownPhoneNumber = pCTSettingCopyMyPhoneNumber();
dlclose(lib);
return ownPhoneNumber;
}
It works on iOS 6 without JB and special signing.
As mentioned creker on iOS 7 with JB you need to use entitlements to make it working.
How to do it with entitlements you can find here:
iOS 7: How to get own number via private API?
AppStore will reject it, as it's reaching outside of application container.
Apps should be self-contained in their bundles, and may not read or write data outside the designated container area
Section 2.5.2 :
https://developer.apple.com/app-store/review/guidelines/#software-requirements

On the iPhone, is it possible to find out which WIFI network we are connected to?

If yes, can we also get additional information about the network configuration?
One useful way to do this could be getting the SSID of the current network. Is there an API to do that?
Update: I found a similar question here:
Can the iPhone SDK obtain the Wi-Fi SSID currently connected to?
Try following method:
#import <SystemConfiguration/CaptiveNetwork.h>
NSString *wifiName = #"Not Found";
CFArrayRef myArray = CNCopySupportedInterfaces();
if (myArray != nil) {
CFDictionaryRef myDict = CNCopyCurrentNetworkInfo(CFArrayGetValueAtIndex(myArray, 0));
if (myDict != nil) {
NSDictionary *dict = (NSDictionary*)CFBridgingRelease(myDict);
wifiName = [dict valueForKey:#"SSID"];
}
}
NSLog(#"wifiName:%#", wifiName);
(Separate answer to preserve history etc.)
It looks like you might not be able to determine the SSID of the WLAN to which you're connected, at least in an app that will go into the App Store. These people use a private API - Preferences.framework - to get to the details of the WLAN (like "is it hidden?" "What's the name?" etc.).
Can't comment, but this might be a duplicate:
Accessing iPhone WiFi Information via SDK
Answer seems to be no. I've done my own research on this and have been unable to find a supported way of getting the SSID.
Have you looked at the Reachability sample app?
Edit: The Reachability app demonstrates the use of the SystemConfiguration framework to show whether your phone's connected to the internet and, if so, how.
It further allows you to distinguish between a local WiFi connection and not (+[Reachability reachabilityForLocalWiFi]).
Regarding the meat of your question, you'll have to consult the phone's ARP table. This answer shows you how to do just that.