Mobile

Android Intents with Kotlin

This past fall, I became part of the Ray Wenderlich tutorial team for Android. As part of that team, we are updating the existing Android tutorials using Kotlin along with the latest Android tool set. My first assignment was to update the Intents tutorial.

What is an Intent you ask? Well, Intents and Intent Filters facilitate communications between app components, allowing things like starting an activity, starting a service, or delivering a broadcast.

In the Intents tutorial, you’ll learn the following:

  • What an Intent is and what its wider role is within Android.
  • How you can use an Intent to create and retrieve content from other apps for use in your own.
  • How to receive or respond to an Intent sent by another app.

The updated version of the tutorial can be found here: https://www.raywenderlich.com/171071/android-intents-tutorial-kotlin

Advertisements

Mobile App Development: Consider the Cost, Not Just the Price!

This article was originally posted on my companies blog site found here

Introduction

When we are talking to customers, either new or existing, we often get asked about the best way to develop mobile apps for both Android and iOS. For many years the options were native versus hybrid. More recently these options have become more complex. The typical reason we get asked this question is that companies are looking to reduce the price of mobile app development. We feel that there is much more to consider in this decision than just the price of development, it’s the true cost that needs to be understood.

At Chariot Solutions, our Mobile Practice focuses on native application development. We didn’t start out with that approach. We worked on native and hybrid apps for our clients. What we have learned over the years is that native simply works best. Sure, for very simple, basic mobile apps it might be worth considering an alternative approach. But we have consistently found that apps that start as hybrid end up suffering from shortcomings that result in sub-optimal user experience or require significant work arounds and even potentially complete re-writes. Based on these experiences, we prefer to focus our efforts on native development resulting in a highly performant, beautifully designed mobile application for our client’s users.

What is Native, Cross Platform, and Hybrid

In order to understand all the aspects of deciding what direction to go with your mobile app development approach, it is important to understand each option and the advantages and trade-offs each has to offer.

At a very high level, native applications are written in a programming language supported by the platform provided SDKs (Software Development Kits). Hybrid and cross platform applications are written in essentially a single programming language and use framework provided software layers to allow developers to generate a user interface and provide access to underlying device features. While this sounds good on paper, the diagram below demonstrates the additional complexity that comes along for the ride.

The following sections provide more detail around the different mobile application development approaches.

Native Mobile Approach

Native mobile apps are written with platform specific languages to directly access the manufacturer provided SDKs.  For iOS, this means writing in either Objective-C or Swift, and for Android the language options are either Java or Kotlin.  Within iOS and Android, each of their supported languages interoperate with the other.

Pros

  • It is not possible to exceed the performance of a natively developed application.
  • Immediate access to all platform features via native SDKs (e.g. bluetooth, AR, machine learning, etc.).
  • The similarities between Apple’s Swift and Android’s Kotlin languages make it much easier to cross-train developers and to port the application code between the two platforms
  • More mature tooling in terms of UI development, debugging, and profiling
  • Easier to support multiple device sizes and orientations through the use of provided tooling
  • Built in support for non-phone device types (wearables, TV, Car, etc.)

Cons

  • Developers need to be familiar with different tool sets
  • Two languages to learn when cross training developers
  • Maintaining two code bases

Hybrid Approach

Hybrid applications are written using HTML, JavaScript, and CSS, which is then wrapped in an application container that allows it to be treated as an app by the device.  It is essentially a browser-based web app wrapped for the ability to access device features like local storage, bluetooth, and push notification support.  One programming language is used to build the app, which is then wrapped for deployment and distribution.  Examples of hybrid frameworks include PhoneGap, Sencha Touch, and Ionic (built on top of PhoneGap).

Pros

  • One programming language to learn
  • Shared code for business logic
  • The same developers and code modules could be re-used for web development.  This is a comment we hear often, but rarely works in practice.

Cons

  • Sub-optimal UI performance
  • Reliance on frameworks and the support they will have moving forward
  • Frameworks are so numerous and evolve so quickly that code written 2-3 years ago can become obsolete and riddled with security and performance issues
  • Difficulty in integrating new versions of the frameworks
  • There are more layers of software in the application, which makes debugging and troubleshooting more difficult
  • Tooling is less sophisticated
  • UI/UX tends to blur between iOS and Android, or forces code branching (i.e. if android do this, else do that) throughout the code base in order to differentiate each of the user experiences
  • User Experience can suffer if you decide to stick with common design patterns from one platform; Android users sometimes get offended if your app looks like an iOS app or vice versa.
  • Plugins required to access native OS/device features, which might require a native developer to implement
  • Delayed availability of new platform SDK features

