iAchieved.it

Software Development Tips and Tricks

By

Writing an iBeacon App in Swift

Editor’s Note: This is Part Two of our series of articles on creating a Swift iBeacon application. By the end of the series you will have written a “game” in Swift called You’re Getting Warmer! which allows you to track down and find a beacon. Part One gets you up and running iBeacon with a Gimbal Proximity Beacon Series 10.

Before getting started with Part Two, you should have an operating iBeacon and know its UUID. If you don’t have an iBeacon start with Part One of this series!

If you’re working with iBeacon we’re just going to assume you known how to create a new Single View Application Swift project with Xcode. Go ahead and do that now. We named our project gettingwarmer.

gettingwarmer_xcodeproj

Beacon Ranging

There are two methods of listening for iBeacons in iOS: monitoring and ranging. The difference between the two is that monitoring is an activity that can continue running in the background, while ranging is a foreground activity. Radius Networks wrote up a nice explanation describing the differences in detail. Apple’s iBeacon documentation uses the term ranging to describe the activity of determining the proximity of a given iBeacon. Our first application will make use of ranging as opposed to monitoring.

BeaconManager

I have always preferred to use the singleton “manager” pattern for working with CoreLocation in iOS. We’ll create a class called BeaconManager which will be responsible for an instance of CLLocationManager as well as serving as our CLLocationManager delegate. To get started create a new file BeaconManager.swift in your gettingwarmer Xcode project and add the following implementation:

The class declaration and init routine should be self-explanatory. If you haven’t been working with Swift 1.2 you may have missed the introduction of the static keyword which allows for a quick implementation of the singleton pattern.

Let’s first implement the didChangeAuthorizationStatus method, because once we are authorized we want to start ranging.

Here’s our implementation:

If the OS can’t determine the authorization status (.NotDetermined), we’ll simply ask for it again (why not).

If we receive a callback that our status is .AuthorizedWhenInUse (what we requested) or .AuthorizedAlways (which will never be the case), we’ll call our startRanging method.

If on the other hand we receive .Denied or .Restricted, we’ll broadcast a notification with NSNotificationCenter that will be heard by our ViewController. The ViewController will then be responsible for raising a dialog indicating that location services are required for the app to operate properly.

Now, let’s take a look at our startRanging method.

Ranging begins with the startRangingBeaconsInRegion method, and in our case a region is identified as “being in the proximity of a beacon broadcasting a UUID of 788FA98B-871C-4C71-9944-88ADEC84A8DA”. It’s that simple. If iOS hears a beacon with this UUID, it is “in” that region.

It may be confusing at first that a “region” in this context is not geographical. Apple’s QuickHelp documentation explains it this way: “A CLBeaconRegion object defines a type of region that is based on the device’s proximity to a Bluetooth beacon, as opposed to a geographic location.

Once ranging starts we have to be prepared to receive didRangeBeacons calls on our CLLocationManager delegate. For now, we’ll add this implementation:

Before leaving ranging, it is important to draw the distinction between monitoring for regions and ranging beacons. Monitoring can run in the background with notifications sent to your app when the registered CLBeaconRegion is “entered” (that is, the beacon was heard). Ranging is for finer proximity detection and can only be used while the application is in the foreground. Again, reading the Radius Networks article is useful.

Rounding Out

Thus far we’ve implemented:

  • a BeaconManager class capable of requesting location services authorization
  • the didChangeAuthorizationStatus method to handle changes in location services authorization from the user
  • a startRanging method which will start listening for our iBeacon
  • the didRangeBeacons method which will be called when iOS hears our iBeacon

We have a few more things to do before running the application:

  • setting NSLocationWhenInUseUsageDescription in our Info.plist
  • creating an instance of the BeaconManager when our ViewController appears
  • intercepting LOCATION_DENIED notifications in the event the user declines location services authorization

In your Info.plist, create a new key called NSLocationWhenInUseUsageDescription like so:

infoplist

Next, round out the ViewController code by adding the following:

When our view appears we want to create an instance of the BeaconManager which in turn will request authorization. Therefore we add our ViewController as an NSNotification observer for the LOCATION_DENIED notification. If this notification is received we pop up an alert dialog (UIAlertController) indicating that location services permission is required.

Run It!

If you’ve implemented everything you should now be able to run the application on your iOS device (note: this will not work in a simulator). After granting location services authorization and bringing out our iBeacon we see in the console:

Beacon ranged:  CLBeacon (uuid:<__NSConcreteUUID 0x1702224e0> 788FA98B-871C-4C71-9944-88ADEC84A8DA, major:1, minor:0, proximity:2 +/- 0.68m, rssi:-59)

What Could Possibly Go Wrong?

Software development can be rewarding and a lot of fun, but it can also drive you crazy when things don’t work right. In this series there are a lot of things that could go wrong that would prevent iOS from recognizing your beacon. If you’re having trouble, consider:

  • is your iBeacon programmed with the same UUID as your CLBeaconRegion?
  • is your iBeacon powered?
  • was the app granted location services permission?
  • is the iBeacon in range?
  • is Bluetooth enabled on your iOS device?

Getting the Code

The complete source code for this tutorial is available on BitBucket. The implementation for this article is available on the partTwo branch.

Next Up

We can now receive iBeacon messages in our application, but we aren’t doing anything with the information. In Part 3 of this series we’ll go through the various properties of the CLBeacon class, namely:

  • proximity
  • accuracy
  • rssi

We’ll then begin adding a user interface to our view controller for a nice game of You’re Getting Warmer!. Stay tuned!

By

Apple Watch Internationalization and Localization

There are plenty of articles on the blogosphere extolling the reasons why you, dear entrepreneur/product manager/software developer, need to consider internationalization (I18N) and localization (L10N) when designing your next killer application. Briefly, internationalization is the process of supporting more than one language in your application. Localization is the process of supporting local and regional differences in the display and formatting of times, dates, and currencies.

Your Apple Watch application is no different. Of course, every mockup and advertisement you’ve seen thus far has had the Apple Watch UI displaying English, but if you support multiple languages in your iPhone application and are designing an Apple Watch extension, you need to support those languages there as well.

In this article we’ll take a look at how to internationalize and localize your Apple Watch application. Our application will be a simple one and present a “Hello World!” label followed by the time (in localized format) and an appropriate time-based greeting. For example, at 9:00 AM the greeting would be “Good morning” in English.

iOS Simulator Screen Shot - Apple Watch Apr 19, 2015, 9.28.26 AM

As usual, we’ll begin with a starter application so you can jump right into internationalization and not spend time laying out the Apple Watch interface. Grab the zip file, extract, and open the applewatch18n project.

For this application we’re going to use two types of internationalization techniques with Xcode: internationalizing the storyboard, and creating a Localizable.strings file. Internationalizing the storyboard is a good technique to use when you want to provide for static labels to be displayed in the appropriate language. For example, if you have a button labeled Close and want to display Cerrar in Spanish, you likely want to use Storyboard internationalization. In our case the Hello world! label on the Apple Watch interface will be displayed as Hola mundo! in Spanish, so let’s go through the steps of creating an internationalized storyboard.

Note: While some application platforms separate the I18N and L10N steps, Xcode (and iOS/OS X) combines them into Localization. We’ll use the terms interchangeably.

The first step to adding localization to your application starts with the Localizations section of your project. Go to the applewatchi18n project in Xcode and find the Localizations section. Click on the + sign.

localizations

Choose Spanish (es) from the menu and you will be prompted to select the files you want localized. Although we won’t use Main.storyboard or LaunchScreen.xib in this example, leave them checked, and of course since we are interested in localizing our Apple Watch interface leave Interface.storyboard checked. Leave the Reference Language as Base.

filesandreference

Click Finish.

Notice now there is a disclosure triangle next to Interface.storyboard in the project explorer. Click on it to reveal:

interfacestoryboard_es

Let’s take a look at Interface.strings (Spanish):

The gibberish strings you see are Xcode Object IDs assigned to the UI component when you add them to the storyboard in Interface Builder. Just think of them as a automatically generated unique identifier (because that’s what they are) for the UI components. That said, the object IDs you see when you run this tutorial in Xcode will be different.

Notice the line "neb-bX-Mot.text" = "Hello world!";. Here is where we’re going to apply our Spanish text for the label we want to display “Hello world!”. To change it, simply replace the Hello world text with Hola mundo.

Tip: The dot-notation .text indicates you are localizing the text property of the given UI element.

To test our new localization change we’re going to have to change the language of our iOS simulator from English to Spanish. This can be done by launching the simulator and going to Settings – General – Language & Region and selecting iPhone Language. Español should be the first selection. Select it and press Done in the upper-right. The simulator will prompt you to confirm that you want to change the language to Spanish, so press Change to Spanish.

