Creating Interactive Notifications in iOS 8

Creating Notification Actions

Several times up to this point I talked about notification actions, but always generally speaking. Now, it’s time to see what they really are.

An action is an object of the UIMutableUserNotificationAction class. This class is new in iOS 8, and provides various useful properties so an action can be properly configured. These are:

  • identifier: This is a string value, that uniquely identifies an action among all in an application. Obviously, you should never define two or more actions with the same identifier. Also, using this property we’ll be able to determine the chosen action by the user upon the notification appearance. We’ll see that later.
  • title: The title is the text that is shown on the action button to the user. This can be either a simple, or a localized string. Be cautious and always set proper titles to your actions, so the user can instantly understand by reading the 1-2 title words what is going to happen by selecting it.
  • destructive: This is a bool value. When it is set to true the respective button in the notification has red background colour. Note that this happens in the banner mode only. Usually, actions regarding deletion, removal and anything else critical are marked as destructive, so they increase the user’s attention.
  • authenticationRequired: This property is a bool value also. When it becomes true, the user must necessarily authenticate himself to the device before the action is performed. It’s extremely useful in cases where the action is critical enough, and any unauthorised access can damage the application’s data.
  • activationMode: This is an enum property, and defines whether the app should run in the foreground or in the background when the action is performed. The possible values specifying each mode are two: (a) UIUserNotificationActivationModeForeground, and (b) UIUserNotificationActivationModeBackground. In background, the app is given just a few seconds to perform the action.

While I was describing this demo application, I said that we’re going to create three distinct actions:

  1. An action to just make the notification go away, without anything else to be performed.
  2. An action to edit the list (actually to add a new item).
  3. An action to delete the entire list.

Let’s see how each one is written in code. For every action, we will set the values to all the aforementioned properties. The first one:

The identifier of this action is “justInform”. As you see, this action will be performed in the background, and as there’s nothing dangerous with it we set to false the destructive and the authenticationRequired properties.

The next one:

Apparently, this action requires the app to run in the foreground so we can edit the shopping list. Also, we don’t want nobody else to mess with our list, so we set the authenticationRequired to true.

And the third and last one:

With this action we’ll allow the user to delete the entire shopping list without launching the application in the foreground. However, this is a dangerous action for the data, therefore we tell the app that it’s destructive and that authentication is required to proceed.

By looking at the above actions setup, you understand that configuring them is an easy task.

Now that we have done all the above, let’s add them to the setupNotificationSettings function we started to implement in the previous part:

Action Categories

When the actions of a notification have been defined, they can then be grouped together in categories. Actually, categories are what is written in the settings, and not the actions themselves, so you should always create them, unless of course you present a notification without actions. Usually, a category matches to a notification, so supposing that all notifications in an application support actions, there should be as many categories as the notifications.

In this demo application, we are going to create just one notification, so we are going to have one category only. Programmatically speaking now, a category is an object of the UIMutableUserNotificationCategory class, which is also new in iOS 8. This class has just one property and one method. The property is a string identifier that uniquely identifies a category (similarly to actions), and the method is used to group the actions together.

Let’s see a few more things about that method, and let’s start by its signature (taken by the Apple documentation directly):

The first parameter regards the actions that should be grouped for the category. It’s an array containing all the actions, and the order of the of the action objects in the array specifies the order they will appear in the notification.

The second parameter is quite important. The context is an enum type, and describes the context of the alert that the notification will appear into. There are two possible values:

  1. UIUserNotificationActionContextDefault: It matches to a full alert that is appeared to the centre of the screen (when the device is unlocked).
  2. UIUserNotificationActionContextMinimal: It matches to a banner alert.

In the default context, the category can accept up to four actions, which will be displayed in the predefined order in the notification alert (at the screen centre). In the minimal context, up to two actions can be set to appear in the banner alert. Notice that in the second case, you must choose what the most important actions are among all so they appear in the banner notification. In our implementation we’ll specify the actions for both contexts.

As I said, the first parameter in the above method must be an array. For this reason, our initial step is to create two arrays with the actions for each context. Let’s go back to our function:

Next, let’s create a new category for which we will set an identifier, and then we will provide the above arrays for the two contexts:

And… that’s all it takes to create a category regarding the actions of a notification.

Registering Notification Settings

In the last three parts we configured all the new features of the local notification, and now we have only left to write everything to settings. For this purpose, we will use the UIUserNotificationSettings class (new in iOS 8), and through the following init method we’ll provide the types and the category of the notification:

The first parameter is the types we defined for the notification. The second parameter is a NSSet object, in which all the categories for all the existing notifications in an application must be set. In this example, we have just one category, however we’ll create a NSSet object no matter what.

Let’s continue the function implementation with that:

Now, we can create a new object of the UIUserNotificationSettings class and pass the required arguments:

Lastly, let’s write (register) the settings in the Settings app using the next line:

The first time the above code will work, it will create a new record for our application in the Settings app.

Now, before I present you the whole setupNotificationSettings() after all the previous additions, let me say something more. This function will be called in the viewDidLoad method, and that means that its content will be executed every time the app runs. However, as the notification settings are not going to change and therefore it’s pointless to set them again and again, it would be wise to contain all the above code in an if statement. In the condition of this statement, we will check if the notification types have been specified or not, where in the second case the if body will be executed. This is translated to code as shown next:

At first, we get the existing notification settings using the currentUserNotificationSettings() method of the UIApplication class. This method returns a settings object, through which we can check the current value of the types property. Remember that this property is an enum type. If its value equals to None, meaning that no notification types have been set, then we’ll allow it to register the notification settings by doing all the above in the previous parts, otherwise will do nothing.

With the above condition we avoid unneeded settings registration. Note though that if you want to modify any settings or add more actions, categories, etc for new notifications, you should comment out the if opening and closing lines and run the app once, so the new additions to be applied and so you can test it with the new settings. Then, remove the comments to revert your code to its previous state.

With that, all the work in the notification details is over. Right next you can see the setupNotificationSettings() function fully implemented and in one part:

Don’t forget to call this function in the viewDidLoad body:

Handling Notification Actions

There is one last aspect of the local notification that we haven’t worked with yet, and that is to handle the actions that get received by the application when the user taps on the respective buttons. As usual, there are certain delegate methods that should be implemented.

Before we see what actions we’ll handle and how, let me introduce you a couple of other delegate methods that can become handy when developing your own applications. Note that in this demo we won’t really use them; we’ll just print a message to the console. Also, make sure to open the AppDelegate.swift file now.

So, the first one regards the notification settings. This delegate method is called when the app is launched (either normally or due to a local notification’s action) and contains all the settings configured for the notifications of your app. Right next you can see its definition. What we only do, is to print the current notification types:

Regardless of the above simple implementation, you can use it to access all kind of settings supported by the UIUserNotificationSettings class. This method can become useful in cases you need to check the existing settings and act depending on the values that will come up. Don’t forget that users can change these settings through the Settings app, so do never be confident that the initial configuration made in code is always valid.

When scheduling a local notification, this will be fired no matter whether your application is currently running or not. Usually, developers imagine how the notifications are going to appear when the app is in the background or suspended, and all the implementation is focused on that. However, it’s your duty to handle a notification in case it will be fired when the app is running. Thankfully, iOS SKD makes things pretty straightforward, as there’s another delegate method that is called when the app is in the foreground:

There will be cases where you won’t need to handle the notification if your app is running. However, in the opposite scenario, the above method is the place to deal with it and perform the proper actions.

Now let’s focus on the delegate method that is called when an action button is tapped by the user. Based on the identifier values we set to the actions, we’ll determine which one has been performed, and then we will make the app execute the proper part of code. We configured three actions in total:

  1. One to make the notification simply go away (identifier: justInform).
  2. One to add a new item to the list (identifier: editList).
  3. One to delete entire the list (identifier: trashAction).

From all the above, we don’t need to do anything when the first action is performed. However, we’ll handle the other two. Depending on the identifier value, we will post a notification (NSNotification) for each one, and then in the ViewController class we’ll observe for those notifications, and of course, we’ll handle them.

Let’s get started with the new delegate method:

In both cases we post a notification (a NSNotification), specifying a different name each time. Notice that at the end we call the completion handler, and that’s mandatory to do, so the system knows we handled the received action. This is the most important delegate method when working with local notifications, as this is the place where you’ll route your code depending on the action the user performed.

Now, let’s go back to the ViewController.swift file. There, let’s make that class observe for the notifications we set before. In the viewDidLoad method add the next lines:

The modifyListNotification() and deleteListNotification() are both custom functions that we’ll implement right next.

Let’s begin with the first one. What we want is to make the textfield the first responder when the app is launched due to the edit list action, so we’re just talking about one line of code only:

With this, the keyboard will automatically be shown and the user will be able to type a new item immediately.

For the delete list action, we want to remove all existing objects from the array that contains them. So, we’ll do exactly that, and then we’ll save the (empty) array back to file. Lastly, we’ll reload the tableview data, so when the user launches the app will find no items at all:

With the above implemented, our demo application is finally ready!

Creating Interactive Notifications in iOS 8

Create A Stack View With Custom Spacing iOS 11 Swift 4 XCode 9

When Apple introduced stack views in iOS 9 they made it much easier to use Auto Layout by reducing the number of constraints you needed to create yourself for many common layouts. One edge case that was not well covered was the need for custom spacing between views. You could do it by nesting stack views but that always seemed an unnecessary complication. In iOS 11 you can create stack views with custom spacing between views.

The Problem

Here is the example layout I want to create:

I have a total of five labels. A header label with a larger font size, three labels and small font size footer. The three middle labels have spacing of 8 points but I want the header and footer to have 32 points of spacing.

This vertical arrangement of views is perfect for a UIStackView apart from the spacing. The spacing property of a stack view applies equally to the arranged subviews.

Stacking Stacks

One way to create the layout without needing spacer views is to embed an inner stack view.

The inner stack view with the three labels has 8 point spacing and the outer stack view has 32 points of spacing. This works but can quickly get messy. For example, if I wanted different spacing for the header and footer.

Custom Spacing (iOS 11)

New in iOS 11 it is possible to customize the spacing after any of the arranged subviews of a stack view. Assuming we have our labels already created the code to setup the stack view might be something like this:

let stackView = UIStackView(arrangedSubviews: [headerLabel, topLabel, middleLabel, bottomLabel, footerLabel])
stackView.axis = .vertical
stackView.alignment = .fill
stackView.spacing = 8.0

This gives us 8 points of spacing between the arranged subviews. To get the extra spacing after the header label and before the footer label:

// iOS 11 only
stackView.setCustomSpacing(32.0, after: headerLabel)
stackView.setCustomSpacing(32.0, after: bottomLabel)

Notes:

  • You always specify the spacing after the arranged subview. There is no method to specify spacing before a view.
  • There is no way to specify this custom spacing in Interface Builder. You need to do it in code.
  • When you remove the subview from the stack view the system removes the custom spacing.

Standard and Default Spacing

There are two new type properties on the UIStackView class in iOS 11 that define default and system spacing:

class let spacingUseDefault: CGFloat
class let spacingUseSystem: CGFloat

You cannot rely on the values that these properties return. The actual values are tokens used to ask for the default or system spacing. System spacing seems to give 8 points of spacing on an iPhone but again you should not rely on the actual value.

You can use these to set or reset the custom spacing after a view. For example to use the system defined spacing after the top label:

stackview.setCustomSpacing(UIStackView.spacingUseSystem, after: topLabel)

To reset the spacing after this label back to the value of the spacing property (removing the custom spacing):

stackview.setCustomSpacing(UIStackView.spacingUseDefault, after: topLabel)
Create A Stack View With Custom Spacing iOS 11 Swift 4 XCode 9

WWDC 2017 Update

Xcode 9

Personally, the thing I get most excited for each WWDC is the new version of Xcode. This year, Xcode 9 was announced, and it represents a huge update with a lot of major changes we’re all going to love.

New Editor

Xcode 9 has a brand new Source Editor, entirely written in Swift. In the new editor you can use the Fix interface to fix multiple issues at once. Also, when mousing around your projects, you can hold the Command key and visually see how structures in your code are organized:

wwdc 2017

One announcement that received a strong ovation was Xcode 9 will now increase or decrease font size in the Source Editor with Command-+ or Command– – the keyboard shortcut shared by many other text editors.

And as an added bonus, the new source editor also includes an integrated Markdown editor (which will really help create some nice looking GitHub READMEs).

Refactoring

I’ve been excitedly anticipating Xcode’s ability to refactor Swift code for as long as Swift has been a thing. IDE-supported refactoring has long been a standard for top-tier development environments, and it’s so good to see this is now available in Xcode 9 for Swift code (in addition to Objective-C, C++ and C). One of the most basic refactorings is to rename a class:

wwdc 2017