Native Cross Platform Approach

This category is also referred to as just “Cross Platform.”  Mobile applications are written using a single language (e.g. JavaScript, C sharp), and use framework provided APIs to access the underlying native SDKs.  UI components provided by the framework get translated into native UI widgets, allowing close to native application UI performance levels.  While there are numerous frameworks available, currently, the most popular native cross platform frameworks are ReactNative (written using JavaScript) and Xamarin (written using C#).

Pros

  • One programming language to learn
  • Shared code for business logic
  • Near native UI performance

Cons

  • The same cons as hybrid, plus the following
  • Steep framework learning curve.  While there is a learning curve for native, that skill will still be required when using a cross platform approach.  More on that later.
  • Reliance on the framework providers to continue to exist and evolve along with the native platforms

Mobile App Development Considerations

Now that we understand what each option actually represents, we need to look at the various considerations that go into choosing a mobile app development approach. Most of these considerations go beyond the “development cost” that people speak about. These include things such as the importance of mobile to the overall business strategy and goals, what platforms are really required by your user base, how complex the app is for both business logic and user experience, and the developers you have on staff. Below is a high level comparison of each approach, with the underlying details following the table.


Business Strategy

If your mobile applications are core to your business, then the only real option to consider is native. The user experience quality and performance obtained when developing a fully native app simply isn’t achievable with the other options. How is mobile core to your business when you don’t have a mobile product? As an example, one of our clients is in the home security space. Their main focus is the security system and its sensors and cameras. But the mobile applications provide the user the ability to control the system as well as providing a view into its current state. This makes mobile core to their business. Maximizing UI performance is critical to the user’s happiness and therefore the success of their product.

Platform Requirements

One of the first questions businesses need to ask about their mobile apps is “Who are the users?” In some cases the answer is “90% of the user’s have iOS devices”. One of our clients came to us with a hybrid application that was suffering with significant performance and usability issues. Their clients all used iOS devices (iPads). For their initial version, they chose hybrid “in case they need to support Android someday.” Our recommendation to them was to develop an iOS app optimized for the platform and taking full advantage of what it has to offer. If an Android app is needed somewhere down the road, given the similarities between Apple’s Swift and Android’s Kotlin, it’s pretty straightforward to port the app over.

Another consideration with respect to platform support is access to device specific features. A good example of this is augmented reality (AR). Apple introduced AR to their SDK with the release of iOS 11. Native apps that want to take advantage of this capability could access it immediately, while hybrid or cross platform apps needed either native plugins written or would need to wait for the capability to be added to the relevant framework.

Application Complexity

When it comes to application complexity, there are really two levels: UI/UX complexity and business logic complexity. UI/UX complexity can include things like compound views, custom controls, complicated transitions, the need to support non-phone device types (e.g. wearables, TV, car, etc.). The more of these types of complexity in the application, the higher the need is to take a native approach. UI/UX performance is one of the most important attributes of a mobile app. It directly impacts the user’s perception of the app and therefore the overall success of the app.

If the business logic for an app is complex, we will typically recommend moving that logic out of the app and into the cloud or some other server that can be accessed via an API for all clients, mobile or otherwise. If this cannot be done, this doesn’t mean hybrid or native cross platform is your only option. There are cross platform tools like KotlinNative, ElectrodeNative, J2ObjC, C/C++, etc. that can allow complex business logic to be written once and shared across native apps. Also, with the similarities between Kotlin and Swift, porting complex business logic from one platform to another isn’t as difficult as it once was.

Developers

The type of developers you have, or want to have, on staff is extremely important. While native cross platform and hybrid may require developers to know only one language, the reality is that platform experts are going to be required for each platform on which your app is released. There are numerous differences between the platforms in terms of what device features and functionality is available or unavailable on each. Unless you go with a full native approach, plugins will be needed to access some features. And during development, bugs and build/distribution issues will creep up. Any of these things can happen and will require deep platform specific knowledge. For good developers, language is mainly about syntax, but good platform knowledge is much more than just syntax. It’s understanding the various capabilities of each platform, their restrictions or limitations, and their UX paradigms.

In the End, We Choose Native

There are multiple options when it comes to building mobile applications.  Deciding on the proper path for your application is about more than just the line item cost of development.  Many considerations need to be assessed when determining the actual cost of development.  Ultimately you need a highly performant, beautifully designed mobile application for your users. My goal is to make sure your users have exactly that. Contact me to help you determine the right path.

UITableView Swipe Actions

Overview

One of the new but little discussed APIs in iOS 11 allows the addition of swipe actions on UITableView rows via the new UISwipeActionsConfiguration class and associated UITableViewDelegate methods. Adding swipe left or swipe right actions is now pretty simple, so lets just dive right in. To try out these new APIs, a very basic list view was created with some hard coded data. This app will allow the user to swipe right to make a row “read” or “unread” and swipe left to either “flag” a row, or “delete” the row from the list. The code for this post can be found here.

 

The UITableView delegate

The keys to adding swipe actions start with new UITableView delegate methods, defined as follows:

func tableView(UITableView,
              leadingSwipeActionsConfigurationForRowAt: IndexPath)
                                    -> UISwipeActionsConfiguration

func tableView(UITableView,
               trailingSwipeActionsConfigurationForRowAt: IndexPath)
                                    -> UISwipeActionsConfiguration

As you can see in the method signatures, these both return a UISwipeActionsConfiguration class. This class is initialized with an array of UIContextualAction classes. So let’s start at the bottom and work our way up.

 

The Details

For our sample app, we’ll create a struct called an Email. It looks like this:

struct Email {
    let subject: String
    let body: String
    var isNew: Bool
    var isFlagged: Bool

    static func mockData(numberOfItems count: Int) -> [Email] {
        var emails = [Email]()
        for idx in 1...count {
            let email = Email(subject: "Email \(idx)", body: "This is my body for email \(idx)", isNew: true, isFlagged: false)
            emails.append(email)
        }
        return emails
    }

    mutating func toggleReadFlag() -> Bool {
        self.isNew = !self.isNew
        //normally make some call to toggle and return success/fail
        return true
    }

    mutating func toggleFlaggedFlag() -> Bool {
        self.isFlagged = !self.isFlagged
        //normally make some call to toggle and return success/fail
        return true
    }
}

We will use this class to load up the table view with data. This is accomplished using the typical UITableViewDataSource methods and can be seen within the ViewController class. The real area of interest is within the UITableViewDelegate. Here we introduce the 2 new methods mentioned above.

 

Setting up the UISwipeActionsConfiguration

Let’s take a deeper dive into the trailing actions method, since it will apply more than one possible swipe action.

func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
        let deleteAction = self.contextualDeleteAction(forRowAtIndexPath: indexPath)
        let flagAction = self.contextualToggleFlagAction(forRowAtIndexPath: indexPath)
        let swipeConfig = UISwipeActionsConfiguration(actions: [deleteAction, flagAction])
        return swipeConfig
    }