Tip: This may sound obvious, but When changing the language on the iPhone it is a good idea to have a basic grasp of the iPhone terms in the target language. For example, Settings is Ajustes in Spanish. Although you can use context clues (such as the icon for Settings), when you need to drill down into multi-level menus and either don’t know the language or alphabet you’re working with, it can be difficult or time-consuming to navigate the interface.

Now that our simulator is in Spanish, run the WatchKit app. You should see something like:

holamundo

Let’s move on now to localization of the time. Now I will be honest: when I see or hear time given in 24-hour (or “military time” as Americans refer to it) notation, my brain has no immediate understanding of the relative time-of-day. In the end, when I see something like 15:45 I subtract twelve from fifteen and understand it to be 3:45 PM, which instantly puts me in the afternoon. But, as I’ve discovered in my travels, many places in the world prefer and use 24-hour time.

Our goal will be to respect the localization/regionalization setting of the user’s iPhone and display the time in their preferred format. To accomplish this we’re going to add some code to our InterfaceController.swift file:

This routine looks up the iPhone’s current locale and then creates a formatted time string for the supplied date. Update InterfaceController.swift willActivate as follows:

Run the application. Assuming no changes were made to the simulator, you should see the AM/PM notation used for the label. We want to use the regional time format for Uruguay (which uses 24-hour notation), so, if your simulator is still in Spanish, go to Ajustes – General – Idioma y región – Región and select Uruguay.

Run the application again and notice that AM/PM is no longer displayed and the time is formatted in 24-hour notation.

Thus far we’ve looked at internationalizing static labels (with an Interface.strings file for our storyboard) and respecting the regional settings for the time. Now we’ll turn our attention to dynamic UI elements that can display different strings based upon the software’s logic.

To get started, let’s add a strings resource file called Localizable. Using Xcode File – New – File, select iOS – Resource and a Strings File template.

stringsfile

Click Next.

Name the file Localizable and ensure it is added to the WatchKit Extension target.

localizable_target

Now that we have the Localizable.strings file created, we need to configure it as a localized file. In Xcode select Localizable.strings that you just created and in the File inspector find the button that says Localize.

Click Localize and Xcode will ask whether or not you want to localize the file and allow you to select the base language. Select Base and click Localize.

localizeprompt

The File Inspector pane will update and in place of the Localization button you will see the languages that the file has localization support for. The default selection will be Base (which is, in fact, English), and we want to add Spanish. Select the checkbox next to Spanish and like Interface.storyboard, Localizable.strings will get a disclosure triangle in the project navigator.

localizablestrings_withspanish

When working with localizable strings the base language string is used as the key from which to look up translations. For example, the following table lists the base strings (which happen to be in English) along with their Spanish translation.

BaseSpanish
Good morningBuenos días
Good afternoonBuenas tardes
Good eveningBuenas noches

To implement this table in the Localizable.strings file, select the Spanish version of the file and add:

Notice that you don’t necessarily have to add content to the base Localizable.strings file. The reason will become clear in a moment.

Add the following function to the InterfaceController:

The above code takes the supplied NSDate and extracts the hour component, and then derives an appropriate greeting. Now, let’s display this greeting in our interface with the following in willActivate:

The key function here is NSLocalizedString which returns the localized version of the supplied string. If there is a localized string available for the target language it is returned. If there isn’t one, the string supplied is returned. For example, if you forgot to provide a Spanish translation for “Good evening” in your Localizable.strings (Spanish) file then “Good evening” would be returned by the function. This is why technically speaking you did not have to provide a mapping for the English translation, the function greetingForTime is supplying it.

Note: The comment argument to the NSLocalizedString function is to provide a hint to human translators that are supplying translations. I have never made use of it and have only used a blank string in code.

Running our application with the simulator still set to Spanish we see:

iOS Simulator Screen Shot - Apple Watch Apr 19, 2015, 12.08.50 PM

Note: As you can see in the screenshot, there is a difference between the language and the time format. Although our phone is set to Spanish, our region was set to the United States.

Now that we have run our application in Spanish, we need to switch the simulator back to English and ensure it is functioning as expected. If you are writing applications that support multiple languages you will have to go through this process for each and every language. Nothing is as embarrassing as claiming you support a given language in your application only to let a typographical or grammatical error get published on the AppStore (it’s buenos días, not buenas dias!)

iOS Simulator Screen Shot - Apple Watch Apr 19, 2015, 12.18.40 PM

Get the Code

You can find a completed version of the application in this zip file. Try adding a German translation to the application!

BaseGerman
Hello world!Hallo Welt!
Good morningGuten Morgen
Good afternoonGuten Tag
Good eveningGuten Abend

By

Multiple Build Schemes with Apple Watch

I frequently use Xcode schemes and configurations to manage building iPhone applications for specific environments. For example, let’s say you’re integrating with an API from another team, and they’ve set up two instances of the API: staging and production. Furthermore, you want to have two sets of builds for those environments: debug and release. All of this can be accomplished with Xcode and Swift, with details outlined in a previous blog post.

In this post I’ll show you how to extend this paradigm to work with an Apple Watch target that you’ve added to your project. We’ll start with an application that is already configured to support two schemes: debug and release, where the debug scheme enables logging. Download the starter project watchschemes. To ensure things are working properly, download the zip file and open the watchschemes.xcodeproj project, and then run the Debug Application scheme. You should get a nice log in the console:

Before we add the Apple Watch target, note our two files that facilitate logging: XCGLogger.swift and LogUtils.swift. They are currently grouped under Supporting Files of our watchschemes folder. When we add the Apple Watch target we’ll reorganize these files to highlight the fact that they are shared between the iPhone application and watch extension. If you haven’t had the pleasure of working with XCGLogger, see our post on using XCGLogger instead of Lumberjack for your Swift projects.

Now, let’s add our Watch target. Go to Xcode File – New – Target and select the Apple Watch “WatchKit App” template. Uncheck Include Notification Scene as we won’t be creating one.

watchkitapptarget

You will notice that Xcode has created a new scheme titled watcheschemes WatchKit App. Xcode may ask if you want to activate that new scheme:

activatescheme

Click Activate.

You will also notice if you edit the scheme you will find that the Run action is associated with the Debug build configuration.

watchkitscheme

What we would like is to have two schemes for our WatchKit App, similar to the two schemes we have for the iPhone application. Let’s do that then by going to the Manage Schemes page. To get there, select the Scheme in Xcode and go down to Manage Schemes.

manageschemes_selection

You should see the three schemes in the project:

schemelist

The first thing we’ll do is rename the default WatchKit application scheme to Debug WatchKit Application and mark it as a shared scheme (sharing the scheme allows for multiple developers to share the scheme in their workflow, allow them to use all of the build configuration defines, optimizations, etc.). Then, we will duplicate that scheme and rename it to Release WatchKit Application.

duplicatescheme

When duplicating the scheme, rename it to Release WatchKit Application and change the build configuration for the Run action from Debug to Release. After duplicating the scheme mark the scheme as Shared.

Now that we have a Debug and Release WatchKit Application, let’s instrument logging into the WatchKit extension such that Debug has meaning. Open the InterfaceController.swift file (in the extension group) and ensure it looks like this:

Out of the box, with no changes to the extension target, this code will not compile. The WatchKit extension has no knowledge of the XCGLogger.swift and LogUtils.swift code that is a part of the iOS application. So let’s add them.

Tip: If you interested in how the ENTRY_LOG() and EXIT_LOG() routines work, see the LogUtils.swift file.

Go to the watchschemes WatchKit Extension target’s Build Phases pane and under the Compile Sources section add both XCGLogger.swift and LogUtils.swift. This simply instructs Xcode to consult these files when compiling the WatchKit extension.

Before adding the two Swift files you should see only the InterfaceController.swift file as a member of the Compile Sources list:

watchschemes_compile_sources_default

After adding you should have 3 files:

watchkitextension_w_compile_sources

Although we’ve added our logging files to the extension target, and we’ve specified the Debug and Release build configuration for the two schemes, one still must configure the build configurations for the extension target. To put another way: Xcode does not copy the build configuration flags and settings from the iOS target to the extension target when it is created. You can verify this by looking at the Swift Compiler – Custom Flags for the WatchKit extension. Whereas our original application has -DDebug set for the Debug build configuration, the extension target does not. You should keep this in mind when creating your first Apple Watch target: if you have compile-time flags configured for your iOS build configurations, you’ll need to reproduce them in your extension target flags. This is what we have done here:

watchkit_custom_flags

Once your build configuration flags have have been set you should be able to Run either the Debug or Release WatchKit Application. For instant gratification, select the Debug Watchkit Application scheme and run. You should see

in the console log for the Debug WatchKit Application scheme.

