Detecting network connections in AIR

One of the biggest benefits of AIR is that applications can be written to easily function whether online or off. Features like file access and a local SQL database give developers the functionality they need to write applications that can pull data from remote data sources while connected, but can also rely on cached data while disconnected. Of course, writing an application that functions seamlessly both online and offline requires that you be able to reliably detect whether you have a connection or not. This article will tell you everything you need to know to reliably determine not only if your application is connected or not, but also whether it can reach the services it requires.

Let me start by saying that this isn’t as simple and straightforward as it might sound. In fact, in today’s world of VPNs and 3G wireless networks and virtual network interfaces, it’s actually pretty complicated. We didn’t realize how complicated it was until early on in AIR 1.0 development when the engineer who was responsible for the online/offline functionality in the runtime gave me a build to test. I started writing an application that needed to know whether it was connected or not, and the first time I yanked my network cable out, we were surprised to find that it didn’t work as expected. The cable was disconnected, my AirPort card was turned off, but for some reason, my computer (and the AIR runtime) thought it was still connected. After some investigation, we realized that the problem was a couple of virtual network interfaces that Parallels set up in order to be able to manage networking between OS X and Windows.

What ensued was an almost philosophical discussion about what it meant to be online and offline. Theoretically, my application might have been trying to talk to a service on my Windows virtual machine which would have meant that my computer actually was connected even though I pulled my cord out. Or I might have had an internet connection, but the server my application needed to talk to might only be accessible while connected to a VPN. Or I might be on a public network that blocks certain services, packets, or ports that my application relies on in order to access data. Or you might be sitting in an underground concrete bunker with no connection to the outside world whatsoever, but you’re developing an application the retrieves data from a server running on your local computer which means, from the application’s point of view, it’s online.

We eventually arrived at the conclusion that there really is no such thing as online or offline, or at least no simple and practical definition that worked for AIR developers, and that meant there was no way we were going to get away with a simple online/offline API (the first version of this API allowed for the simple registration of online and offline events on the static NativeApplication instance). In fact, we realized that it doesn’t even matter if you’re online or not which meant we were trying to answer the wrong question. All that matters is whether you can successfully access a particular service. And to figure that out, we were going to have to deliver a couple different APIs, and probably some best practices around using them.

The two APIs we decided to deliver with the runtime are the networkChangeEvent, and the ServiceMonitor class. You register for networkChangeEvents on the NativeApplication static instance. Each time a networkChangeEvent is thrown, you know that network connectivity has somehow changed, but you don’t know how it’s changed. For instance, the user might have connected, disconnected, logged into a VPN, joined a wireless network, etc. That’s where the ServiceMonitor class comes in. Since we determined that there really is no absolute concept of online or offline, you can use the ServiceMonitor class to tell you something which is much more interesting: whether or not you can actually reach a specific service.

The ServiceMonitor class has two subclasses: SocketMonitor and URLMonitor. The SocketMonitor is for monitoring services that you connect to directly with a TCP socket like a mail or an XMPP server. The URLMonitor class is for monitoring HTTP services like REST based services. Both can be configured to listen for networkChangeEvents for you, or they can can be activated manually by calling the checkService method. Both also have various ways to configure them to work with your specific service. The service event thrown by the ServiceMonitor has a code property which indicates whether or not communication with the service was successful.

This is a pretty complete solution, but there’s still one more scenario that we haven’t accounted for. Let’s say the end user plugs in a network cable which causes the networkChangeEvent to fire which, in turn, causes the ServiceMonitor to check the state of the service. And let’s say the service responds favorably which causes the ServiceMonitor to throw its status event with a code property of "service.available". Your application responds by showing a big green light indicating to the end user that all is well, and that it’s safe to submit data to or pull live data from your remote service.

The problem is that the service might go down between the time you last checked it and the time your application needs to interact with it. Or your ISP might have suddenly gone out of business. Or an underwater transatlantic cable could have been cut. Any number of things could prevent your application from successfully talking to its services. The ServiceMonitor can’t help you now, so it’s up to you to catch the IOErrorEvents and handle them gracefully. Since I typically use the Cairngorm Flex framework, I have a single boolean property in my ModelLocator called online which any part of my code can access. I set the online property inside of my ServiceMonitor event handlers and also within my IOErrorEvent handlers, as well (and I also set it to true every time I successfully interact with a service). That way, whether the end user has no connectivity or the service the application is trying to access is down, the application behaves consistently and appropriately.

Of course, having a robust solution to reliably determining whether you’re online or not is only half the challenge since your application also has to know how to behave in both circumstances. Writing a complete online/offline application is beyond the scope of this article, but I will say that hinging application logic on the ModelLocator’s online property is the key. If you want a detailed real-world example, I recommend taking a look at Lineup, my Exchange calendaring application. It works both online and off, and demonstrates all the principles described in this article.