Here, we are using a helper method to instantiate each of the UIContextualAction classes we will need to build our swipe actions. Then we can instantiate a UISwipeActionsConfiguration using the UIContextualAction classes to populate the actions array. The UISwipeActionsConfiguration is then returned from the delegate method.

The important thing to note here, is that the order of the items in the action array determines the order of the actions displayed when the table view row is swiped. The easiest way to remember is that the first item displays furtherest out, and subsequent items display moving towards the cell. So if we are dealing with trailing actions, the first item in the array corresponds to the rightmost action (“Delete”), the second one will be one inside of that (“Flag”), and so on.

 

Handling Contextual Actions

Next, lets take a look at the UIContextualAction. This is where the work happens. The documentation found here. The initializer takes a UIContextualAction.Style, title, and UIContextualActionHandler block. The UIContextualActionHandler gives you access to the UIContextualAction, the view that displayed the action, and a completion handler that you pass a bool indicating whether or not the action was successful. An example can be found in the contextualToggleFlagAction method shown below:

func contextualToggleFlagAction(forRowAtIndexPath indexPath: IndexPath) -> UIContextualAction {
        // 1
        var email = data[indexPath.row]
        // 2
        let action = UIContextualAction(style: .normal,
                                        title: "Flag") { (contextAction: UIContextualAction, sourceView: UIView, completionHandler: (Bool) -> Void) in
            // 3
            if email.toggleFlaggedFlag() {
                // 4
                self.data[indexPath.row] = email
                self.tableView.reloadRows(at: [indexPath], with: .none)
                // 5
                completionHandler(true)
            } else {
                // 6
                completionHandler(false)
            }
        }
        // 7
        action.image = UIImage(named: "flag")
        action.backgroundColor = email.isFlagged ? UIColor.gray : UIColor.orange
        return action
    }

