Need an API that detects when an iPhone is plugged in - iphone

I'm making an application for Mac, and I need an API that detects when an iPhone is plugged in. Thanks.
EDIT : To clarify, specifically, I need an API that detects when an iPhone is plugged into a USB port on a Mac.

I don't have a complete answer, but a program that achieves what you want is USB Prober, supplied with Xcode and located at /Developer/Applications/Utilities/USB Prober.app. That program is open source, with the browser viewable repository being here and the whole project being included in this download. I actually found an older version to be more helpful, as available here, especially BusProbeClass.
They all rest on IOKit for which Apple's documentation seems to be very lacking in both quantity and quality.
That's heavy reading, but if you check out + USBProbe then you'll see it gets a list of current USB devices, gets IOUSBDeviceInterfaces for each in the variable deviceIntf and then pushes them to somewhere useful for the rest of the program. If you check out + outputDevice: locationID:deviceNumber: lower down in the same source file, you'll see that GetDescriptor can seemingly be used on an IOUSBDeviceDescriptor to get properties including the vendor and product ID, the combination of which is guaranteed to be unique by the USB Implementer's Forum.
Using the vendor and product ID, you can search for any specific USB device. From my Mac's System Information I can tell you that an iPhone 4 has a product ID of 0x1297 and Apple's vendor ID is 0x05ac.
Extra: from dissecting that code, if you remove a whole bunch of checks that things are succeeding and compress it all down to demonstrative stuff then the following is at least a test for whether an iPhone 4 is plugged in right now (you'll need to link to the Foundation and IOKit frameworks):
#include <stdio.h>
#import <Foundation/Foundation.h>
#import <IOKit/usb/IOUSBLib.h>
#import <IOKit/IOCFPlugIn.h>
#import <mach/mach_port.h>
int main (int argc, const char * argv[])
{
// get the port through which to talk to the kernel
mach_port_t masterDevicePort;
IOMasterPort(MACH_PORT_NULL, &masterDevicePort);
// create a dictionary that describes a search
// for services provided by USB
CFDictionaryRef matchingDictionary = IOServiceMatching(kIOUSBDeviceClassName);
// get an iterator for all devices that match
// the dictionary
io_iterator_t deviceIterator;
IOServiceGetMatchingServices(
masterDevicePort,
matchingDictionary,
&deviceIterator);
// iterate through the iterator...
io_service_t ioDevice;
while((ioDevice = IOIteratorNext(deviceIterator)))
{
IOUSBDeviceInterface **deviceInterface = NULL;
IOCFPlugInInterface **ioPlugin = NULL;
SInt32 score;
// get a pointer to the device, stored to ioPlugin
IOCreatePlugInInterfaceForService(
ioDevice,
kIOUSBDeviceUserClientTypeID,
kIOCFPlugInInterfaceID,
&ioPlugin,
&score);
// ask the device for its interface
(*ioPlugin)->QueryInterface(
ioPlugin,
CFUUIDGetUUIDBytes(kIOUSBDeviceInterfaceID),
(void *)&deviceInterface);
// make and issue a request to get the device descriptor
IOUSBDeviceDescriptor deviceDescriptor;
IOUSBDevRequest request;
request.bmRequestType = USBmakebmRequestType(kUSBIn, kUSBStandard, kUSBDevice);
request.bRequest = kUSBRqGetDescriptor;
request.wValue = kUSBDeviceDesc << 8;
request.wIndex = 0;
request.wLength = sizeof(deviceDescriptor);
request.pData = &deviceDescriptor;
(*deviceInterface)->DeviceRequest(deviceInterface, &request);
// now we have the device descriptor, do a little cleaning up -
// release the interface and the device
(*deviceInterface)->Release(deviceInterface);
IOObjectRelease(ioDevice);
// ensure that the values returned are in the appropriate
// byte order for this platform
CFSwapInt16LittleToHost(deviceDescriptor.idVendor);
CFSwapInt16LittleToHost(deviceDescriptor.idProduct);
// check whether we have an iPhone 4 attached
if(deviceDescriptor.idVendor == 0x05ac && deviceDescriptor.idProduct == 0x1297)
printf("iPhone 4 is connected!");
}
// clean up by releasing the device iterator
// and returning the communications port
IOObjectRelease(deviceIterator);
mach_port_deallocate(mach_task_self(), masterDevicePort);
return 0;
}
I haven't yet figured out how to observe for changes in plugged-in devices.

Related

IOCreatePlugInInterfaceForService returns mysterious error

I am trying to use some old IOKit functionality in a new Swift 4.0 Mac app (not iOS). I have created a bridging header to use an existing Objective C third party framework, DDHidLib, and I am current working in Xcode 9.
The code that attempts to create a plug in interface for a usb gamepad falls over on IOCreatePlugInInterfaceForService, returning a non-zero error.
The truly bizarre thing is I have an older app created in a previous version of Xcode that uses the same framework and works correctly after opening in the new Xcode 9. This previous project is still Swift using a bridging header for the same Obj-C framework. I have checked the build settings and tried to make everything match, but I get the same result; the old app works but any new apps do not.
Is there a way to either: find out the exact differences in build settings/compilers to see what the elusive difference may be, OR to step into the IOCreatePlugInInterfaceForService IOKit method to see what may be causing the error to be returned in one project but not another?
EDIT: Here is the method that is failing:
- (BOOL) createDeviceInterfaceWithError: (NSError **) error_; {
io_name_t className;
IOCFPlugInInterface ** plugInInterface = NULL;
SInt32 score = 0;
NSError * error = nil;
BOOL result = NO;
mDeviceInterface = NULL;
NSXReturnError(IOObjectGetClass(mHidDevice, className));
if (error)
goto done;
NSXReturnError(IOCreatePlugInInterfaceForService(mHidDevice, kIOHIDDeviceUserClientTypeID,kIOCFPlugInInterfaceID,&plugInInterface,&score));
if (error)
goto done;
//Call a method of the intermediate plug-in to create the device interface
NSXReturnError((*plugInInterface)->QueryInterface(plugInInterface, CFUUIDGetUUIDBytes(kIOHIDDeviceInterfaceID), (LPVOID) &mDeviceInterface));
if (error)
goto done;
result = YES;
done:
if (plugInInterface != NULL)
{
(*plugInInterface)->Release(plugInInterface);
}
if (error_)
*error_ = error;
return result;
}
In the old version that works, IOCreatePlugInInterfaceForService always returns a value of 0. In all the versions that don't work, the return value appears to always be -536870210. The mHidDevice in this function is the io_object_t handle for the device.
EDIT2: Here is the IORegistryExplorer page for the device
Finally managed to resolve this after weeks of head scratching. The new Xcode 9 uses app sandboxing to basically prevent access to USB, bluetooth, camera and microphone etc. by default in a new app. Once I switched this off it reverted to it's expected behaviour.
Glad it was such a simple answer in the end but disappointed Xcode does not provide more descriptive error messages or responses to let a user know they are essentially preventing themselves from accessing the parts of the system they need.
Looks like kIOReturnNoResources is returned if the loop at the end of IOCreatePlugInInterfaceForService completes with haveOne == false for whatever reason. Perhaps Start() is returning false because another process or driver already has exclusive access? I'd check what clients the device has in IORegistryExplorer.
This error also happens when an application is trying to access the camera or bluetooth on MacOS 10.14 and higher. Permission shall be granted either explicitly by user (pop-up window), or through the Security & Privacy. The application should check for permission as shown here.

How to calculate Voice and Data usage in BlackBerry 10 application

Hi I am developing an application in BlackBerry 10 platform which will calculate data usage and voice usage of user device for particular duration.
There are some of the feasibility check need to be done for this which are as follows
Does BB10 API supports data usage calculation? If yes, Can I differentiate 3G/Cellular data from WiFi data?If yes, how can I achieve this?
How can I calculate Voice usage in BB 10 application? Voice usage is nothing but duration of all calls happened within particular timespan
Is there any API BB10 provides through which I can check if device is currently in Roaming or not?
Please let me know if this can be done in BB 10 application
Does BB10 API supports data usage calculation?
Yes, there are a few for API's for this
Can I differentiate 3G/Cellular data from WiFi data?
Yurp you can.
1) Add the following line to your .pro file:
LIBS += -lbbdevice
2) Make sure you include:
#include <bb/device/NetworkDataUsage>
3) Getting data useage for cellular network only
bb::device::NetworkDataUsage *nduCell = new bb::device::NetworkDataUsage("cellular0");
nduCell ->update();
quint64 bytesSent = nduCell ->bytesSent();
quint64 bytesReceived = nduCell ->bytesReceived();
4) Getting data useage for wifi only
bb::device::NetworkDataUsage *nduWifi = new bb::device::NetworkDataUsage("tiw_sta0");
nduWifi ->update();
quint64 bytesSent = nduWifi ->bytesSent();
quint64 bytesReceived = nduWifi ->bytesReceived();
That will give your the data useage since the device has started.
You will need to call ndu->update() regularly to get the most recent data usage statistics.
Extra Info:
Changing the parameter for the NetworkDataUsage changes the interface it minitors:
cellular0 == Cellular
tiw_sta0 == Wifi
ecm0 == USB
To find out which interfaces are available on your device:
1) Add the following line to your .pro file:
QT += network
2) Make sure you include:
#include <QNetworkInterface>
3) Displaying available interfaces
QList<QNetworkInterface> interfaces = QNetworkInterface::allInterfaces();
for (int i = 0; i < interfaces.size(); i++) {
qDebug() << QString::number(i) + ": " + interfaces.value(i).humanReadableName();
}
How can I calculate Voice usage in BB 10 application? Voice usage is nothing but duration of all calls happened within particular timespan
This can be done using Phone class.
There is signal call void callUpdated (const bb::system::phone::Call &call, ) using which we can get to know if incoming call is received or outgoing call is initiated.
With the combination of this and Timer class we can calculate Voice usage of device. (This code is not tested)

