Mobile Connectivity in iOS Apps

For any smartphone user, one of the worst things that can happen is to lose cell coverage. Regardless of when it happens, it usually occurs during a call or when you need to look something up on the internet.

As mobile app developers, we have faced this problem for many years. Even the simplest of apps typically need an internet connection even if it is to only display an iAd. More sophisticated apps may need an internet connection to store data back in the cloud, whether it is a high score for a game or enterprise data logged by the CEO. Let’s take a step back and look at the current state of mobile connectivity in iOS apps.

How do you check for the connected state in iOS?

Mobile connectivity is something that Apple addressed early on with it’s Reachability library. It uses the System Configuration framework to monitor the network state of your iOS application. To get set up, you will first need to download the sample code and add the SystemConfiguration.framework to your iOS app as shown in Figure 1.

Figure 1 : SystemConfiguration.framework should be added to your project under "Linked Frameworks and Library".

Figure 1 : SystemConfiguration.framework should be added to your project under “Linked Frameworks and Library”.

Once added, only include the Reachability.h and Reachability.m files in your project that you downloaded earlier and don’t forget to import the Reachability.h file in your ViewController.

A very simple sample to test for internet connectivity when your application launches is found in the viewDidLoad method of your current view. You could use the following code to determine if the user has an internet connection or not:

- (void)viewDidLoad
{

[super viewDidLoad];

Reachability *networkReachability = [Reachability reachabilityForInternetConnection];
NetworkStatus networkStatus = [networkReachability currentReachabilityStatus];
if (networkStatus == NotReachable) {
    NSLog(@"Cannot find internet...boo!");
} else {
    NSLog(@"Found internet....yea!");
}
}

When you check your debug window, you should see a message similar to the following if you have an internet connection:

2014-07-15 10:37:11.672 MobileConnectivity[7509:60b] Reachability Flag Status: -R -----l- networkStatusForFlags
2014-07-15 10:37:11.672 MobileConnectivity[7509:60b] Found internet....yea!

If you switch back to the Reachability sample project and take a look at the APLViewController.m file file you will see more sophistated samples such as: changing the host name of the server you wish to monitor; determining if a network connection changes; and how to dectect which type of network they are connected to, whether it be WiFi, WWAN, etc. I’m not going to go into those in detail as the code is already provided, but we will find out shortly that the community has greatly enhanced the Reachability project to make it simplier to use… but first let’s talk about some best practices.

What are some best practices for dealing with this?

From trial and error, I’ve created a list of best practices that I use personally in my own apps for addressing connectivity.

1. Make use of network changed notifications

Throughout your app’s lifecycle, the internet connection can change. Your user can be driving through a poor coverage area and lose their cell signal or enter a building that has very little cell coverage. Your app needs to be able to monitor these changes and react accordingly.

If you look at the Reachability sample project again and take a look at the APLViewController.m file file, you will see a comment with the following line:

/*
 Observe the kNetworkReachabilityChangedNotification. When that notification is posted, the method reachabilityChanged will be called.
 */

The code sets up a notification that reacts with the various states of internet connectivity that your app may experience as shown in Figure 2. This is extremely helpful in our second point listed below.

Figure 2 : Disconnecting my computer from the internet then reconnecting.

Figure 2 : Disconnecting my computer from the internet then reconnecting.

2. Think about your end-users’ experience first.

The goal is to make the end-users’ experience the best possible if they lose connectivity. If you are using iAd, then simply toggle the visibility of the ad to invisible. If you are writing a line-of-business app that collects data, then make sure the data is persisted locally on the device after each change. If you are displaying data from the web such as an image or site, fill the content with a non-intrusive message such as “Cannot Connect to the Internet” as shown in Figure 3 or “Check internet availability”.

The key takeaway here is to always have the end-users’ experience in mind. They don’t want to enter data twice or to think that there is a problem with your app when it is actually because they don’t have an internet connection.

04


Figure 3 : Hide the iAd and inform your user of the disconnected state. Figure 3 : Hide the iAd and inform your user of the disconnected state.

3. Preserve bandwidth on cell signals.

You have the ability to determine if your end-user is on a cellular signal or Wifi. If you create an app that needs to download large amounts of data, then wait until they are on an Wifi connection. Not only will it save your end-users’ data plan, but it will also preserve battery life. You should also do tthe same when uploading large amounts of data, waiting until a Wifi signal is detected.

Are there any good open-source projects that help with mobile connectivity?

While Apple’s own Reachability library is easy to work with, it does not support GCD (Grand Central Dispatch), which allows for concurrent code execution on multicore hardware for iOS and OS X. Forunately for us, there are open-source projects that will allow us to work with GCD as well as write-cleaner code. One such library is Tony Million’s Reachability.