In this method:

  1. We are simply retrieving the data element from our data array
  2. Instantiating the UIContextualAction class, providing a style, title and handler
  3. Mutating the object. Of course our email struct could have been a class to ease the mutation handling.
  4. Saving the mutated object back to our data and reloading the appropriate rows.
  5. Call the provided completion handler, indicating success.
  6. Had the update to the object failed, we can indicate that to the completion handler by passing false.
  7. Setting the image and color attributes on action. By specifying an image, the title in the initializer is not displayed. This certainly makes localization a bit more work, since the images would need to contain any text we wanted to display for an action, assuming we wanted both text and images.

One more thing of note is that on the UISwipeActionsConfiguration class, you can specify whether the first action in the collection should be performed with a full swipe. This defaults to true. Here is a video of the working app with both leading and trailing swipe actions.

Changing your iOS App Icon programatically

When iOS 10.3 was released, Apple opened up an API to allow developers to change the app icon for their app. Of course this doesn’t mean you can change it every second like the Clock app, or even every day like the Calendar app. What you can do is change the app icon when the app is running in the foreground, and it will notify the user with a pretty ugly system alert dialog that the icon is changing. This post will walk through the configuration and API calls to allow an app to change the app icon.

The first step is to obtain your app icon image assets. These must be .png files and you will need 2x and 3x resolutions. An important thing to consider is that you want all the proper icon sizes available so that when the icon changes it is consistent across settings, spotlight, notifications, etc.

Unfortunately, these cannot be placed in a xcassets file, however, they must be packaged in the main bundle. The source code for this post can be found here.

The next step is to configure the Info.plist file. Review the documentation for the plist file carefully. In the provided code, the plist file contains the CFBundleIcons dictionary configured as show below:

Screen Shot 2017-07-13 at 9.19.42 AM

In the CFBundleAlternateIcons dictionary, the key represents the string that will be used when making the API call to change the app icon.  You will see these used in the code samples later in this post.  The value is an array of CFBundleIconFiles.  In our case, its an array of one item, with the relative path to the filename (without extension and size modifier).  If you like to keep your files organized in both Xcode and the filesystem like me, you’ll want to store your icons in a sub folder within your project, so it’s important to specify the relative path, otherwise you’ll get a runtime error when trying to change icons.

Now on to the code.  The API docs can be found here: https://developer.apple.com/documentation/uikit/uiapplication/2806818-setalternateiconname.  The APIs are pretty basic.  Ideally you want to check if the app can change the app icon with something like the following:

if UIApplication.shared.supportsAlternateIcons {
    print("I can do it")
}

Then to change the icon, do something like this:

//note that the name corresponds to the key in the 
//  Info.plist CFBundleAlternateIcons dictionary
UIApplication.shared.setAlternateIconName("hockey") { (error: Error?) in
    guard let error = error else {
        print("success")
        return
    }
    print("switching icon to hockey encountered and error: \(error)")
}

Finally, to reset the icon back to the primary one by setting the name to nil:

UIApplication.shared.setAlternateIconName(nil) { (error: Error?) in
    guard let error = error else {
        print("success")
        return
    }
    print("switching icon to primary encountered and error: \(error)")
}

Simple as that. Check out the sample app and switch icons between your favorite Philadelphia sports teams 😃

Saving Blood Pressure Data to Apple’s HealthKit

While working on one of our demo mobile apps for the upcoming SXSW conference, I found the need to store blood pressure and heart rate data in HealthKit. Apple’s documentation is pretty solid and has some good examples on how to use the HealthKit framework. In this short post, I’ll walk through the code snippets required to request access to write data to HealthKit and then actually write the data.

