iphone dlopen
Several months ago I wrote a post about how to use dynamic framework loading in iPhone development. Here is the link (no I'm not using wordpress, that is an old experiment and Pages is way easier than anything else available right now). That post is still receiving lot of traffic, some comments, and I'm still receiving emails from developers asking about information about the code or help. The post has also been copied (and pasted :D), but that's another story. I thought it's about time to add answer some of the questions and tell interested developers how to update that code to run with the new iPhone OS 3.0.
First of all, this is a snippet of code that loads the WiFiManager private framework, which replaced the Apple80211 framework (the full version is available for download here, be aware it's compiled against 2.0 and you need to make some changes to make it run):
void *libHandle;
void *airportHandle;
int (*open)(void *);
int (*bind)(void *, NSString *);
int (*close)(void *);
int (*associate)(void *, NSDictionary*, NSString*);
int (*scan)(void *, NSArray **, void *);
libHandle = dlopen(”/System/Library/SystemConfiguration/WiFiManager.bundle/WiFiManager″, RTLD_LAZY);
open = dlsym(libHandle, “Apple80211Open”);
bind = dlsym(libHandle, “Apple80211BindToInterface”);
close = dlsym(libHandle, “Apple80211Close”);
associate = dlsym(libHandle, “Apple80211Associate”);
scan = dlsym(libHandle, “Apple80211Scan”);
as you can see, the location of the WiFiManager private framework is hardcoded in the dlopen call, and that is what makes this code prone to failure after OS update. We hope long life to that line of code, but don't take it for granted. (For the new location of the WiFiManager framework many thanks to Russ McBride from University of California, Berkeley).
Another point that generated lot of thoughts and discussions is the RSSI value (Received Signal Strength Indication). The RSSI value gives information about the signal strength as well as about the CTS (clear to send) signal. Different companies use different range for representing the signal strength. The scan call returns a NSArray of NSDictionary, each one with all the details regarding a wireless connection detected. IIRC, when I wrote that sample code, the RSSI value was between 0 and 50. Based on several comments and emails received, I stick with the idea that iPhone OS 3.0 maps the RSSI value between -100 and 0.
One of the most interesting discussion has been about how to connect the device to a detected network. And I found it hilarious that all the developers I've spoken (including me) faced the same error. The associate call does exactly the job. It takes the airportHandle, the NSDictionary that describes the network and the password. WEP and WAP network are supported. In case of free wifi network, the right call to do is the following:
associate(airportHandle, someNetworkDictionary, nil)
and note the nil instead of an empty string.
And let's get to the AppStore. Several developers asked how I made into the AppStore since the dynamic loading of private framework and of any general libraries is not allowed. I don't know where they got such information, but the code I posted and made available to download is only a pure demonstration. It's not in the AppStore and it won't be in the future, maybe. An application called WiFi Checker by Lars Bergstrom is in the AppStore (with > 1 million downloads) and it uses the described technique. How did he do? I don't know. But it stopped working after 3.0 OS release and it looks like the update is pending in the queue since June.
Dynamic loading is an interesting technique. It allows to do a lot of cool stuff that people using the SDK don't even think about. But in case you are interested in it, you should think about going on Cydia Store or just share the code in some other way.