How to Use It

  • Add SystemConfiguration.framework to the linked frameworks and libraries as you did before.
  • Copy both the Reachability.h and Reachability.m files to your project.
  • Import the Reachability.h file into your ViewController.

We can then use the following code to not only check if we have internet access, but also listen through our app’s lifecycle for connectivity.

- (void)testInternetConnection

{
    __weak typeof(self) weakSelf = self;
    internetReachable = [Reachability reachabilityWithHostname:@"www.google.com"];

// Internet is reachable
internetReachable.reachableBlock = ^(Reachability*reach)
{
    // Update the UI on the main thread
    dispatch_async(dispatch_get_main_queue(), ^{
        //Make sure user interaction on whatever control is enabled
    });
};

// Internet is not reachable
internetReachable.unreachableBlock = ^(Reachability*reach)
{
    // Update the UI on the main thread
    dispatch_async(dispatch_get_main_queue(), ^{
        UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"No network connection"
                                                        message:@"You must be connected to the internet to use this app."
                                                       delegate:nil
                                              cancelButtonTitle:@"OK"
                                              otherButtonTitles:nil];
        [alert show];

        //Make sure user interaction on whatever control is disabled
    });
};

[internetReachable startNotifier];
}

Looking at this code, we can see that we are checking to see if google.com is available and if it is we use GCD to give the developer the option to enable user interaction on a control. If it cannot find a valid internet connection, then is displays a UIAlertView and gives the developer the option to disable any controls the user may interact with. The last line starts the notifier that will call this method again if the user loses internet connectivity during the lifetime of the app.

A sample of this is shown in Figure 4, where I enabled and disable a TableView (containing my RSS feed)when I lost internet connectivity.

Figure 4 : Tony Million's Reachability in action.

Figure 4 : Tony Million’s Reachability in action.

Introducing our Data Sync Framework (Beta)

Update 10/24/16: The Data Sync framework is no longer a supported option.


Telerik’s Data Sync Framework tackles this problem two-fold.

  1. It persists application data locally using SQLite and has the ability to synchronize and store data across devices using our back-end services.
  2. Changes to your data made offline, can be synced manually or automatically once your app is online again. The component is also smart enough to determine if the data should be synced over 3G or a WiFi connection. Again, this is done without any additional plumbing code that you have to write.

How do we use it:

  • Download Telerik UI for iOS and add TelerikUI.framework, SystemConfiguration.framework and libsqlite3.0.dylib to the linked frameworks and libraries in your project properties.
  • Import the Telerik framework into your ViewController.
  • Refer to Telerik’s help documentation to learn how to implement the data sync functionality in your app.
  • Examine the snippet provided below as it shows how easy it is to hook into our backend service:
      TKEverliveClient* everliveClient = [TKEverliveClient clientWithApiKey:self.apiKey
                                                            accessToken:self.accessToken                                                                  serviceVersion:@1];
    
      TKDataSyncReachabilityOptions options = TKSyncIn3GNetwork | TKSyncInWIFINetwork;
      TKDataSyncPolicy* thePolicy = [[TKDataSyncPolicy alloc]         initForSyncOnDemandWithReachabilityOptions:options
                                                                                      conflictResolutionType:TKPreferLocalInstance
                                                                                              syncTimeout:100.0];
    
      _theContext = [[TKDataSyncContext alloc] initWithLocalStoreName:@"localGameDb"      cloudService:everliveClient  syncPolicy:thePolicy];
    
      [_theContext setDelegate:self];
    
      [_theContext registerClass:[VideoGame class] withPrimaryKeyField:@"gameId"      asAutoincremental:NO];

This code creates a TKEverliveClient instance passing in the apiKey and accessToken for the current user. Then sets up the TKDataSyncPolicy options and initializes the TKDataSyncContext with our everliveClient credentials as well as the synchronization policy we defined earlier. It also registers the class that holds the fields that we wish to persist.

Note: The full source for the demo shown below can be found on Github.

In Figure 5, we are going to persist two fields, one called gameID and the other gameTitle. We have two buttons to add an item locally and another button that will sync all the items that are not stored in the backend service (but are still persisted locally). After adding an item, we will display it in our backend service, then disconnect from the internet and add several more items then reconnect to the internet and sync manually.

Figure 5 : The Data Sync Framework in action.

Figure 5 : The Data Sync Framework in action.


Conclusion

Today we looked at several ways that iOS developers can check for mobile connectivity in their iOS apps. Who would have thought that mobile connectivity could be so complicated, yet so easy to handle with the proper libraries. From Apple’s own Reachability and community contributions to it, to Telerik’s fully featured data sync framework – you have plenty of options at your disposal. Whatever library you choose, you will want to make sure that you implement the best practices so that your users come back to not only your current app, but apps you create in the future!

Comments

  • Khushbu Mahavadia

    Good solutions