The demo app I am working on interacts with a heart rate monitor via BLE (Bluetooth Low Energy) to capture the users blood pressure and heart rate. The mobile app can start and stop the blood pressure cuff, display measurement progress, and finally show the results captured by the blood pressure monitor. Rather than having the app store any of that data, I decided to use HealthKit to make this information available to the iOS Health App and any other apps on the device that have read access.

Requesting read/write access to HealthKit

Let’s get started with requesting access from the user to write data to HealthKit. In my app I created a class called HealthKitManager, since every app needs at least one manager class.


class HealthKitManager {

    fileprivate let healthKitStore = HKHealthStore()

    func authorizationRequestHealthKit(completion: @escaping (Bool, Error?) -> Void) {

        // 1
        if !HKHealthStore.isHealthDataAvailable() {
            let error = NSError(domain: "com.chariotsolutions.mobile", code: 999,
                                userInfo: [NSLocalizedDescriptionKey : "Healthkit not available on this device"])
            
            completion(false, error)
            print("HealthKit not available on this device")
            return
        }

        // 2
        let readTypes: Set<HKSampleType> = [HKSampleType.quantityType(forIdentifier: HKQuantityTypeIdentifier.bloodPressureDiastolic)!,
                                          HKSampleType.quantityType(forIdentifier: HKQuantityTypeIdentifier.bloodPressureSystolic)!,
                                          HKSampleType.quantityType(forIdentifier: HKQuantityTypeIdentifier.heartRate)!]

        let writeTypes: Set<HKSampleType> = [HKSampleType.quantityType(forIdentifier: HKQuantityTypeIdentifier.bloodPressureDiastolic)!,
                                            HKSampleType.quantityType(forIdentifier: HKQuantityTypeIdentifier.bloodPressureSystolic)!,
                                            HKSampleType.quantityType(forIdentifier: HKQuantityTypeIdentifier.heartRate)!]
        // 3
        healthKitStore.requestAuthorization(toShare: writeTypes, read: readTypes) { (success: Bool, error: Error?) in
            completion(success, error)
        }
    }

I created an authorizationRequestHealthKit method. This method takes a completion function to allow callers to handle success and failure of the authorization request.
Walking through the code above:

  1. First, we need to check if HealthKit is available on the device. If not, the calling code should inform the user appropriately.
  2. Even though I am not reading data in my demo app, I wanted to include the read types sample code. The thing to note here is that blood pressure data is considered correlated data, meaning multiple samples that make up a single data entry. But there is no permission for correlated data. You are asking the user to read and write specific data types, in this case diastolic blood pressure, systolic blood pressure, and heart rate.
  3. This step is where some of the magic happens. This is where we ask the user for the exact data elements we want to read and store in HealthKit. The requestAuthorization method doesn’t actually indicate whether the user is allowing access, but whether or not the request for authorization has succeeded. The nice thing here is that based of the read and write types requested, the OS will present a screen with all the relevant information and controls to allow the user to make their access decision. Also, the UI will only be presented if the user has not yet allowed access to the requested data, meaning the UI only gets presented when required 🙂

Important safety tips:

  • The requestAuthorization completion block is called on the background thread, so be aware if your blocks do any UI work.
  • You must add messages that indicate the reasons for requesting permissions from the user. This can be done in the info.plist for your app. Just add the keys NSHealthShareUsageDescription and NSHealthUpdateUsageDescription with the pertinent messages as the values.

IMG_3186

The authorizationRequestHealthKit method can then be called from wherever you need to request access to the user’s HealthKit data.

Writing the sample data to HealthKit

The next step is to actually write the data. The APIs provided for this are pretty straightforward once you see it. I added the following method to my HealthKitManager class:


func saveBloodPressureMeasurement(systolic: Int, diastolic: Int, heartRate: Int, completion: @escaping (Bool, Error?) -&gt; Void) {

        // 1
        let startDate = Date()
        let endDate = startDate
        
        // 2
        let systolicType = HKQuantityType.quantityType(forIdentifier: .bloodPressureSystolic)!
        let systolicQuantity = HKQuantity(unit: HKUnit.millimeterOfMercury(), doubleValue: Double(systolic))
        let systolicSample = HKQuantitySample(type: systolicType, quantity: systolicQuantity, start: startDate, end: endDate)
        
        let diastolicType = HKQuantityType.quantityType(forIdentifier: .bloodPressureDiastolic)!
        let diastolicQuantity = HKQuantity(unit: HKUnit.millimeterOfMercury(), doubleValue: Double(diastolic))
        let diastolicSample = HKQuantitySample(type: diastolicType, quantity: diastolicQuantity, start: startDate, end: endDate)
        
        // 3
        let bpCorrelationType = HKCorrelationType.correlationType(forIdentifier: .bloodPressure)!
        let bpCorrelation = Set(arrayLiteral: systolicSample, diastolicSample)
        let bloodPressureSample = HKCorrelation(type: bpCorrelationType , start: startDate, end: endDate, objects: bpCorrelation)
        
        // 4
        let beatsCountUnit = HKUnit.count()
        let heartRateQuantity = HKQuantity(unit: beatsCountUnit.unitDivided(by: HKUnit.minute()), doubleValue: Double(heartRate))
        let heartRateType = HKQuantityType.quantityType(forIdentifier: .heartRate)!
        let heartRateSample = HKQuantitySample(type: heartRateType, quantity: heartRateQuantity, start: startDate, end: endDate)
        
        // 5
        healthKitStore.save([bloodPressureSample, heartRateSample]) { (success: Bool, error: Error?) in
            completion(success, error)
        }   
    }

There are different type of data samples that can be written to HealthKit. Blood pressure and heart rate data is considered a quantity sample. It’s made up of a sample type, quantity, and the sample data which includes the point in time the data was taken.

Let’s breakdown the method:

  1. Since all this data is captured at one point in time, lets capture the current date as the start and end date of the sample.
  2. Here we are constructing the systolic and diastolic sample data. Both the type and quantity are used to define the sample.
  3. This is where we correlate the diastolic and systolic measurements into one sample.
  4. The heart rate sample is its own measurement. The thing of note here is that the unit of measure (beats per minute) is a combination of count divided by time.
  5. Here we save the blood pressure and heart rate measurements, with the typical completion block. An example of a failure would be if the user has not granted write access for these measurements, the completion block will get an errorAuthorizationDenied error.

That’s a quick walk through of how to write blood pressure and heart rate data to Apple’s HealthKit.

Please note that this post was also posted by me to
Chariot Solution’s blog

Using Node.js and Charles Proxy to Mock a Server API

While working on an iPhone project for a client, I came across a situation where I needed to test some error conditions returned from a server API which I have no control over.  I ended up using Charles Proxy to remote map the server API calls to a locally running Node.js server.  Of course the proper way to do this is to write functional tests and mock the networking classes to return the appropriate responses, but that is a blog post for another day.

In this post, I’ll walk through the steps to create a simple iPhone app that interacts with a public API, using Node and Charles to simulate an error response.  This post assumes some experience writing iOS code, but all the source code will be available at https://github.com/stevenpsmith/charles-node-blog.

Create an iOS App

For the iOS app, I’ll write a simple weather app that uses the OpenWeatherMap API.  We all know the world needs yet another weather app :).

Let’s start by creating a new single view project in Xcode.  In my iOS projects I almost always use CocoaPods for dependency management.  CocoaPods makes it easy to add/remove 3rd party libraries to your iOS project.  In this app, we’ll use AFNetworking to access the API, and I’ll add MBProgressHUD in case the response time is slow and the user needs to wait for UI updates. The following assumes that you already have CocoaPods installed.

After creating the Xcode project, quit Xcode (or close the project) and create a text file named “Podfile” at the root of the project.  The contents should include the following:

platform :ios, '7.0'

pod 'AFNetworking', '~&gt; 2.0.3'
pod 'MBProgressHUD', '~&gt; 0.8'

With that file in place, drop to a command line and execute pod install

That will create a workspace and configure the libraries. From this point forward, we use the workspace instead of the project. The final version of the application will look like this:

Screenshot_1_14_14__12_03_PM

The code base can be found at https://github.com/stevenpsmith/charles-node-blog, but the key portion is the API call, which is below (without all the details)