As you continue development of your WatchKit application you can use the debug configuration. Once you are ready to run the release version with no logging, switch over to the Release WatchKit Application scheme you created.

Tip: With the two build configurations and schemes you can build either a WatchKit application that includes debug logging, or one that doesn’t. I personally prefer to have additional configurations and schemes for targeting various installations of APIs or other backend services; the approach outlined above can be extended to accomplish this so you can support variations such as Debug Staging or Release Beta.

Tip: Don’t forget your Archive scheme actions! I frequently upload archive builds to either TestFlight or TestFairy that have logging instrumentation, test API keys, or are utilizing staging servers. You will want to ensure the Archive action for your scheme has the correct build configuration set.

Organizing Common Swift Files

As mentioned above, our XCGLogger.swift and LogUtils.swift files are utilized by both the iOS application and WatchKit extension. To facilitate making this explicitly obvious in the project, I’ve started to add a Common Sources group to my Xcode projects and placing the shared files there. In this project this looks like:

commonsources

Getting the Code

The final version of the code for this tutorial is on the watchschemes branch of the BitBucket repository. To download a copy, grab this zip.

By

Bluetooth Low Energy, Arduino, and Xcode

In some ways Apple signaled what it sees as the future for home automation when it introduced HomeKit with support for 802.11 (Wifi) and Bluetooth Low Energy (also referred to as BTLE or Bluetooth Smart) as transport protocols. Notably absent were both Z-Wave and Zigbee. Sure, Apple provided for the implementation of a “bridge” device to these existing protocols, but every product announcement since then touting HomeKit support has been a Wifi or BTLE device. Don’t take my word for it, browse through this article outlining the devices showcased at CES this year. A brief lineup:

and more. Neither Z-Wave nor Zigbee is mentioned, which is not to say that either protocol or the the thousands of devices that are out there will simply go away, only that it’s clear Apple sees BTLE and Wifi as the future for home automation control. Whether that is true remains to be seen.

But this article isn’t about HomeKit, it’s about Bluetooth Low Energy itself and how to quickly integrate an Arduino-powered Adafruit BTLE board with your iPhone, all using an Arduino Xcode project. So let’s get started.

In our previous post we covered how to create an Arduino sketch using Xcode and the embedXcode project. The outcome of that process was a simple Arduino application that blinked two LEDs back and forth, and while cool, not exactly ground breaking. Let’s take it to the next level and integrate an Adafruit nrf8001 BTLE Breakout board with the Arduino and talk to it with our iPhone. Moreover, we’ll do all of this with our favorite IDE (well, mine at least), Xcode.

Before we get started, you’ll need to have the following on hand:

  • Arduino Uno board and USB programming cable
  • Breadboard and 8 male-to-male jumper cables
  • Adafruit nrf8001 BTLE Breakout board
  • Arduino application installed on your Mac
  • embedXcode installed on your Mac
  • an iPhone and access to the AppStore

For the last two items, see our previous post for instructions on installing.

The nrf8001 breakout board does not come out of the box with the header pins soldered on, so you’ll need to do that step. Luckily the instructions are provided by Kevin Townsend’s excellent nrf8001 article.

Assuming you the breakout board soldered and in your breadboard, wire it per the instructions found on Adafruit:

adafruit_products_8001Final

From the Adafruit nrf8001 article

btlewiring

Don’t take wiring lessons from me

Once the wiring is completed, we need to install the Adafruit BLE UART software into our Mac’s Arduino user library folder. There is a distinction between system libraries and user libraries that will become apparent in a moment.

To install the Adafruit BLE UART software as a user library click on this download link. A folder named Adafruit_nRF8001-master will be created in your Downloads folder. Rename this folder to Adafruit_BLE_UART and then drag-and-drop it into your ~/Documents/Arduino/libraries folder:

arduinolibraries

Now, let’s create our Xcode project. Open Xcode and use File – New – Project to create a new embedXcode Sketch. We’ve named our project nrf8001 and targeted the Arduino Uno board.

nrf8001_options

To walk this through in stages, open the nrf8001.ino file in your project and delete its contents and then add following to it:

This code is actually found in the Adafruit_BLE_UART folder you downloaded earlier, under the examples folder in a file called echoDemo.ino.

In Xcode click the Run (play) button using the All target. You should get a Build Failure with an error:


Shell Script Invocation Error SPI.h: No such file or directory

Recall that we are dealing with C++ when working with Arduino, and a header inclusion failure is likely the result of failing to specify that we are using some library. In this case we are wanting to use the Arduino SPI system library and didn’t tell Xcode in our Makefile. So open the Makefile and find the lines:

Change the APP_LIBS_LIST line to APP_LIBS_LIST = SPI and try to compile again. The error now should be a failure to find Adafruit_BLE_UART.h, which is a part of a user library. Looking back at the Makefile we see a USER_LIBS_LIST definition, so change it to

Run again and you should see a terminal screen pop up like this:

adafruitterminal

If you are seeing the same output, congratulations! You’re almost there.

Now, let’s grab an application for our iPhone to connect to our Bluetooth module! On your iPhone search for the nRF UART application from Nordic Semiconductor. Download and open the app on your iPhone and, of course, ensure Bluetooth is enabled!

The nRF UART app isn’t fancy – a button to Connect to the Adafruit BTLE board, a Console showing you what’s going on, and a text field for sending text.

IMG_8800

Bring your Adafruit terminal log into focus on your Mac and then press the Connect button on the nRF UART app on your iPhone. If everything is working properly (all of your pins are wired to the right spot and the application is running) you should see Connected! on your Mac terminal and the console log on the iPhone indicating that a connection was successful.

IMG_8801

Now, type some text in the textfield on the iPhone app and press Send. If everything is working properly you should see the text you typed in your phone show up in your Arduino application console!

IMG_8802

From the iPhone…

adafruit_browncow

To Arduino!

Get the Code

The complete Xcode project for working with the Adafruit nrf8001 is on Bitbucket. Remember, you must have the Adafruit_BLE_UART library installed in your Arduino user library folder.

Acknowledgements

This post is really made possible by Kevin Townsend and his article on Adafruit. As I’m quickly learning, much of Arduino magic comes from the fact that it just works. For example, although I know SPI and some BTLE protocol details, I didn’t have to lean on that knowledge to put this tutorial together or get my iPhone and Arduino/Adafruit BTLE communicating!

By

Using Carthage with Alamofire

I have never been a fan of CocoaPods due to its intrusiveness in the build process and insistence on creating Xcode project workspaces. Unfortunately managing dependencies through the use of Git submodules is no better. How many times have you told yourself, “Okay, I understand submodules now” only to be met with fatal: reference is not a tree: when trying to do a git submodule update? Perhaps I’m dense, but I shouldn’t have to turn to Google every time I check out a project which uses submodules.

In the tutorial HTTP JSON Request with Swift and Alamofire we used the git submodule approach to add the Alamofire framework as a dependency to our Xcode project. Let’s now look at a new approach to managing framework dependencies with Carthage.

Carthage was developed to make framework dependency management in your Xcode projects just a bit easier. Luckily for us, Alamofire now supports using Carthage, and we can leverage that support in our project to get rid of the git submodule approach.

To get started with Carthage, you’ll first need to install Homebrew. If you have never used Homebrew before, you’re in for a real treat. To install Homebrew open a terminal and paste:

Follow the prompts and once Homebrew is properly installed then you can install carthage with brew install carthage.

==> Downloading https://downloads.sf.net/project/machomebrew/Bottles/carthage-0.5.2.yosemite.bottle.tar.gz
Already downloaded: /Library/Caches/Homebrew/carthage-0.5.2.yosemite.bottle.tar.gz
==> Pouring carthage-0.5.2.yosemite.bottle.tar.gz
🍺 /usr/local/Cellar/carthage/0.5.2: 157 files, 34M

Now, let’s look at how to add Alamofire to our project using Carthage. The first step is to create a Cartfile in our project folder. The Cartfile is what you might expect: a list of dependencies (and where to fetch them from) for our project. Our Cartfile will contain a single dependency on Alamofire.

Run carthage update. Carthage will now check out and build Alamofire.

% carthage update
*** Fetching Alamofire
*** Checking out Alamofire at "2f39b8634ab85cd6b3a55bbcfdec8cbb6463a6ee"
*** xcodebuild output can be found in /var/folders/yn/ljzrn5hd4g3fxsj4klwkhbkm0000gp/T/carthage-xcodebuild.wAPiQR.log
*** Building scheme "Alamofire iOS" in Alamofire.xcworkspace
*** Building scheme "Alamofire OSX" in Alamofire.xcworkspace

Once completed you should see a new file and new folder in your project directory: Cartfile.resolved and Carthage, respectively.

You are going to want to check in both Cartfile and Cartfile.resolved, so add them to your repository.

git add Cartfile
git add Cartfile.resolved

