Note: Due to the NDA, this tutorial won’t include any screenshots from Xcode 6. When iOS 8 is released, I will update the tutorial with screenshots.
Extensions were one of the more dramatic new things introduced at WWDC 2014. They allow all kinds of convenient ways to extend the power of your app beyond the app itself.
This tutorial will walk you through making a today extension for iOS 8 (commonly called a widget). Widgets display in notification center, and allow people to quickly access to bits of information or perform simple actions without having to launch your app.
Although this tutorial specifically focuses on today extensions, much of what we will cover applies to other extensions too, including sharing code & data.
Before you begin, download the source code to super simple sample app Word of the Day here. Word of the Day as you would expect, displays the word of the day from Wordsmith.org. It wouldn’t get many downloads in the App Store, but it does the job.
This is a finished project, with a widget (today extension), an embedded framework we are using to share code, and data sharing with a shared container.
Sharing Code With an Embedded Framework
One of the most important things you need to do when adding a widget to your project is to share code and files from your main project with your extension. Since extensions are separate binaries, the easiest way to do this is by creating an embedded framework, a new feature available in iOS8.
Step 1: Add a New Target
In your project, select File > New > Target. Then, on the sidebar, select Framework & Library under the iOS header, then select Cocoa Touch Framework and click Next.
Give your framework a name and click Finish.
Step 2: Add & Remove Necessary Files
Make sure to move all the necessary code and resources (including images, etc) that you will need to access from both your extension as well as your app into the new framework.
The easiest way to do this is to select your Framework target, and go to the Build Phases tab. Add all .m files to the Compile Sources phase, all .h files to the Headers phase (more details about header files below), and resources go to the Copy Bundle Resources phase.
All of these files should also be removed from the corresponding locations in the original target (your app). Make sure the files you need to access from both your app & widget are all added to your framework, and removed from your main app.
Step 3: Import Headers & Set Header Visibility
When you create your dynamic framework, it’s going to come with an umbrella header file that you can use to import other header files in the framework. For example, in our sample project, our WordOfTheDayFramework has a handy WordOfTheDayFramework.h file.
Any files that needs to be visible to the app or extension, need to be imported into this file. For example, we need both TFWordOfTheDay.h and TFWordOfTheDayFetcher.h, so we add these two lines to WordOfTheDayFramework.h:
#import "TFWordOfTheDayFetcher.h" #import "TFWordOfTheDay.h"
Note that you’ll get a build error after doing this if any of the headers you import into this master header are not public.
To change this, check your Framework’s Build Phases tab, and make sure any headers you want to access in your app or extension are in the Public visibility category. Any headers that only need to be visible to the framework should be in the Project visibility category. You can drag & drop headers from one section to another to fix this.
Note that when you create a NEW file in your framework, by default the header visibility will be set to Project. You’ll want to change that to Public if necessary.
Step 4: Link Your Framework to Your Extension
When you created your Framework, it should have automatically been embedded in your app and linked. Double check by going to your app target, under Build Phases, check that your Framework is in the Link Binary With Libraries section and the Embed Frameworks section.
Select your extension target, and add the framework to the Link Binary With Libraries section to link your framework to the widget.
Important Note: After performing this step and building your project, you’ll likely get an error like this: warning: linking against dylib not safe for use in application extensions.
To make this error go away, choose the Framework target, and under the General tab, check the Allow app extension API only box (some APIs are not available in extensions, and this will tell Xcode to warn you if you try to use any of those APIs).
Step 5: Update Framework Imports
Now that all your shared code is moved to the embedded Framework, you need to update any imports by referring to the framework. You can do this by just importing the umbrella header if you want, or import a specific file. In our sample project to import everything we could use:
Or, to import a specific header:
And that’s should be it! You should be all set to share code between your app and your extension. If I missed anything important, or if you run into any trouble, let me know in the comments.
Coming soon: In the next segment, we’ll cover sharing data & defaults between your app and widget, and after that, in the last segment, we’ll talk about debugging widgets.