Notice the class itself is renamed, and all references to that class in the project are renamed as well, including references in the Storyboard and the filename itself! Sure, renaming something isn’t that tough, but you should lean on your IDE wherever possible to make your life easier.

There’s a bunch of other refactoring options available as well, and what’s even cooler is Apple will be open sourcing the refactoring engine so others can collaboratively extend and enhance it.

Swift 4

Xcode 9 comes with Swift 4 support by default. In fact, it has a single Swift compiler that can compile both Swift 3.2 and Swift 4, and can even support different versions of Swift across different targets in the same project!

We’ll be posting a detailed roundup about What’s New in Swift 4 soon.

Xcode ❤️s GitHub

Xcode 9 now connects easily with your GitHub account (GitHub.com, or GitHub Enterprise) making it very easy to see a list of your existing projects, clone projects, manage branches, use tags, and work with remotes.

Wireless Debugging

Xcode 9 no longer requires you to connect your debugging device to your computer via USB. Now you can debug your apps on real devices over your local network. This will also work with Instruments, Accessibility Inspector, Quicktime Player, and Console.

Simulator Enhancements

There’s some really neat changes to the iOS Simulator. Now you can run multiple simulators at once!

wwdc 2017

Yes, this is a screenshot I just took, and these are all different simulators running at the same time! In addition to each simulator being resizable, simulators also include a new bezel where you can simulate different hardware interactions that weren’t possible in the past.

Testing

There were two improvements to Xcode’s automated testing support that caught my eye:

  1. Xcode UI tests can access other apps – It hasn’t been possible in the past to write Xcode UI tests for app functionality that lives inside other apps, like Settings, or Extensions. It’s now possible for your Xcode UI tests to access other apps for providing deeper verification of behavior.

    For example, if your app leverages a Share Extension to receive photos, it was not possible to write an Xcode UI test to open the Share Sheet in the Photos app to share a picture into your app. This is now possible.

  2. Tests Can Run On Simulators In Parallel – Taking advantage of the ability to run more than one iOS Simulator at the same time, automated tests can now run on more than one simulator at the same time. For example, this will be useful for running your test suite against an iOS 10 Simulator while simultaneously running the same suite on an iOS 11 Simulator.

Speed

Several changes were made to Xcode that will speed up your app development process:

  • The Xcode team put some special effort into the Source Editor to ensure high performance editing for files of all sizes.
  • Xcode comes with a new build system with much improved speed. It’s beta so it’s off by default; be sure to enable in File->Workspace Settings.
  • Additionally, if you use Quick Open or the Search Navigator, you’ll see near-instantaneous results for whatever you are searching for.

iOS 11

iOS 11 was announced today and beta 1 is already available for download. There were several features that peaked my interest.

Drag and Drop

Perhaps the most exciting iOS enhancement for me was the introduction of drag and drop to the iPad. You can now drag and drop things from one place to another, whether it’s within a single app, or even across separate apps!

As a user, you can also take advantage of other advanced multitouch interactions to continue grabbing additional items to eventually send to the destination app. UITableView and UICollectionView make it pretty easy to add drag and drop to lists in your app.

Take a look at Apple’s drag and drop documentation for a section called First Steps to understand how to add drag and drop to your app.

ARKit

WWDC 2017 introduced ARKit, a framework that provides APIs for integrating augmented reality into your apps. On iOS, augmented reality mashes up a live view from the camera, with objects you programmatically place in the view. This gives your app’s users the experience their content is a part of the real world.

Augmented reality programming without some sort of help can be very difficult. As a developer you need to figure out where your “virtual” objects should be placed in the “reality” view, how the objects should behave, and how they should appear. This is where ARKit comes to the rescue and simplifies things for you the developer.

ARKit can detect “planes” in the live camera view, essentially flat surfaces where you can programmatically place objects so it appears they’re actually sitting in the real world, while also using input from the device’s sensors to ensure these items remain in the correct place. Apple’s article on Understanding Augmented Reality is a good place to start for learning more.

Machine Learning

Machine learning is an incredibly complicated topic. Luckily, the Core ML framework was released today to help make this advanced programming technique available to a wider audience. Core ML provides an API where developers can provide a trained model, some input data, and then receive predictions about the input data based on the trained model.

Right from their documentation on Core ML, Apple provides a good example use case for Core ML: predicting real estate prices. There’s a vast amount of historical data on real estate sales. This is the “model.” Once in the proper format, Core ML can use this historical data to make a prediction of the price of a piece of real estate based on data about the house, like the number of bedrooms (assuming the model data contains both the ultimate sale price, and the number of windows for a piece of real estate). Apple even supports trained models created with certain supported third party packages.