You do not need to add the Carthage folder, so you can add it to your .gitignore file if you like.

Now, let’s add the build output from Carthage to our project. First, go to your project’s General tab and locate the section Linked Frameworks and Libraries. You can either drag-and-drop the built framework from the Finder, or use the + button and navigate to the folder in Xcode.

Add_Alamofire

You should see the framework added to the list:

Alamofire_added

Now, go to Build Phases and create a new Run Script phase. The script contents will be:

Then add an Input File as the framework you want to copy, i.e., Alamofire.framework.
Carthage_RunScript

That’s it! With your Xcode project set up to pull in the built framework that Carthage created, you’re ready to build and run! Much easier than using than CocoaPods or git submodules.

Gotchas

If you are iOS developer that likes to stay on the bleeding edge you undoubtedly have both the release and beta versions of Xcode installed on your Mac. If you build your projects solely within Xcode there’s typically no conflict between the two, but since Carthage builds your frameworks from the command-line, the version of Xcode selected by xcodebuild matters. For example, if your xcodebuild is set to use the release version of Xcode and you run carthage update and then include that framework in an Xcode beta project, you will likely get the error Module file was created by an older version. To resolve this use xcode-select to switch xcodebuild to use the beta version of Xcode:

As of February 28, 2015, the Alamofire main branch hasn’t been updated to support Xcode 6.3 (and by extension, Swift 1.2). To continue working with Alamofire in your Xcode 6.3 projects, update your Cartfile to specify a branch dependency:

Run carthage update and Carthage will checkout the xcode-6.3 branch of Alamofire and compile it. If you get a build failure make sure you’re using the right xcodebuild!

% xcodebuild -version
Xcode 6.3
Build version 6D520o

Get the Code

You can check out our example application (for details on the application, see our post here)of using Alamofire and Carthage on Bitbucket. There are two branches, carthage and carthage-xcode-6.3.

If you’re using Xcode 6.1 then you will want to use the carthage branch:

If you’re using Xcode 6.3 (which is beta at the time of this writing):

Note! If you open the translator project and try to build and are met with No such module 'Alamofire' you didn’t build Alamofire with carthage update first!

By

Introducing Bondi

iAchieved.it LLC is happy to announce the release of Bondi on the Apple AppStore in both English and Spanish. If you ever have the fortune to visit the city of Montevideo, Uruguay, make sure you have Bondi at your side.

Bondi is Spanish slang for city bus and is the term used by Montevideo locals to refer to their urban busses. Our Bondi app presents all of the Montevideo urban stops on a map and then allows you to select and then view all of the bus lines running through that stop. You can then filter those lines for time of day and type of day (the busses run on different schedules on weekdays vs. Saturday and Sunday).


bondibus

Here come the bondis!

One question that pops up on Reddit /r/iOSProgramming frequently is “are there production applications written only in Swift?” and we can definitely (and proudly!) say, Bondi is written only in Swift! We’ve had nothing but great success with the Swift programming language and have included frameworks such as XCGLogger and Alamofire in our development.

During the process of developing Bondi we learned a few tips and tricks that we’d like to share; one for iAd presentation and the other for the frosted background effect when presenting a modal view controller. We’ll be writing up posts to describe both of these techniques soon!

By

Building an Apple Watch App for Location-Aware Weather

Editor’s Note: This is a tutorial on how to use iOS 8.2 with Xcode 6.2 to develop an Apple Watch app. It is not an exhaustive overview of WatchKit. I recommend reading the following first in this order:

By the time you’ve finished reading these tutorials you should have a basic understanding of the architecture of a WatchKit app and the application lifecycle of a WatchKit Extension (the app component that runs on your iPhone).

While I’ve tried to provide plenty of step-by-step detail, this tutorial does make an assumption that you have a basic understanding of iOS application development and are comfortable navigating in Xcode. You will of course require an iOS developer’s account to obtain Xcode 6.2 and the iOS 8.2 simulator included.

A Current Conditions WatchKit App

Starter Application

It should have been clear from reading the Apple WatchKit Programming Guide that your Watch app is an extension of an existing iPhone application. That is, there is no such thing as an Apple Watch-only application. One of the examples given on Apple’s website is that of an American Airlines watch app that shows flight updates, boarding notifications, etc. The American Airlines watch app cannot be used without downloading and installing the iPhone app, as that is where the code for the Watch app will reside.

Rather than walk through how to create an application from scratch we’ll begin with a starter application and add an Apple Watch app to it. Ours is a basic weather app that provides a brief look at the weather in your current location. To keep things simple we’ll provide:

  • the name of the current location (for example, New Orleans, LA)
  • a weather icon depicting the current conditions
  • a brief description of the current conditions
  • the current temperature

Even though this is a simple app in its functionality, it does provide a good example of how we will leverage third-party SDKs and the CoreLocation framework to provide location-aware weather information to an Apple Watch app. Warning: If you thought this was going to be a “How do I write a simple WatchKit app in 10 minutes?” tutorial, try out the Bitcoin Price Tracker app first. Ours is a bit more involved.

Download the starter application from BitBucket and open the project in Xcode.

To get started with the app you’ll need to change your aerisweather target bundle identifier. In this example we’ve changed it to com.yourcompany.aerisweather.

watch_tut_change_bundle_identifier

We will be using the Aeris Weather API from HAMweather.com, so you will need to register for the service and create some API keys. You may want to review our previous post on signing up.

Create a new application in the HAMweather portal by filling out your Application Name and Application Domain/Identifier.

watch_tut_api_key

Click Register to register your application and receive your API keys.

watch_tut_successful_registration

Configure your keys by creating a property list file called ApiKeys.plist. This can easily be done through Xcode with File – New – File selecting the iOS Resource item and then Property List. Again, name it ApiKeys.

watch_tut_apikeys_save

If Xcode has two ApiKeys.plist files listed in the project navigator, select one of them, right-click, and Delete and choose Remove Reference (not Trash!).

Add two items to the property list file,AERIS_CLIENT_ID and AERIS_APP_SECRET, and set them to the values of the keys that were created when you registered your application in the Aeris portal.

Stop and build the iOS application at this point in the iOS simulator for either the iPhone 5, 5s, 6, or 6 Plus. If Xcode complains about the lack of a provisioning profile click the Fix Issue button to generate an appropriate provisioning profile.

watch_tut_fix_pp

The simulator should prompt you requesting location access. Click Allow. Hopefully you see something like this in your simulator.

watch_tut_first_app_run

Simulating Location

We are using significant location change monitoring which relies primarily on recognizing locations of Wifi networks and cell towers rather than GPS. We use this rather than GPS because we don’t require the same level of accuracy for providing the current weather. Of course in large urban areas where cities blend together your app may show you to be in Dallas when in reality you are in Richardson. To simulate significant location changes in the simulator select the Debug menu and choose Location – Freeway Drive. At this point you can stop the application. As long as the Freeway Drive location simulation is running we will have data for us in our Watch app.

Note: If the app is not receiving location updates (and correspondingly you see a screen that has default label text), go to Hardware – Location and select None. Then, go back to Hardware – Location and select Freeway Drive.

Adding the Watch App

Let’s add a watch app to our weather app! I assume you have the aerisweather project open and you’ve already added API keys for Aeris and have run the starter app in the simulator. If you haven’t, do so, the remainder of the tutorial builds upon these steps.

Now, to add a Watch App target in Xcode go to File – New – Target and select Apple Watch.

watch_tut_watchapp_target

Take a moment to note what the Watch App template does: This template builds a Watch App with an associated WatchKit app extension. It bears repeating that there are two items about to be added: the watch app itself which runs on the Apple Watch and the watchkit app extension which runs on the iPhone.

Click Next. When choosing your target options make sure for this tutorial to uncheck Include Notification Scene and Include Glance Scene. We will not be including either a notification or glance scene in this tutorial. Also ensure your Language is set to Swift. Click Finish.

watch_tut_choose_options

Notice on this screen also there is a new bundle identifier. If you used com.yourcompany.aerisweather for your bundle identifier above, the new identifier for the watch app will be com.yourcompany.aerisweather.watchapp. As you will see below there is also a third bundle identifier for the app extension named com.yourcompany.aerisweather.watchkitextension.

Again, two new targets have been added, along with a new scheme. The targets are the watch app extension and watch app, and the scheme is aerisweather Watch App.

watch_tut_new_targets

When first working with WatchKit it was confusing understanding how to simulate the Watch. The answer is by using the new scheme Xcode created, in our case it is named aerisweather Watch App. You must use the simulator for now; that is, you cannot run the app and app extension on your physical iPhone and simulate the watch.

Let’s lay out our watch interface using the Xcode storyboard created for us. Go to the file Interface.storyboard in the aerisweather Watch App folder. Like our iPhone app we will have a label for our last known location, a weather icon, current conditions label, temperature label, and at the bottom a last updated string. Here is our layout:

watch_tut_layout

Laying items out on a watch interface is a bit easier than for an iOS device. For one reason we don’t have to use constraints! There are a few things to note. First, our layout was created by adding, in this order:

  • Label with a horizontal position of center
  • Group
  • Image inside the group with a horizontal position of Left and size of 64×64
  • Label inside the group with a horizontal position of Right
  • Label with a horizontal position of center
  • Label with a horizontal position of center

Second, we are using Avenir Next for our font, and have set the currentTemperature label to 30-pt, and the lastUpdated label to 10-pt. The remaining labels are 16-pt.

We now need to wire our elements up to the InterfaceController. Notice that the controller is in our extension and not in the Watch app itself! But if you click on Interface.storyboard and then the Assistant Editor icon (the joined circles), Xcode will place the storyboard and controller side-by-side in the editor.

watch_tut_interfacecontroller

Just as with building iOS applications, simply CTRL-click from the UI element and drag over to the InterfaceController class to insert the Outlet. To be consistent with our iPhone interface we’ll name these:

  • currentLocationLabel
  • currentWeatherIcon
  • currentTemperatureLabel
  • currentConditionsLabel
  • lastUpdatedLabel

After adding our IBOutlets

It is possible to run the watch app at this point and see the labels displayed. To run the app select the aerisweather Watch App scheme and click Run. To see the Apple Watch display go to the simulator and in the Hardware menu find External Displays and select one of the two Apple Watch displays.

Note: I’ve frequently had trouble with the simulator and watch kit extensions running properly. If you see in your Xcode debug navigator waiting to attach to your process and it never attaches, simply stop the application and run again. One more than one occasion I’ve had to restart the simulator altogether.

App Groups

To display the weather on the Apple Watch we’re going to need to fetch it from Aeris, but to fetch it from Aeris we’re going to need to obtain the last known location.

We need to stress that our app extension does not have access to iOS CoreLocation, thus it cannot retrieve the location and update the weather. Why? Because Apple warned us not to use it. From Apple’s WatchKit guidelines: “Avoid using technologies that request user permission, like Core Location. Using the technology from your WatchKit extension could involve displaying an unexpected prompt on the user’s iPhone the first time you make the request. Worse, it could happen at a time when the iPhone is in the user’s pocket and not visible.” So there you go.

To obtain the location we leverage sharing application data between our iOS application and our app extension. Select your project in the project navigator and select the aerisweather WatchKit Extension target. Then select the Capabilities page and scroll down to App Groups. Enable it and select groups.aerisweather.

watch_tut_enable_app_groups

Now, let’s add some code! Open InterfaceController.swift and add the following to the willActivate function:

Run your watch app again and you should see in your console log something like:

If the log instead says No last location you haven’t launched and run your iOS application. Remember, our watch application (and its corresponding extension) does not run CoreLocation, so it cannot directly obtain the user’s location. Only the iOS application requests and receives location information.

What exactly did we just do? By enabling app groups we are allowing our iOS application and our watchkit extension to share information. When our iOS application receives a new location from CoreLocation it reverse-geocodes the coordinate and then writes that information to a file in the app group group.aerisweather. When you launch your watch app it reads that information from the file in the app group. Check out the CoreLocationController‘s didUpdateLocations function to see where the information is being written.

Note that we must enable App Groups in each app that is granted permission to read and write in the shared group.aerisweather group.

Adding Aeris

