blog.lukhnos.org

Reachability Support in LFWebAPIKit

LFWebAPIKit is the HTTP component that powers ObjectiveFlickr. It is also the web API library we use in our products and client projects. We don't use NSURLConnection because of its various issues.

Yesterday we've also completed adding reachability support to LFWebAPIKit. You can check out ObjectiveFlickr's latest source code to find it. I've also supplied two sample apps, one for iPhone, and one for Mac.

Most iPhone developers, I believe, first run into Apple's own Reachability sample code (iPhone Developer Program login required). I also believe many have found trouble with it, as we had.

The problem is that Apple's code does not tell you what they really mean by "reachable". Or to be more technically precise and correct, "being reachable" is probably not we have in mind when we come upon it. We usually need to know:

  1. If there is a network interface
  2. The type of the network (on iPhone—is it WiFi or WWAN [cellular network])
  3. Most importantly, for most of us, if an HTTP connection can be made to a destination host, and if we can get some response from it

The Reachability API on both iPhone and Mac, as part of the System Configuration framework, can actually answer the first two questions. The problem is the third question: You'll really have to make an HTTP request to know that. And no, simply telling the Reachability API to try to reach the IP address of the destination host will not work. The Reachability API is about network interface availability and the potential capability to connect, not about whether you have a valid IP address or whether you can really make this or that connection.

To put it in another way (despite much less technically precise), consider this simple fact: Any working interface will be able to reach 127.0.0.1, but whether an HTTP request send to it depends on whether you have a working server on your own local machine. In theory any Internet-capable interface is capable to reach any valid IP address, routing rules and other setups permitting. Whether a request can really made over such potential is another issue you have to test with other means.

The LFSiteReachability API supplied in LFWebAPIKit is a much simplified library that encapsulates the above three queries. To know if any network interface exists, call -connectivityExists and it immediately returns a BOOL value. And call -startChecking to start receiving updates on interface availability and HTTP request result.

By default, the host is set to google.com. A HEAD request is sent there whenever network interface status changes (it's also sent if the interface is available from the very beginning). Only when the request succeeds will your delegate receives the "reachable" status you really want to hear. You can change both the site's URL and the timeout for such test.

Update: Do try out the sample app (under LFWebAPIKit/Tests/SiteReachability-iPhone) on your iPhone. Run the app with only 3G/Edge, turn the debug log on (in LFSiteReachability.m) then pull out the SIM card in your iPhone then put it back, then you'll see why there's such need. When your SIM card is put back, your iPhone will shortly tell the app that 3G/Edge network is available and "reachable". But that's far away from being able to send real HTTP request with that. It usually takes a dozen of seconds before your 3G/Edge network really resumes working after the SIM card is back in place.