Vision

The iOS 11 SDK introduces the Vision framework. The Vision framework provides a way for you to do high performance image analysis inside your applications.

While face detection has been available already in the CoreImage framework, the Vision framework goes further by providing the ability to not only detect faces in images, but also barcodes, text, the horizon, rectangular objects, and previously identified arbitrary objects. The Vision framework also has the ability to integrate with a Core ML model. This allows you to create entirely new detection capabilities with the Vision framework.

For example, you could integrate a Core ML trained machine learning model to identify dogs drinking water in pictures (you just need to obtain the model first which helps the Vision framework understand how to look for a dog drinking water). Take a look at the Vision framework documentation for more information.

HEVC and HEIF

Support for two new media formats was introduced with iOS 11: High Efficiency Video Coding (HEVC) and High Efficiency Image Format (HEIF). These are contemporary formats that have improvements in compression, while also recognizing today’s image and video assets are more complicated than they were in the past. Technologies like Live Photos and burst photos require more information be kept for a given image.

For example, a Live Photo may designate a “key frame” to be the thumbnail to represent the sequence of images. These new formats provide a more convenient, and smaller, way to store and represent this data. The following frameworks have been updated to support these new formats: VideoToolbox, Photos, and Core Image.

MusicKit

I’m a huge fan of music, and I’m sad to say that I traded in my Apple Music subscription for a Spotify subscription about two months ago. The changes coming with the new MusicKit framework could single-handedly bring me back as a paying Apple Music customer. One of my biggest frustrations as an Apple Music customer was the lack of access to the streamable music from within third-party applications.

There isn’t much documentation on MusicKit yet, but Apple presented that there will now be programmatic access to anything in Apple Music. Not just songs the user owns, but all the streamable music.

AirPlay 2

And related to music, AirPlay 2 is also new with iOS 11. It’s most notable feature is the added ability to stream audio across multiple devices. Think Sonos, but with your AirPlay 2 supported devices!

In for your music or podcast playing app to take advantage of this, you’ll need to call setCategory(_:mode:routeSharingPolicy:options:) on AVAudioSession with the AVAudioSessionRouteSharingPolicyLongForm parameter value.

iOS Rapid Fire

There were a bunch of other miscellaneous updates that caught my eye as well:

  • App Store Redesign – Coming with iOS 11 is a redesigned App Store app. It looks a lot like Apple Music, and has separate tabs for Apps and Games.
  • Promote in-app purchases on the App Store – Got a new in-app purchase that you would like users aware of? You can now promote in-app purchases on the App Store, and additionally, in-app purchases can also be featured on the App Store by Apple!
  • Live Photo adjustments – You can now edit Live Photos to do things like loop the Live Photo, or blur the moving parts.
  • New SiriKit Domains and Intents – Enhancements to SiriKit now make it possible to add notes, interact with to-do lists and reminders, cancel rides, and transfer money.
  • Annotate Screenshots on iPad – When taking a screenshot on your iPad, you’ll be able to quickly access the screenshot via a thumbnail in the corner of the screen, and then annotate it with markup.
  • Phased App Releases – Now you can slowly release your app over a period of time. If you’re worried about a new app update putting a heavy load on your server-side backend, this can be a way to mitigate that risk.

Hardware

Another question we love to ask ourselves each WWDC is “what new hardware will we buy?” :]

HomePod

Apple’s response to the Amazon Echo and Google Home was announced today, HomePod. It follows suit as an Internet connected speaker that has an always-listening virtual assistant.

What was most interesting to me was that Siri was totally underplayed, and instead it was the musical and audio capabilities of the speaker that were highlighted. It was almost as if it’s advertised primarily as a listening device, and as a smart device second – which is opposite of the Amazon Echo and Google Home.

HomePod can also serve as your HomeKit hub. One thing of note is until you say “Hey Siri” the HomePod will not send any information to Apple.

Refreshed Desktops

iMacs and Macbook Pros were updated with contemporary hardware and new prices.

iMac Pro

Apple announced a brand new iMac Pro that will be available in December 2017.

New iPad Pro

A new 10.5″ iPad Pro was announced effectively replacing the 9.7″ iPad, while also providing newer capabilities.

WWDC 2017 Update