Now, let’s get to adding Aeris to our watch app. To be more precise, we are adding Aeris to the watchkit app extension, as no Aeris code runs on the watch itself. As such, and this is key, we need to register another application in the HAMweather.com portal. Because we will be executing Aeris routines inside an application with a different bundle ID (remember, our extension has a bundle identifier of com.yourcompany.aerisweather.watchkitextension we need to register it.

watch_tut_watchkitextension_register

Add your new secret to the ApiKeys.plist file as AERIS_EXTAPP_SECRET. In the property list you should now have three different keys: AERIS_CLIENT_ID (which is shared by all the applications in your account), AERIS_APP_SECRET and AERIS_EXTAPP_SECRET.

watch_tut_allkeys

Next we need to configure our Objective-C bridging header for the watchkit extension target. If you’ve been working with Swift and Objective-C in the same projects you should be accustomed to this step by now.

watch_tut_add_bridging

Set the bridging header to $(SRCROOT)/bridgingHeader.h (you will see it is actually already a part of the overall project since we use it for our iOS application as well).

Now let’s add the Aeris.framework itself. Select the aerisweather WatchKit Extension target and then Build Phases. Click the disclosure triangle for Link Binary With Libraries and click the + icon. When presented with the Choose frameworks and libraries to add dialog, click Add Other. Locate the Aeris.framework item in your project directory, select it, and click Open.

watch_tut_addaerisframework

We’ll be using the ApiKeys.swift in the watch kit extension, so we need to add it to the compile sources. You should already be in the Build Phases panel for the watch kit extension, so click the disclosure triangle for Compile Sources and then click the + icon. Find the ApiKeys.swift file, select it, and click Add.

watch_tut_addapikeys_compile

Now, add the ApiKeys.plist to the Copy Bundle Resources list. In the same area, Build Settings, disclose the Copy Bundle Resources area, click +, and add the ApiKeys.plist.

watch_tut_addapikeysplist

The Aeris framework also requires us to add -ObjC to Other Linker Flags in the Build Settings (if you don’t you’ll get a nasty crash with -[__NSCFString awf_URLEncodedString]: unrecognized selector sent to instance). Go ahead and add it.

watch_tut_other_linker

Adding AFNetworking

We are going to compile our AFNetworking code into our target (rather than using a pre-compiled framework), so we need to add all of the required AFNetworking files to our Compile Sources. Go back to Compile Sources in the Build Settings panel for the extension target, click the + icon, and find the AFNetworking folder. Select each of the .m files in the AFNetworking and UIKit+AFNetworking folders and add them. This can be done quickly by holding down the Option key while selecting each file.

watch_tut_add_afnetworking

There are iOS routines that are not available to app extensions. In particular sharedApplication is referenced in AFNetworking code and it is not available. If you tried to compile now, you will see an error like 'sharedApplication' is unavailable: not available on iOS (App Extension). The AFNetworking authors recognized this issue and added a flag AF_APP_EXTENSIONS that can be defined to not call on unavailable routines. For an example see Github, and here is a screenshot of what the error looks like:

watch_tut_sharedapp_na

To set the AF_APP_EXTENSIONS define go to your aerisweather WatchKit Extension Build Settings page and type preprocessor in the search box and locate the section headed Preprocessing. We will be building the Debug configuration in this tutorial so add AF_APP_EXTENSIONS=1 underneath the DEBUG=1 define.

watch_tut_afappextensions

Rebuilding at this point will still result in an error regarding iOS App Extensions and sharedApplication because a routine inside the Aeris SDK uses AFNetworkActivitityIndicatorManager. The offending routine in AFNetworkActivityIndicatorManager.m is

To resolve the issue simply wrap the contents of the method with #if !defined(AF_APP_EXTENSIONS) and #endif:

One more file needs to be touched: UIAlertView+AFNetworking.m. There are calls to UIAlertView in the methods showAlertViewForTaskWithErrorOnCompletion and showAlertViewForRequestOperationWithErrorOnCompletion. Wrap both calls to the UIAlertView with #if !defined(AF_APP_EXTENSIONS) and corresponding #endif.

Take a moment to compile and run your watch app: there should be no unresolved errors at this point!

Updating willActivate

Now that we have everything configured properly for using Aeris, let’s fill out our routine to include the following in the willActivate routine after we receive our location. This block of code goes immediately following the line println("Last location: \(city), \(state), at \(lastUpdatedAt)") in InterfaceController.swift.

The full willActivate routine should now look like this:

Running the Watch App

Running now you should see something like this in the logs:

and our corresponding watch app will show:

watch_tut_no_icons

Oops! We need to add some assets to our app! Our iOS application currently contains a folder named Images.xcassets with all of our weather icons. We’ll leverage this and include them into our watch app. To do so right-click on Images.xcassets in the aerisweather folder and select Show in Finder.

Now select your Images.xcassets icon in the aerisweather Watch App folder (there are three folders named Images.xcassets in your project, make sure and select the right one here!) and then drag-and-drop the contents of the folder in the Finder into Xcode in the icon pane of your Images.xcassets. To be clear on this one: our existing iOS application contains all of the icons we need, but we need them on our watch as well. Using Show in Finder we expose the contents of our Images.xcassets so we can drag-and-drop the resources into the Watch App’s Images.xcassets!

weather_tut_drag_and_drop

Run the watch app again and you should see something like:

tut_apple_watch_finished

Get the Code on BitBucket

BitBucket contains two versions of the application:

  • The starter application which does not include the Apple Watch target. Download this file if you want to go through the above tutorial from start to finish.
  • The Apple Watch application which includes both the iPhone and Apple Watch apps. Download this file if you want to see the completed Apple Watch application.

Warning! Neither version comes with the ApiKeys.plist file which contains the Aeris SDK API keys. You have to create this file yourself and obtain your own API keys from HAMweather.com!

You can also obtain fork us on BitBucket, just go to the main project page.

Final Thoughts

It’s been fun putting together this tutorial on creating an Apple Watch app. If you install and run the aerisweather app on your iPhone it does take a toll on the battery over the course of the day using the significant location change monitoring feature of CoreLocation. I’m a bit disappointed in that, but have become somewhat accustomed to recharging the iPhone every day. It will be interesting what types of applications are available for Apple Watch on launch day and what iOS features they take advantage of!

Questions or Comments

I’ve been through the tutorial a number of times starting with the aptly named starter application. If you have any difficulty going through the tutorial please send a tweet to @iachievedit!

By

Using Swift in an Existing Objective-C Project

It’s clear from the Swift tutorials out there (including ours), that folks ask the question “How do I include Objective-C frameworks in my Swift project?” more often than “How do I include Swift code in my Objective-C project?” That’s understandable. Swift is new and shiny and we want to start off playing with Swift first and then mix in some Objective-C when we have to (which if you are using popular frameworks such as AFNetworking, Parse, etc., you have to quickly).

Since there’s plenty of Objective-C bridging header tutorials out there already, I thought I’d share my experience with the reverse direction: adding Swift code to an existing Objective-C project. I’d love to say it was easy and painless, but the reality is it was a pain in the ass (read this Stackoverflow thread to see why!).

Let’s start off the basic rule: Don’t add any Swift files to your project without reading this first. If you have already added Swift files and are scratching your head why things won’t work (namely that your -Swift.h can’t be found), delete them from your project and just start over and follow these steps:

Update Your Project Build Settings

Your project’s (not the target) build settings need to have the flag Defines Module set to YES. Go to your project build settings page and type Packaging in the search field and then set Defines Module to YES.

Screenshot 2014-11-26 16.04.46

Make Note of Your Product Module Name

Did you even know you had a product module name? I didn’t. To find it go to your target’s (not the project) build settings and again search for Packaging. Make note of the Product Module Name. In our case it is testing.

Screenshot 2014-11-26 16.10.33

Create Your Swift File

Create your Swift file with Xcode File – New – File. If Xcode asks whether or not you want to create a bridging header, you can if you like, but it’s not strictly required for what we’re trying to accomplish (Swift in Objective-C not the other way around, which is what the bridging header is for).

The Rules

There are rules around what’s required to get Swift objects living in harmony in your Objective-C code. For a complete overview see Apple’s documentation, but here’s what I’ve found to be true:

  • You have to #import <productModuleName-Swift.h> in every Objective-C class you plan to use your Swift classes in
  • The @objc declaration on a Swift class isn’t good enough – inherit from NSObject

The Header File

What others have pointed out in the Stackoverflow post referenced early is that unlike the the Objective-C bridging header the Swift bridging header is not a file you can see in your project, but is automatically generated in the build chain. That is, the compiler creates it as a temporary file prior to compiling your Objective-C. Even still, you have to #import it and if Xcode complains that it isn’t available you either don’t have Defines Module set to YES, or you named the header incorrectly (it is productModuleName-Swift.h, where productModuleName is your product module name), or (and here’s the irritating part) you added a Swift file to your project prior to setting Defines Module to YES.

The Swift Class Definition

Trying to use only @objc as an indicator that you’re going to use the Swift class in Objective-C code results in ARC complaints about alloc not being defined. Here’s a screenshot of declaring our Swift class like this:

Unfortunately we cannot compile due to the annoying No known class method for selector 'alloc' error:

Screenshot 2014-11-26 16.26.26

Changing our class to:

and the compilation proceeds and we can access our Swift class.

From there things proceeded relatively well. Our final test included the following Swift code:

with our delegate header including

and using it in our Objective-C application delegate:

As expected, our output:

Conclusion

If you can’t get Swift classes mixed into your Objective-C code on your first attempt, you’re aren’t an idiot. Future versions of Xcode one would hope will fix the annoying feature of failing to generate a -Swift.h header file if you didn’t do things in exactly the right order. In the meantime, follow these steps and definitely pore back over the Stackoverflow thread in case you missed something.

By

Using Aeris SDK for Weather Advisories

Editor’s Note: This is part three in a three part series. The goal in this series is to develop a fully functional (and useful) iOS application that is capable of pushing weather alerts based on your location to your iOS device. The series is broken down as follows:

  • Part One – Developing a Push Notification-capable application with Parse and Swift
  • Part Two – Using CoreLocation with Swift
  • Part Three – Integrating in a Weather Service API

In this third part of our three part series we’ll be completing our weather alerts application started in Part One. A warning! The code examples that follow in this post build upon the code covered in both Part 1 and Part 2.

HAMweather

We’re going to make use of the HAMweather service for our weather data. There are a variety of weather services that provide rich APIs for obtaining all manner of weather-related data. Here’s just a few of them:

We chose HAMweather over the others solely on the fact that it provided weather advisory access in its free offering. As a bonus it comes with a nice iOS SDK framework for dealing with its weather API named Aeris.

Signing Up for HAMweather

To get started with HAMweather and Aeris, proceed on over to the signup page and select Aeris API – Developer Free then scroll down and enter the required user information. Of particular interest will be selection of your domain name: if you plan on using the Aeris SDK on the server-side choose the domain under which your servers are registered. In our case, we chose iachieved.it.

Click Next to agree to the user agreement and then Login to login with your newly created username and password. Once you’ve logged in you’re going to want to proceed directly to managing your subscriptions by clicking on the Account tab.

tut_aeris_your_subscriptions

Click on Aeris API – Application/Website Registration to register the application and generate a consumer ID and secret. Pay particular attention to your Application Domain/Identifier field, this needs to match your iOS application bundle identifier, which uses reverse DNS notation. iAchieved.it’s bundle identifier is it.iachieved.weatheralerts, but yours will be based upon your reverse DNS.

tut_aeris_api_application

Click the REGISTER button at the bottom of the page to register the application and get your application keys!

tut_api_registration_success

Now we need to add Aeris API keys to our application. We’re using our ApiKeys.plist file to maintain all of our API keys, and have referred to the Aeris consumer ID and secret as AERIS_CONSUMER_ID and AERIS_CONSUMER_SECRET.

tut_api_keys

If you have a confused look on your face as to why we added these keys to a property list file, go back to Part One and our tutorial on using property lists for API key management.

Obtaining the iOS SDK

We’ll be using the new Aeris 2.0 SDK for iOS, which can be obtained from Github. Download the SDK 2.0 Beta 1 and unzip to a folder.

tut_aeris_frameworks

Add the Aeris.Framework to your project by dragging and dropping it into your weatheralerts project navigator. Ensure that the Copy items if needed and Create groups are selected, and that your weatheralerts target is checked. For our purposes we only need Aeris.Framework, but if we wanted to begin leveraging other features of Aeris we would add some of the other frameworks.

Aeris also requires using the link flag -ObjC. To set the flag go to your project’s Build Settings and type Other Linker in the search box. You will see Other Linker Flags in the Linking section. Add -ObjC:

tut_objc_linker

Adding AFNetworking

Aeris makes uses of the popular AFNetworking networking library for iOS, so we will need to add it to our application first. We’re going to grab the 2.5.0 version, so go to Github and click on the Download Zip button. Note: We could have used Cocoapods to manage the installation of AFNetworking, but there’s additional setup required to get Cocoapods going, and quite frankly, I don’t like the way it takes over my Xcode project organization.

Drag and drop both the AFNetworking and UIKit+AFNetworking (Aeris makes use of AFNetworkActivityIndicatorManager class) folders into your project, again ensuring that Copy items if needed and Create groups are selected and that the files are added to your target.

Using Aeris

Now that we have all of the prerequisites out of the way we can get down to business with actually using Aeris. The first step in accessing the Aeris SDK routines in a Swift-based project will be to import its header files in our application’s bridging header. Add the following to your bridging header (which should be named bridingHeader.h):

#import <Aeris/Aeris.h>

The complete bridgingHeader.h file should look something like this now:

#ifndef weatheralerts_bridgingHeader_h
#define weatheralerts_bridgingHeader_h

#import <Parse/Parse.h>
#import <Aeris/Aeris.h>

#endif

We’ll now turn to the WeatherServiceController class created in Part 2 of our tutorial. Find the init() routine and ensure it looks like the following:

override init() {
    super.init()
    
    let aerisConsumerId = valueForAPIKey(keyname: "AERIS_CONSUMER_ID")
    let aerisConsumerSecret = valueForAPIKey(keyname: "AERIS_CONSUMER_SECRET")
    
    AerisEngine.engineWithKey(aerisConsumerId, secret: aerisConsumerSecret)
    
    NSNotificationCenter.defaultCenter().addObserver(self,
      selector: "locationAvailable:",
      name: "LOCATION_AVAILABLE",
      object: nil)
}

AerisEngine.engineWithKey() initializes our Aeris framework with the consumer ID and secret that we received when registering our application.

The Aeris SDK employs a notion of loaders that are used to obtain information from the HAMweather service. To obtain a list of advisories in our current location we first have to obtain an Aeris place and then use an advisory loader to retrieve the advisories (if any) for our place.

To create a place, or, AWFPlace, we provide city, state, and country information like so:

let place = AWFPlace(city: city, state: state, country: country)

We can at this point load the advisories for our place using an AWFAdvisoriesLoader.

let advisoryLoader = AWFAdvisoriesLoader()
  advisoryLoader.getAdvisoriesForPlace(place, options: nil) { (advisories, e) -> Void in
  }

The getAdvisoriesForPlace function takes our place and returns a list (array) of advisories currently issued for it. Let’s put this all together and place in our WeatherServiceController‘s locationAvailable function:

func locationAvailable(notification:NSNotification) -> Void {
    let userInfo = notification.userInfo as Dictionary<String,String>
    
    println("WeatherService:  Location available (userInfo)")
    
    let city    = userInfo["city"]!
    let state   = userInfo["state"]!
    let country = userInfo["country"]!
    
    let place = AWFPlace(city: city, state: state, country: country)
    let advisoryLoader = AWFAdvisoriesLoader()

    advisoryLoader.getAdvisoriesForPlace(place, options: nil) { (advisories, e) -> Void in
      if let error = e {
        println("Error:  (error.localizedDescription)")
      } else {
        // Take the last advisory
        if let advisory = advisories.last as? AWFAdvisory {
        
        let userInfo = [
          "location":  city + ", " + state,
          "name":  advisory.name,
          "body":  advisory.body
        ]
        
        NSNotificationCenter.defaultCenter().postNotificationName("ADVISORY_AVAILABLE",
          object: nil,
          userInfo: userInfo)
        } else {
          println("no advisories")
        }
      }
    }
  }

Now, when our WeatherServiceController receives a new location from our CoreLocationController (via a NSNotification labeled LOCATION_AVAILABLE), it will unpack this information from the userInfo dictionary, create an AWFPlace, and then use the AWFAdvisoriesLoader to load any advisories for the area.

Let’s take a look at what we’re doing with the advisories array. For simplicity, and to not barrage the user with push notifications, we’re going to take the last advisory in any list of advisories returned to us. The expression if let advisory = advisories.last as? AWFAdvisory is our use of Swift optionals to evaluate the if block to true if we have an advisory. If we do have an advisory then we create a userInfo dictionary containing the location of the advisory, the advisory name, and an advisory body which contains additional information. This information is then posted to the NSNotificationCenter with the name ADVISORY_AVAILABLE.

We’ve only scratched the surface in what is possible with the Aeris SDK. For more information on using Aeris, see the Getting Started documentation.

Pushing the Advisory

If you recall from Part One of our tutorial we created a class PushNotificationController to be responsible for managing our relationship with the Parse framework. Let’s return to our PushNotificationController class and update its init routine to handle listening for an ADVISORY_AVAILABLE notification.

The full init() function for PushNotificationController should now look like:

override init() {
    super.init()
    
    let parseApplicationId = valueForAPIKey(keyname: "PARSE_APPLICATION_ID")
    let parseClientKey     = valueForAPIKey(keyname: "PARSE_CLIENT_KEY")
    
    Parse.setApplicationId(parseApplicationId, clientKey: parseClientKey)
    
    NSNotificationCenter.defaultCenter().addObserver(self,
      selector: "advisoryAvailable:",
      name: "ADVISORY_AVAILABLE",
      object: nil)
    
  }

Now let’s write our advisoryAvailable: routine:

func advisoryAvailable(notification:NSNotification) -> Void {
    
    println("advisoryAvailable")
    
    // Get our advisory name
    let userInfo = notification.userInfo as Dictionary<String,String>
    
    let advisoryLocation = userInfo["location"]!
    let advisoryName     = userInfo["name"]!
    
    let pushMessage = "Weather Advisory for (advisoryLocation):  (advisoryName)"
    
    // Create our Installation query
    let token = PFInstallation.currentInstallation().deviceToken
    let pushQuery:PFQuery = PFInstallation.query()
    pushQuery.whereKey("deviceToken", equalTo:token)
    
    // Send push notification to query
    let pushNotification:PFPush = PFPush()
    pushNotification.setQuery(pushQuery)
    pushNotification.setData([
      "sound":"alert.caf",
      "alert":pushMessage
      ])
    pushNotification.sendPushInBackgroundWithBlock({ (succeeded,e) -> Void in
      
      if succeeded {
        println("Push message to query in background succeeded")
      }
      if let error = e {
        println("Error:  (error.localizedDescription)")
      }
    })
  }

Breaking this down, we:

  • unpack our advisory information from the NSNotification
  • build a Parse PFQuery targeted for our device
  • use Parse to send the push notification

This code uses Parse’s client push capability which must be enabled for your Parse application. Go to your application in Parse and to the Settings – Parse page and enable client push.

tut_parse_client_push

Warning!Failure to enable client push in the Parse portal will result in your push notification failing!

We should be able to now run our application and using a combination of Wunderground and Xcode simulator find a location that we know has a pending advisory. Simply look at the current weather advisories, find a city in one, and then use Google to look up the GPS coordinates. As of today there is a Coastal Flood Advisory for Franklin, Louisiana, so we’ll put it’s GPS coordinates in our Waypoints.gpx file.

tut_gps_coordinates

Remember to put a minus sign for the longitude coordinate if you want the Western hemisphere!

Putting everything together and running our application, we get a nice push notification about a coastal flood advisory in Franklin, Louisiana.

tut_weather_advisory

Adding Sound to our Push Notification

Push notifications should typically grab your attention, especially ones for weather alerts! If you recall our push notification data is set as follows:

pushNotification.setData([
      "sound":"alert.caf",
      "alert":pushMessage
      ])

The sound data specifies a sound resource to play back with the receipt of the push notification. This file has to be included in your application resources obviously to be located and played. So grab our alert.caf file and add it to your project. Then, ensure that it is added as a resource by going to your application target and selecting the Build Phases page and adding alert.caf in the Copy Bundle Resources section.

tut_copy_bundle_resources

Bitbucket Xcode Project

The work done thus far is available on Bitbucket on a branch named part3. To use the project you can directly download the zip file and open the enclosed Xcode project. There are a few steps you’ll need to complete to use the project:

  • Sign up for Parse and HAMweather and obtain your own API keys
  • Change the Bundle Identifier to reflect your organization (that is, change it.iachieved. to com.yourcompany)
  • Create and add your own ApiKeys.plist file and use your Parse and HAMweather API keys
  • Create and configure your own provisioning profile

Additional Thoughts

Our application is pretty basic. So basic, in fact, there’s no user interface. No home location we can set, no weather forecast to look at, and we can’t even choose which types of advisories we want to receive. Honestly, who needs coastal flood advisories sent to them? Well, other than those on the coast. There’s plenty we can do with the basic application framework developed, and now is where the fun can really begin.

Unfortunately, there is a bit of a flaw in our application design. What happens if an advisory is issued for an area after the user has moved into area? Oh dear. Well, perhaps we can run our application in the background and periodically wake up and check for advisories? Nope. Could we increase the frequency of receiving location updates in the background? Sure, if you wanted Apple to reject your application outright.

This is where it can become all too obvious that mobile applications that provide up-to-date information feeds typically require some type of cloud application to push those feeds to users. Taking a look at our demo application the issue is that something needs to be periodically checking whether or not there are new advisories for the user’s last known location.

Never fear. We’re going to expand this tutorial series to include utilizing Parse’s Cloud Code feature to run background jobs to update a user if there is a new advisory for their last location. Stay tuned!

By

CoreLocation on iOS 8 with Swift

Editor’s Note: This is part two in a three part series. The goal in this series is to develop a fully functional (and useful) iOS application that is capable of pushing weather alerts based on your location to your iOS device. The series is broken down as follows:

  • Part One – Developing a Push Notification-capable application with Parse and Swift
  • Part Two – Using CoreLocation with Swift
  • Part Three – Integrating in a Weather Service API

In this second part of our three part series we’ll be expanding on our weather alerts application started in Part One. A warning! The code examples that follow build upon the code in Part 1.

CoreLocation

CoreLocation is the iOS framework which provides location-based information to your application. By location we mean either the phone’s location in a GPS-coordinate space, or we can mean in reference to beacon devices. In this tutorial we are interested in the GPS location of the device.

Before we get started using CoreLocation, it is important to note that Apple has raised the bar in terms of how resource-intensive your application is with regards to using location-based services. Our application, Lewis and Clark, made use of CoreLocation to send frequent and accurate GPS locations to determine whether a user was in a new county or state. Apple had approved the application through several iterations and then rejected the application on the grounds it was requesting “navigation-level” GPS coordinates and was not a navigation application. When writing an application that makes use of location updating strive to only request the bare minimum accuracy necessary for your application to work correctly.

Okay, let’s get started. In your weatheralerts Xcode project, create a new Swift file called CoreLocationController.swift. If you don’t have the project you can get the version from here. Make sure and read the Part One post to obtain API keys for Parse and add them to your project.

CoreLocation uses the delegation pattern, so our class needs to declare that is implements the CLLocationManagerDelegate protocol. If you are unfamiliar with using the delegation pattern in iOS, see the following excellent tutorials:

Back to the code! Here is our initial content for CoreLocationController.swift:

Next let’s declare a member variable locationManager and configure it in the init() method as follows (this code goes in your CoreLocationManager class!):

Note: To declare Swift classes as delegates you must first inherit from NSObject. See Stackoverflow for a good answer as to why.

Before we forget, go to the AppDelegate and add:

as a member variable after the pushNotificationController declaration, and in the didFinishLaunchingWithOptions function add:

after the self.pushNotificationController = PushNotificationController() line.

Delegate Methods

There are a number of CoreLocation delegate methods we need to implement in our CoreLocationController class, but the first we will implement is locationManager(manager: CLLocationManager!, didChangeAuthorizationStatus status: CLAuthorizationStatus). iOS 8 introduced changes to how apps are authorized to use CoreLocation, and we want to capture when our app moves from a given authorization state to the Authorized state. To capture that transition we implement the delegate method:

If we tried to compile and run this code as is you would notice that no authorization request is made. iOS 8 requires you to not only request authorization status (with the code requestAlwaysAuthorization function), but also provide a description as to why you are requesting a given authorization. The text description is given by the key NSLocationAlwaysUsageDescription (when requesting always authorization, which is used to receive location updates while the app is in the background) in your Info.plist. To add it, edit your Info.plist in Xcode. I prefer to right-click in the Info.plist editor window and Show Raw Keys/Values before inserting a new key.

In this example we’ve added our key NSLocationAlwaysUsageDescription and the reason we give is “Your location is used to send you timely weather alerts in your immediate area.”

tut_locationalways_usage
Show Raw Keys/Values

Run the application again and you should see:

tut_access_location

Press Allow and your application should switch to an .Authorized status. If you have the same println statements in your code as above you will see in the console log:

Notice that when our app changed to .Authorized we call self.locationManager.startUpdating(). startUpdating() is a method on CLLocationManager which will be responsible for obtaining GPS coordinates and delivering them to us. And since this is a delegate pattern, we need to implement the function that will be called when CLLocationManager has GPS coordinates: locationManager(manager: CLLocationManager!, didUpdateLocations locations: [AnyObject]!).

Here’s our initial implementation of this delegate function:

Run the application again and you should begin receiving a stream of locations. Too many locations as a matter of fact, and they are all likely right on the same location. We want to fine tune how many location updates we receive, as well as our relax our accuracy requirements.

Consider our use-case, receiving weather alerts relative to our location. Does it matter if our GPS location is accurate down to a meter? No. Chances are a weather alert in your area is going to be the same as in your next-door neighbor’s area, i.e., you are in the same “area”. We can greatly reduce the demands of our application without sacrificing accuracy by relaxing our GPS accuracy to a kilometer. Moreover, we don’t need any additional updates to our location unless we move significantly, say 3 kilometers. This can be achieved by adding the following code after self.locationManager.delegate = self in our init() routine.

An illustration:
tut_accuracy_distance

The location reported by our phone is the green dot. Because our accuracy is set to one kilometer we could actually be anywhere in the blue circle. Again, we don’t really care. On the edge of the blue circle, right in the center, etc., its all the same for a weather alert. The red circle represents our distance filter, that is, the distance we have to move before we will receive another update. As long as our green dot stays within the red circle, we won’t receive an update from CoreLocation, which again is fine for our purposes.

Note: In our application we might even be better served by significant location change updates from iOS, but for our purposes we’ll use standard location updating.

Reverse Geocoding

We now have the basics for receiving location updates whenever our phone moves approximately 3 kilometers from its previous location, and our location is accurate within a kilometer. Our weather API will require us to pass city, state, and country information to provide weather alerts. We can obtain this information by using the reverse geocoding feature of the CLGeocoder class. Reverse geocoding relies on databases to take GPS coordinates and return the “address” of that location. iOS encapsulates the returned data in a CLPlacemark object which has various attributes we can extract as follows (this code goes in our didUpdateLocations delegate function):

We’ll note that the call reverseGeocodeLocation returns immediately, and it is only after the reverse geocoding results are available (a network request is made to Apple servers to look up the data) is the completionHandler block called. Heed the warning in Apple’s documentation when using reverse geocoding! Geocoding requests are rate-limited for each app, so making too many requests in a short period of time may cause some of the requests to fail. When the maximum rate is exceeded, the geocoder passes an error object with the value kCLErrorNetwork to your completion handler.

Simulating Movement

At some point we’re going to need to test our application and ensure that current weather alerts are recognized and displayed to the user. I live in North Texas, and while we do get severe weather from time to time (tornados anyone?), we don’t have severe weather every day. So how are we going to test our application? Simple. We will take a look at Wunderground’s severe weather alert map, pick a city within an alert area, look up its GPS coordinates, and give that information to Xcode to simulate for us.

Before we go into the details of getting the GPS address of a city of interest, let’s start with creating a GPX file in Xcode for GPS-location simulation. To create a GPX file use Xcode File – New – File and select iOS Resource – GPX File

tut_create_gpx_file

Name the file Waypoints. Edit the file in Xcode and delete the default waypoint (the lone <wpt/> element) and then add:

This coordinate is in Buffalo, New York, which, as of this writing, has a winter weather alert. Run the application and then use Xcode to simulate the location based upon the content of the Waypoints GPX file. This is done within Xcode, on the bar above the Debug Area notice the location arrow:

tut_simulate_waypoints

You should see after triggering the location simulator to use Waypoints:

Posting Our Location

I am a big fan of the notification model in iOS application development. Rather than add hooks across classes with references to objects, or create a new delegate protocol, simply post a notification to the notification center and let anyone who is interested in the data subscribe to it (sometimes referred to as pub-sub).

We will eventually write a class that handles taking our location and uses a weather service API to look up whether there are any active alerts. That class is going to listen for an event that the CoreLocationController will publish. For simplicity we’ll call it the LOCATION_AVAILABLE event. Here’s how we use the notification center to post it. After extracting the CLPlacemark data into a userInfo dictionary, add the following line:

Let’s go ahead and create the class that will receive and handle the notification. Create a new file called WeatherServiceController and implement the following:

Note: WeatherServiceController must inherit from NSObject to make use of the notification center. Failure to derive the class from NSObject will result in the following type of trap when the notification is posted by the CoreLocationController:

Before trying to run the again, remember, we have to create an instance of our WeatherServiceController. Head back to the AppDelegate and add:

to your member variable declarations and:

in your didFinishLaunchingWithOptions function. At this point your AppDelegate should look a bit something like this:

Running the code again and simulating to Buffalo, New York:

Receiving Events in the Background

If you’ve been working along and put the application in the background, you’ll notice no updates are received! That sort of defeats the purpose, so we have to explicitly add the capability to receive location updates in the background. Go to your application target and navigate to the Capabilities page and scroll down to Background Modes. Turn background modes on and select Location updates

tut_background_location_updates

Bitbucket Xcode Project

The work done thus far is available on Bitbucket on a branch named part2. To use the project you can directly download the zip file and open the enclosed Xcode project. There are a few steps you’ll need to complete to use the project:

  • Sign up for Parse and obtain your own API keys
  • Change the Bundle Identifier to reflect your organization (that is, change it.iachieved. to com.yourcompany)
  • Create and add your own ApiKeys.plist file and use your Parse API keys
  • Create and configure your own provisioning profile

Part 3

In part three we’ll be adding the final touches to the application which will be passing the reverse geocoded location to our weather service API. This API will in turn provide us with information about weather alerts for the area, and if any are available we will provide that information to Parse to receive a push notification.