Accurately reading of iPhone signal strength

There are a few questions on this already, but nothing in them seems to provide accurate results. I need to determine simply if the phone is connected to a cell network at a given moment.
http://developer.apple.com/library/ios/#documentation/NetworkingInternet/Reference/CTCarrier/Reference/Reference.html
This class seems to be documented incorrectly, returning values for mobileCountryCode, isoCountryCode and mobileNetworkCode where no SIM is installed to the phone. carrierName indicates a 'home' network or a previous home network if the phone has been unlocked.
I also looked up and found some people claiming the following to work, which uses an undocumented method of the CoreTelephony framework, but the results have been useless to me, reporting seemingly random figures, where perhaps it is not itself updating consistently.
-(int) getSignalStrength
{
void *libHandle = dlopen("/System/Library/Frameworks/CoreTelephony.framework/CoreTelephony", RTLD_LAZY);
int (*CTGetSignalStrength)();
CTGetSignalStrength = dlsym(libHandle, "CTGetSignalStrength");
if( CTGetSignalStrength == NULL) NSLog(#"Could not find CTGetSignalStrength");
int result CTGetSignalStrength();
dlclose(libHandle);
return result;
}
Thanks.
Edit: The app is connected to an internal wifi and must remain so, making a reachability check more difficult.
I'm playing with this function and I've noticed you're calling it in an interesting way. I'm calling it by adding CoreTelephony.framework as a compile-time link. For the function itself, you'll want to declare it's prototype somewhere (perhaps immediately above the method you call from):
int CTGetSignalStrength();
This needs to be declared since it isn't in a public header for CoreTelephony.
Now, I built a simple app that prints signal strength every second.
int CTGetSignalStrength();
- (void)viewDidLoad
{
[super viewDidLoad];
while (true) {
printf("signal strength: %d\n", CTGetSignalStrength());
sleep(1);
}
}
I ran it on my iPad mini and it shows steady values until I picked it up, where the number went up. Wrapping my iPad in tin foil (tin foil is a debugging tool I have never used before) caused the number to go down. When I put my iPad in airplane mode, it kept repeating the last value, so this will not be an accurate measure for you.
If you want to test if a device currently has a cellular data network connection, you may be more interested in Reachability, specifically kSCNetworkReachabilityFlagsIsWWAN.
Ok I think I have the correct solution now, which was a bit simpler in the end.
The issue with the CTGetSignalStrength() method is that it works normally, but if you remove a sim, it reports the last signal before the removal. I found another method in the same framework called CTSIMSupportGetSIMStatus(), also undocumented, which can tell you if a SIM is currently connected. Using both as follows should confirm the current network signal.
First declare the methods:
NSString * CTSIMSupportGetSIMStatus();
int CTGetSignalStrength();
Then check connectivity to cell network like so:
NSString *status = CTSIMSupportGetSIMStatus();
int signalstrength = CTGetSignalStrength();
BOOL connected = ( [status isEqualToString: #"kCTSIMSupportSIMStatusReady"] && signalstrength > 0 );

iPhone SSID Check is Unreliable

My application requires the user's iPhone to be connected to a 3rd party hardware device which broadcasts an SSID containing the Product Name (always the same) followed by a Unit Number (i.e. ProductName_123); essentially a Captive Network. Before allowing users to interact with my application, I ensure that the iPhone is currently connected to an appropriate SSID. I do so with the following method (I have obfuscated the product name for privacy reasons):
- (BOOL) connectedToHardwareDevice
{
/* Retrieve Interface Information */
CFArrayRef myArray = CNCopySupportedInterfaces();
CFDictionaryRef captiveNtwrkDict = CNCopyCurrentNetworkInfo(CFArrayGetValueAtIndex(myArray, 0));
/* Put network information into an iterable dictionary */
NSDictionary *dict = ( NSDictionary*) captiveNtwrkDict;
NSString* ssid = [dict objectForKey:#"SSID"];
/* Look for the Hardware Device name in the SSID */
rangeOfString:#"ProductName"].location == NSNotFound || ssid == NULL)
{
return false;
}
else
{
return true;
}
}
In my iPhone Wireless Network settings, I have declared a static IP for my testing device, which hastens the connection procedure as DHCP is avoided. However, often times I will open the application and be prompted with my "Not Connected" alert, which is triggered by the aforementioned method returning false. I find this exceptionally strange, considering I update a text field in a view with the current SSID, which will usually be correct despite the alert being shown.
My questions are as follows: Is there a more reliable means to achieve my goal? Am I going about this incorrectly? Is there some part of my method I could change in order to have more reliable results?
Thank you! If any additional information is required, please don't hesitate to ask!
My solution is to run the method again until a counter hits 20. If the counter hits 20 and the SSID is still not a match, then assume the user isn't connected to the hardware device and enter the "wait for WiFi connection" loop. This may not be the most graceful, but it works.

iOS: How to ascertain the CPU type, e.g. A4 or A5, or instruction set architecture arm6 or arm7?

Does Apple provide an API that gives access to this information?
Does the ARM have an equivalent to the x86 CPUID instruction that I could use in an asm block?
Thanks.
Erica Sadun has written a number of useful queries. I would begin checking out the uidevice extensions code and see if you can find what you are looking for there.
https://github.com/erica/uidevice-extension
Also, as Gapton says, keep in mind that some device queries will not get App Store approval, especially the unpublished ones, but a fair number of them are okay to use.
I need CPU model info and instruction set. So I try to do it as simple as possible:
std::string GetCPUModel()
{
// you can compare results with https://www.theiphonewiki.com/wiki/List_of_iPhones
struct utsname systemInfo;
uname(&systemInfo);
std::string version(systemInfo.version);
size_t cpuModelPos = version.find("RELEASE_");
if (cpuModelPos != String::npos)
{
// for example: will return "ARM64_S8000" - for iPhone S6 plus
return version.substr(cpuModelPos + strlen("RELEASE_"));
}
return {};
}