[[CSMServerAPI sharedInstance] weatherForLongitude:-75.1914 
                                       andLatitude:40.1386 
    successBlock:^(NSDictionary *weatherDict) {
        // code to map API response to UI elements here
        //...
    } failureBlock:^(NSError *error) {
        //access error message parts from response here
        //....
        NSString *msg = ...
        UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Houston - We have a Problem" 
                                                        message:msg 
                                                       delegate:nil 
                                              cancelButtonTitle:@"OK" 
                                              otherButtonTitles:nil];
        [alert show];
    }];

If everything is successful, the UI gets populated with the weather data. But, if there is a failure, we throw an alert up to the user containing the error messages (I know, alerts are not user friendly, but this is an example).

Mocking an error with Node

Now that we have the API calls in place, we need to set up our node server to fake an error response. Sticking with the theme of keeping things simple, I used the express framework for node. With node installed, I created a directory for my server app and added a ‘package.json’ file inside. The ‘package.json’ looks like the following:

{
  "name": "mock-api",
  "description": "for use with charles proxy to mock error conditions for OpenWeatherMap API",
  "version": "0.0.1",
  "dependencies": {
    "express": "~3.4.7"
  }
}

Dropping to a command line and executing npm install will set up the node server with the express module. Now we create an ‘app.js’ file and add our mock API, as follows

var express = require('express');
var app = express();

var errorJson = {error:"API Error",error_msg:"You have encountered an error thanks to Charles and Node....have a nice day!"};

app.get('/weather', function(req, res) {
  	res.json(400, errorJson);
});

app.listen(process.env.PORT || 4730);

Since our call to the OpenWeatherMap API is a get request to the /weather URI, we simply handle that request route in our code and return the response we want, which is an error containing a JSON error message. To start the server, execute node app.js at the command line and the server will be listening on port 4730.

Configure Charles Proxy for Remote Mapping

If you code against server APIs and don’t use Charles Proxy, or something like it, you really should start. It is immensely valuable for troubleshooting API calls, and the more I use it, the more nice features I find. I’ve used it for bandwidth throttling, request/response inspection, breakpoints (to change requests or responses), and now URL mapping. In order to map the OpenWeatherMap API to our local node server, access the Map Remote settings via the Tools -> Map Remote... menu. Once there, add a new remote mapping, filling out the fields as shown below. The configuration was also exported and is available at https://github.com/stevenpsmith/charles-node-blog.

Edit_Mapping_and_Map_Remote_Settings_and_Charles_3_8_3_-_Session_1

With that in place, enable remote mapping, run the iPhone app and get the following error:

Screenshot_1_14_14__11_51_AM

If you used Charles to record your network requests, you can even see the mapping occurred in the request overview notes. That’s all there is too it. You can certainly do a lot more than just simulate errors with this set up. I’ve used it to simulate server application errors as well, where server returns an http 200, but the response includes some application specific errors. Timeouts can be tested as well using the connect-timeout module. There is an example in the source code for that too.

So this is one way to intercept your API calls and modify them for testing. This is certainly no replacement for good functional tests, but simply another thing to add to your developer toolbox.

Apple’s New App Store Submission Requirements

Apple recently announced that new apps and app updates must be built with Xcode 5 and optimized for iOS 7 starting February 1st, 2014.

What does this mean?

Well, even if your app was built and released on iOS 6 and currently looks fine running on iOS 7, your next app update will change all that.  Building with Xcode 5 will now result in the app using the iOS 7 widgets when running on an iOS 7 device.  Depending on how your app was built, this could dramatically impact its user interface.  The changeover has had various levels of impact with our clients.

What should you be doing?

Build and test the application using the latest Xcode and iOS SDK.  This means test it on devices too (both iOS 6 and 7 devices).  Even if things look OK in interface builder, once you run it on the simulator and devices, things will start to look different.

Things to look for (just a sample):

  • API changes, deprecations, etc.
  • Differing control sizes and layouts (segmented controls, switches, progress views, etc.)
  • Navigation bar size differences
  • Edge-to-edge content (table views, content sliding under nav bars, etc.)
  • Status bar colors and translucency
  • Buttons
  • Images and Icons

Be aware that there are numerous way to support both iOS 7 and previous iOS versions, whether it be through auto layout, offsets, or code.  The best advice is to start planning as soon as possible.