iOS 8 extensions
As we are counting days before the public release of iOS 8, we wanted to share some context and tips around App Extensions. An extension offers custom functionality of an app out to the whole system, extending it in new and meaningful ways. Once off-limits, new parts of the operating system are now open, providing fresh surface area for your app to touch. After an introduction to extensions in general, we’ll delve into the world Today widgets, which we believe will foster new and innovative ways of interacting with apps.
iOS 8 extensions
An extension’s API is defined by a particular extension point. Extension points are points on the system for an extension to bind to. This could be the Notification Center or iOS keyboard. Each extension point is packaged within a system framework, meaning that third-party extension points are not allowed. An extension point defines policy such as launch characteristics, and presentation from within the host app.
|Extension point||Example extension|
|Today||Get a quick update or perform a quick task in Today view of Notification Center (a Today extension is called a widget)|
|Share||Post to a sharing website or share content with others|
|Action||Manipulate or view content within the context of another app|
|Photo Editing||Edit a photo or video within the Photos app|
|Document provider||Provide access to and manage repository of files|
|Custom keyboard||Replace the iOS system keyboard with a custom keyboard for use in all apps|
Whether it’s translating text instantly within Safari or performing simple actions within Notification Center, extensions remove friction present in previous versions of iOS.
What is an Extension ?
An extension is meant to be streamlined and focused towards a singular task. However, it is important to realize that an app extension is not an app. Rather, an extension has its own code signature, set of entitlements, and creates its own binary. Each extension must be delivered within a containing app; an app that contains one or more extensions. When a user installs a containing app, the extension is also installed alongside it.
An extension is almost always instantiated from within a host app. For example, a user finds a picture in Safari, hits the share button, and chooses an appropriate extension. Safari is the host app and thus defines the context in which the extension lives, but does NOT launch the extension directly. Rather, Safari talks to the Social Framework, who then discovers, loads, and presents the extension. The extension code is ran, and uses system instantiated communication channels to pass data. Once complete, Safari tears down the extension view and the system terminates the process.
While running, an extension only communicates with its host app. There is no direct communication between an extension and its containing app. In addition there is no communication between the host app and containing app. Indirect communication, however, is available using well-defined API’s. They may be used when an extension asks its containing app to open (openURL:), or when an extension wishes to use a shared resource container (NSUserDefaults).
The Today widget example
Today center widgets live in the Today view of notification center. They are designed to give a user quick access to information that’s important right now. Apple has used widgets in previous versions of iOS to give updates on weather, calendar events, or to mark a reminder as completed. A widget is meant to be used for quick updates or simple tasks (such as showing latest updates or the progress of some background work, polling the user). Performance is paramount for a widget, so reconsider if you want to create an extension that performs lengthy or intensive tasks.
Add Application Extension Target
When you’re ready to start creating your widget, simply add a new Application Extension target to your containing app. You’ll be left with a property list file (Info.plist), a view controller class, and a default user interface. You’ll now see “1 New Widget Available” in Notification Center, where you can add the widget by tapping “edit”.
Enable App Groups
In order to keep your widget and containing app in sync, you will need to create a shared data container. This is accomplished by enabling the App Group entitlement for both the containing app and extension.
In Xcode, go to the “Capabilities” tab for your containing app and enable “App Groups”. Select your Development Team as provisioning and add a new group. Repeat this process for the widget target, except this time you’ll use the already created App Group instead of making a new one.
Once done, this newly created App Group needs to be registered in the developer portal. An App ID for your containing app and widget need to be added to this group. If all is well, we can now use NSUserDefaults to share data between our containing app and extension.
To enable sharing between your containing app and widget using NSUserDefaults, use initWithSuiteName: to instantiate a new NSUserDefaults object, passing in the identifier of the newly create App Group. Whenever it’s appropriate, update this shared data container for use by your widget. For example:// Create and share access to an NSUserDefaults object NSUserDefaults * mySharedDefaults = [[NSUserDefaults alloc] initWithSuitName:@"com.example.domain.MyTodayWidget"]; //Use the shared user defaults object to update the user's account [mySharedDefaults setObject:theAccountName forKey:"lastAccountName"];
Update the snapshot
The system will often take snapshots, cache them, and present them the next time your widget is presented. In order to make sure the snapshot is taken at the right time, conform to NCWidgetProviding and implement the widgetPerformUpdateWithCompletionHandler: method. Inside of this method, check to see if you have new content to be displayed and return the appropriate NSUpdateResult.
Design the UI
As space is limited for a widget, it’s important to use area in an efficient manner, while keeping user experience quick and focused. Ideally, your widget should look like it was designed by Apple. A widget’s width is constrained to the Today view, but height can be increased to display more content.
- To adjust height, Apple recommends that you use Auto Layout constraints. However, you can also use preferredContentSize:.
- To change default margin insets, conform to the NCWidgetProviding protocol and implement the widgetMarginInsetsForProposedMarginInsets: method.
- To animate the resizing of your view, use viewWillTransitionToSize:withTransitionCoordinator:.
- To mimic the blur and vibrancy effects in Notification Center you can leverage UIVisualEffectView. If you’re interested in knowing more about it, take a look on our dedicated blogpost.
As a note, keyboard entry is not supported.
Performance and Other Considerations
At its heart, a widget is a view controller. This means that it will follow the same life cycle that developers are already used to (viewWillAppear, viewDidDisappear, etc). As performance is important to a widget, make sure you’re ready to display content by the time you’re returning from viewWillAppear. This means caching data and running expensive operations ASAP and in the background. As many widgets can be open at the same time, memory limits are aggressively enforced. Being a good citizen also means not blocking main run loops or hogging GPU resources.
Not all API’s are available for extensions. These API’s are marked with an “unavailability macro”, such as NS_EXTENSION_UNAVAILABLE. Apple defines these as “inappropriate for app extensions”. A noteworthy example of this is the shared application object.
Debugging a widget in Xcode is quite similar to a normal app. Before running, choose the extension scheme in Xcode. You will then be prompted to choose a host app. In our case, “Today” will be the host. The debugger hasn’t been too consistent for beta versions of Xcode 6 and will often lose connection to the extension. It may be necessary to manually attach your extension process to the debugger by going to Debug > Attach to Process. It’s also a good idea to keep an eye on the debug gauges while running your extension.
Extensions are an exciting addition to iOS 8 that may have most visible impact in iOS 8. They’re meant to remove friction and make tasks faster and more enjoyable for all users. Extensions will provide intercommunication between apps while widgets turn notification center into a central hub for “at a glance” information and tasks.