How to create iOS 8 Today extension and share data with containing app – tutorial

Posted on June 28, 2014 by Lukas under iOS development | 97 comments

iOS 8 extension logoApp extensions were introduced a couple of weeks ago during WWDC 2014 Keynote as a way to extend the reach of your app to some parts of iOS (8), for example by creating a widget that will show up in Notification Center, or a custom sharing action. It’s no doubt a huge opportunity for iOS/Mac developers, so if you have an idea for a widget/extension, I suggest you start working on it as soon as you can.

If you are a registered iOS/Mac developer, definitely watch the WWDC Sessions Creating Extensions for iOS and OS X, Part 1 and 2 here. You will have a pretty good idea of what extensions are, how do they work and what you can do with them. The first part briefly explains how you can share data between your extension and containing app using NSUserDefaults, but neglects to point out some ‘pitfalls’ that you need to avoid in order to get it working. That’s where this tutorial comes in.

Warning: as of writing this (end of June’14), the Xcode 6 beta 2 (that you need to use to build your extension) has some bugs that might cause you some annoyance, but you can generally track down and then avoid the certain actions/scenarios that make problems.

What are you going to build

We are going to build a simple Today extension (that’s the name for iOS 8 widgets in Notification Center) that shows a number that can be set from the containing app (and changes made in the app will be reflected in the widget in real time). We’ll use shared NSUserDefaults to accomplish this.

iOS 8 Today extensioniOS 8 Today extension containing app

You can find the whole sample project on GitHub here.

Prerequisites

You’ll need Xcode 6 (beta 2 as of writing this, but any newer will do), and ideally a real iOS device running iOS 8 (beta 2 or higher). To obtain these beta releases, you need to be a registered iOS or Mac developer.

The step-by-step tutorial

Now I will guide you through the whole process of creating new project and doing everything necessary to get our extension to work.

1) Create new project

In Xcode 6, select File > New > Project. Select the Single view application template, and call it TodayExtensionSharingDefaults. You can use Swift if you feel like it, but we are going to stick with Objective-C for now.

Update (30 July)

If you are looking for Swift version of this code, take a look at the comments section bellow. Conrad has some hints that will help you out.

2) Add Application Extension target

In Xcode, select File > New > Target…. Then in the left pane, select Application extension and under that choose Today Extension. Because our Today extension is going to show a number, give it the name NumberWidget.

Adding Today Extension target
You will be asked if you want to activate the “NumberWidget” scheme. Click Cancel, since we are going to debug it using the normal Application scheme.

3) Set up application user interface

In Project navigator under TodayExtensionSharingDefaults group, click on Main.storyboard. Add a text field and a button.

Make the following adjustments the the text field:
– set its width to 100
– set its origin.x to 110
– set its Keyboard type to Number Pad

Make these adjustments to the button:
– set its name to “Set number”
– position it below the text field.

It should look something like this:

Today Extension sample app user interface.

Next, switch to the Assistant Editor and create outlet connection by control dragging from the text field to the interface. Call the outlet “textField”.

UITextField connection

Repeat the same for the button, but this time drag inside the implementation, and call the action “setButtonPressed”.

UIButton connection

4) Set up widget user interface

The great thing about Today extensions is that they are built using UIViewControllers, which means that you can use storyboard to build its user interface. In the project navigator, expand NumberWidget group and click on MainInterface.storyboard. Then perform the following changes:

– select the File inspector and uncheck ‘Use Auto Layout’ (for simplicity of this tutorial, we won’t use it).
– change view controllers height to 50
– select the placeholder label with white text in the middle of the view and change its text to “Number:”; its color to Light grey so we can see it and position it to the left
– add new label, change its text to 111 and its color to green. Position it next to the ‘Number:’ label.
– similarly as in the previous step, connect the 111 label to its implementation file by switching to Assistant Editor and control dragging from the label to the interface. Call the outlet ‘numberLabel’
– make the labels a little bit bigger, the way you like it

The interface should look something like this:

iOS 8 Today Extension interface

Now, you can run the project to test out the extension. When the app is launched (either on your device or in simulator), simply drag from top to show the notification center. At the bottom, tap edit and your NumberWidget should be listed in the ‘Do not include’ section. If it’s not, rebuild and then it should be there for sure.

iOS 8 Today Extension editing

You can tap the green plus button next to it to add it and then Done to go back to the Today view. But wait, the extension view has zero height now! Don’t worry, that’s because we removed auto layout and haven’t set the preferredContentSize yet. We’ll do that in a minute.

5) Enable App Groups for both targets

You need to do this to be able to share NSUserDefaults between your extension and the containing app. The process is very straightforward so lets jump right in.

In Project Navigator, click on TodayExtensionSharingDefaults project icon, then in the upper left corner click on the tiny arrow to show list of targets, then click on TodayExtensionSharingDefaultsTarget, switch to Capabilities in the top menu, and scroll down to the App Groups. This might sound a little complicated, but the following screenshot should make it clear:

App Groups settings in Xcode

Now, turn on the App Groups switch. Select your Development Team to use for provisioning and click Choose. This will add the “App Groups” entitlement to your App ID. Depending on whether you did this before or not, there might be some other groups listed in the App Groups. Either way, click + to add new App Group and call it group.TodayExtensionSharingDefaults. Then, click OK.

Update 12 August ’14 As Malcolm Hall found out and shared in comments, the App Group name has to be unique since beta 5. So use group.yourcompany.TodayExtensionSharingDefaults instead in the rest of this tutorial.

Adding new App Group in Xcode

Xcode will now add “App Groups containers” entitlement to your App ID. If everything went as it should, the new App group should be there and it should be checked (as in the following screenshot).

Xcode App Group checked

Now you need to repeat these steps for the Extension target, only this time you’ll use the already created App Group instead of creating new one. Select NumberWidget from the Targets list, turn on App Groups, select the same development team as in previous step and click Choose, and then select the group.yourcompany.TodayExtensionSharingDefaults.

Great, now we are just one step from finish! Lets get to the code.

6) The Application code

Select ViewController.m and add the following code into the -setButtonPressed method:


NSUserDefaults *sharedDefaults = [[NSUserDefaults alloc] initWithSuiteName:@"group.yourcompany.TodayExtensionSharingDefaults"];
    
[sharedDefaults setInteger:[self.textField.text integerValue] forKey:@"MyNumberKey"];
[sharedDefaults synchronize];   // (!!) This is crucial.

Here, we just alloc/init new NSUserDefaults with our App Group, and store the number entered inside the textField under MyNumberKey. Normally, you would want to define these strings as constants somewhere, but for simplicity of this tutorial we’ll leave this way. The synchronize call is crucial because we need the default to be written to disk immediately, since we will be reading it in the extension in a moment.

7) The Extension code

Open TodayViewController.m and do the following changes:

Replace -initWithNibName with the following initializer.


- (id)initWithCoder:(NSCoder *)aDecoder {
    if (self = [super initWithCoder:aDecoder]) {
        [[NSNotificationCenter defaultCenter] addObserver:self
                                                 selector:@selector(userDefaultsDidChange:)
                                                     name:NSUserDefaultsDidChangeNotification
                                                   object:nil];
    }
    return self;
}

↳ Here, we are adding an observer to the NSUserDefaultsDidChangeNotification. The NSNotificationCenter will now call our selector whenever a user default is changed.

In viewDidLoad, add these two lines:


self.preferredContentSize = CGSizeMake(320, 50);
[self updateNumberLabelText];

↳ The first one signals to the Notification Center our desired size for the widget, and the second one updates the numberLabel based on the current value of @“MyNumberKey” default.

Next, add these two methods near the end of the file (above the @end directive)


- (void)userDefaultsDidChange:(NSNotification *)notification {
    [self updateNumberLabelText];
}

- (void)updateNumberLabelText {
    NSUserDefaults *defaults = [[NSUserDefaults alloc] initWithSuiteName:@"group.yourcompany.TodayExtensionSharingDefaults"];
    NSInteger number = [defaults integerForKey:@"MyNumberKey"];
    self.numberLabel.text = [NSString stringWithFormat:@"%d", number];
}

↳ Here, we simply update the numberLabel’s text whenever defaults are changed. Note that the change notification will be posted whenever any default is changed, so if you’ll have more defaults, you might need to figure out a smarter way how/when update the values.

8) Finish!

Now you can Build and Run and you should be able to set any number inside the app and then see the change reflected in your widget immediately after opening the Notification Center.

Wrapping up

You should now have general idea how to build a very basic Today extensions and even how to share data between extension and the containing app. As I mentioned in the intro, you can find the sample app we built here on Github.

I know that this tutorial is a very rough draft and there is a lot that could be improved, but due to my other projects and deadlines, I couldn’t dedicate this more time to make it more polished. I hope it will be/was helpful to you anyway ;).

If you run into any other bugs or find something in this tutorial confusing, feel free to use the comments section below; I’ll try to help you out.

Troubleshooting

Since Xcode 6 beta 2 has quite a few bugs, you might encounter quite a few problems. What helped me:

– If, for some reason, the widget height is still 0 in the Simulator, test it on a real device
– if the widget is not reflecting new changes, you need to: delete the app from your device; reboot it; perform Clean in Xcode, and then Build and Run again. You might need to build twice in case the Today extension is not there after first Build and Run.

Where to go from here

As I mentioned in the beginning, I suggest you watch these WWDC Sessions:
Creating App Extensions for iOS and OS X, Part 1
Creating App Extensions for iOS and OS X, Part 2

Also, Apple has published a pretty good programming guide that goes in depth to what extensions are, how to use them and even provides best practices for common cases of each extension type. This is the guide:
App Extension Programming Guide

  • Nishant

    How extension will be notify, that some changes happen in containing app ?
    Because the observer added method is not get invoked.
    reason may be, When changes happen the extension controller not exist, when you open the extension, it will call init with coder and it will add observer.

    • Lukas

      Hey Nishant,
      the extension is notified by NSNotificationCenter (we are adding the observer of NSUserDefaultsDidChange for this exact purpose). Obviously when the extension is not running, it can’t be notified, but it’s not an issue because as soon as it is “launched” when the notification center is opened, it will get the current value of the default (because we are calling -updateNumberLabelText in the -viewDidLoad method). Is this comment helpful?
      Lukas

  • Andrew

    Great tutorial, but is there any chance that you could translate the extension code into Swift? I have never programmed in Objective C so translating can be a bit of a struggle for me. I managed to write the application code in Swift, but I can’t figure out the extension part.

    • Lukas

      Hi Andrew,
      thanks! I am glad you like it. Unfortunately, I haven’t had the chance to start learning Swift yet, so I probably won’t be able to help you. But I’ll try! What lines exactly are struggling with in the extension code? Past them into your answer, and I’ll look around how they can be translated to Swift.
      Cheers,
      Lukas

  • Nagesh Kumar Mishra

    Simple and Great tutorial!! Can you tell me how to open the main app, when user will tap on today extension!!

    • Lukas

      I am glad you like it! Opening the app – that’s a good question! I know it’s not possible with the plain old [UIApplication openURL;], but I remember there was a similar method mentioned in the App extension programming guide. Take a look there and you should find it ;).

  • http://github.com/kvtaniguchi Kevin Taniguchi

    Lukas – thanks for making this – on beta 4 I’m getting the following error: Failed to Inherit CoreMedia permissions – not app breaking but just wondering how to get rid of it

    • Lukas

      Kevin, you are welcome. I have honestly no idea, I haven’t installed beta 4 yet, and I probably won’t have much time this week to do it, but as soon as I try it out I’ll let you know. And if you figured it out before that, please post your solution here for other readers to know. Thanks.

      • Matt Becker

        Has there been any news on this? I am getting the same error which is preventing me from reading the NSUserDefaults within the extension.

        Failed to inherit CoreMedia permissions from 45498: (null)

        • Lukas

          No, unfortunately, there hasn’t been. I am still stuck with some client work and I need to finish it first before I get to this.

          Lukas

      • http://amtdevelop.wordpress.com Angel Traversi

        Same error with Beta 5

        • Yuta Hoshino

          Same error. objective-c, Xcode 6.0.1

        • http://www.facebook.com/profile.php?id=100003469590755 Antonio

          Hi, good work. You can actually shreotn it though. You don’t need to check whether a preference is already in the user defaults because the values you register are stored in the registration domain and returned only if the preference has not been set/changed. In other words, they are the defaults and any changes made in preferences will override then when you request a value. This is not obvious from the Apple doco, but this sentence from Accessing Preference Values, Registering Your App’s Default Preferences tells it all with regard to registerDefaults This method places your custom default values in the NSRegistrationDomain domain, which causes them to be returned when a preference is not explicitly set.

  • Conrad

    Figured this out with Swift, add the following to the ViewController.swift on the function of the button

    let sharedDefaults = NSUserDefaults(suiteName: “group.YOURGROUPHERE”)
    sharedDefaults.setObject(textField.text!, forKey: “numberPass”)
    sharedDefaults.synchronize()

    And then add this in the TodayViewController.swift in the widgetPerformUpdateWithCompletionHandler function.

    let sharedDefaults = NSUserDefaults(suiteName: “group.YOURGROUPHERE”)
    numberLabel.text = sharedDefaults.objectForKey(“numberPass”) as String

    I’m super new to iOS native dev so there might be a better way to do it. I had to clean my project each time for the extension to work properly. Once i changed the number it would change in the notification panel. Really cool stuff.

    Thanks for the tutorial as well!

    • Lim Thye Chean

      What happened if you don’t clean the project?

      Can you show the code in TodayViewController.swift?

    • Lukas

      Hey Conrad, I am glad you like it! Also, it’s great that you figured out how to do it in Swift, I will update the tutorial to direct people looking for Swift version to your comment.

    • Jak

      Would you mind posting your ViewController.swift and TodayViewController.swift? I am having trouble converting this tutorial to swift (I’m a total Xcode beginner).

      Thanks!

  • Lim Thye Chean

    Great tutorial! I have redid the tutorial in Swift – get the widget up but unfortunately get nil for the default text.

    The main issue is that after every builds I will got this error: “A signed resource has been added, modified, or deleted”, and refuse to build. The only way I can solve this is to remove and redo a new group entitlement!

    Once I can get this solved, I will look into why I get nil for the default text in widget.

    • Lim Thye Chean

      I solve my own problem. The error will go away for a clean build, and the nil issue is I forgot to do the app groups for both targets.

      • Lukas

        Hi Lim, thanks for the praise! Also, thanks for posting solution for your problem, hopefully other people who might have the same issue will find it helpful.

    • Kam

      Hi Lim Thye Chean,

      can please share Swift version of this tutorial ?

      I am looking forward to create one with NSUserDefaults

  • ajeet

    Hii, I am using your sample code, but today extension value is not changed in this code after entering in textfield ? why ?

    • Lukas

      Hi, have you followed the tutorial or just got the sample code from GitHub? If it’s the latter, you need to set up the App groups for *both* your app and the extension. See step 5 of this tutorial.

      • Ome Twi

        Hi Lukas, I think, you forgot to mention that to be able to Add Groups in the app (not in extension) one has to enable it (Add Groups ability) in provisioning file.

        • Lukas

          Hi Ome,
          thanks for your comment, but I haven’t forgotten that. Xcode provisioning profile manager does that automatically, when you turn on the App Group. But it’s true that if you already have a profile for the main app, you’d probably need to add this capability manually. So thanks for pointing that out :).

  • Max

    Hi!

    I had a look at your code, as you seem to be one of the few having implemented the
    NSUserDefaultsDidChangeNotification
    for the purpose of sending update notifications from app to widget.

    That is exactly what i tried as well, but I couldn’t get it to work and unfortunately and it seems like yours isn’t working either. The number in your widget is only updated when the Notification Center opens, but not when the app synchronizes the NSUserDefaults in the background while Notification Center is open already.
    ( I tried setting the Number and synchronizing the defaults with a delay of a few seconds and opened the Notification Center in between)

    If I’m right, the Notification has no effect in your widget code, just as in my own 🙁

    Please tell me I’m wrong, I really need this to work…

    cheers,
    Max

  • Lukas

    Hi Max,
    you are from Runtastic, huh? That’s direct competition for my app Routie, so I guess you won’t get any help from me ;D. No, I am just kidding ;). I honestly haven’t tried it with the timer, but what I would suggest you try: in the userDefaultsDidChange: method, add a dispatch_async call and then read the value from the default a second later. It might be the case that the default is not fully written to the disk when the notification is posted.

    I will get much more into it in the following weeks when I’ll start implementing this in Routie.

    Best,
    Lukas

    PS: If you do figure it out, please, post about it here. I’d really appreciate it!

    • Max

      Hi!
      I honestly haven’t thought about the competition-factor :D, but as it’s just a private project i’m working on, there’s no sweat, right? 😉

      What you suggested is exactly what i had done, hence the comment. I’ll continue to puzzle over it and will definitely share the results, if i get to the bottom of this.

      Cheers, Max

  • Lukas

    😀 Ah, okay. I thought you are working on a widget for the main Runtastic iOS app. But, you work there as an iOS developer? On the app? If yes, it’s quite cool :).

    Regarding the timer: no, I suggested adding the delay into the widget, inside the notification observer. Because the question is whether the didChangeNotification doesn’t get called at all, or if it does get called, but at the time it is called the new value is not in the defaults yet. If it was the latter, reading the default after a little while would solve the issue.
    Please let me know if this makes sense, it’s kind of hard for me to describe it clearly in English.

    Cheers,
    Lukas

    • yanv

      Hi,

      Did any of you guys manage to get this to work? It looks like NSNoticficationcenter does not work with app extensions. Please do post if you have more information on the subject.

      Cheers,
      Y.V

      • Lukas

        I’ve had a little time so I tried it, and really, it looks like the NSUserDefaultsDidChange observer method is never called. I’ll probably use timer that will poll the defaults every X seconds, and will do it in a smart way so it’s not too ineffective.

    • Max

      Hi!

      It does make sense, yes 🙂 But that wasn’t the problem 🙂

      I actually wanted to post that it actually IS working, i just used the wrong method to store the values in the shared NSUserDefault store. (I used setValue:forKey instead of setObject:forKey: – stupid auto-completion ^^)

      When I changed it to setObject:forKey / objectForKey:, it suddenly worked!

      However:
      I played around with the NSTimer, until a found a very helpful post here:

      http://stackoverflow.com/questions/8415870/scheduled-nstimer-when-app-is-in-background?lq=1

      It covers how to properly use a timer so that it will continue firing in the background (provided you have a background mode set in plist and are actually using it – location for example)

      Now my code to store the values is called also in the background, including [sharedDefaults synchronize];

      But for some reason, the notification in my widget doesn’t fire anymore 🙁

      -> i will let you know once i crack the problem.

      Cheers,
      Max

      • Max

        Update:

        NSUserDefaultsDidChangeNotification does NOT fire in the app or widget when something is changed in the other. I have been wrong about it.

        Seems like it is not supported yet. For OSX developers, i found a promising post:

        http://realmacsoftware.com/blog/shared-preferences-between-sandboxed-applications

        But if that is applicable for iOS, i don’t know & haven’t tried.

        I’m giving up on the matter, hoping the Notification will be supported in future releases.

        Cheers,
        Max

  • http://www.santiapps.com Marcio

    Everything works fine for me but I just get a 0 in the green label. Ive cleaned and deleted and reinstalled. Im on the simulator, not on the device.

    • http://www.santiapps.com Marcio

      I just saw the updates to troubleshooting. Im trying to get it on a device that hasn’t been set up for development, so im trying to use a distribution profile for test flight. I can’t get this working because i get an error saying i didn’t provide entitlement for apple security groups or something. I click on Fix Issue but it always comes back the same. So I can’t get the profile to use in TF.

      • Lukas

        Hey Marcio,
        it might be the case that the App Groups are causing this problem. As Malcolm noted in his comment, since beta 5, the App Groups need to be unique. So you need to insert your company name (or sth.) in there to make it unique. Let me know if this helps.

  • Malcolm Hall

    When I tried to add the App Group capability I got an error that the application group with identifier ‘group.TodayExtensionSharingDefaults’ is not available. And then when I tried to add it manually in the dev center I got the error: An Application Group with Identifier ‘group.TodayExtensionSharingDefaults’ is not available. Please enter a different string.

    Any idea why I can’t use that string?

    • Malcolm Hall

      Looks like the group container now has to be unique. I used group.com.mycompany.TodayExtensionSharingDefaults replacing mycompany with my domain name. And then that needs to be used in the code anywhere the defaults are accessed.

      • Lukas

        Hey Malcolm,
        thanks a lot for sharing that with us! I’ve just updated the post and gave you credit for discovering this :). I also recently got back to developing Routie update for iOS 8, and when I saw there was trouble with the App Groups, I immediately knew how to fix it. So thank you, I am sure readers coming here appreciate it as well.

  • Roy

    Hi. Thanx for the sharing. I have an additional question. I found that I can add UIScrollView in the view of widget, but scrolling was not possible. Does anybody know how to enable scrolling in the view of widget?

    • Lukas

      Hi Roy, you are welcome. Adding scroll view with vertical scrolling is probably not a good idea, because it will interfere with scrolling of the notification center itself. I think that Apple even advices against it in the extension programming guide. I suggest you try to think of a different design of your extension that doesn’t involve vertical scrolling ;).

      • Roy

        Yes, I had read that, too. But I want to know if it’s impossible or it’s just recommended not to do.

        • http://bennyTheDeveloper.com Benny

          You can use a UIScollView or its subclasses (Like UITalbeView & UICollectionView ) objects

          But, the user won’t be able to scroll them.
          And so also UISwipeGestureRecognizer won’t work.

          In the other hand, you can add button for the user like button with arrows right and left in order to scroll your UIScrollView.
          And then just implement your IBAction appropriately (see UIScrollView class ref for more details about scrolling from code)

  • Wojtek

    Hi
    I have one question. Does that code work on devices. I am asking because I made something similar and it works only in simulator. And I don’t know what I did wrong. Using ios 8 beta 5 and xcode 6.0 beta iphone 5.

    • Lukas

      Hi Wojtek,
      yes, it works on devices too. Sometimes you just need to remove the app, restart the device, and then install again to get it working.
      Lukas

    • http://www.iosdeveloper.sk FIlip

      I have the same problem.!

  • Pingback: iOS 8 Custom Keyboard extension don't allow share data with containing app?()

  • Pingback: Confluence: Emakina/Mobile()

  • David

    Great tutorial!

    The shareDefaults we use now is
    NSUserDefaults *sharedDefaults = [[NSUserDefaults alloc] initWithSuiteName:@"group.yourcompany.TodayExtensionSharingDefaults"];

    But what if I used [NSUserDefaults standardDefaults] in my existing app? Any smart way to transit the existing settings to the new userDefaults?

    • Lukas

      Thank you David!

      Well, in theory, you could make a category on NSUserDefaults that would override the -standardDefaults and would return an instance of the shared defaults, like this:


      @interface NSUserDefaults (sharing)
      @end

      @implementation NSUserDefaults (sharing)

      + (NSUserDefaults *)standardUserDefaults {
      static NSUserDefaults *suiteInstance = nil;
      if (suiteInstance == nil) {
      suiteInstance = [[NSUserDefaults alloc] initWithSuiteName:@"group.yourcompany.TodayExtensionSharingDefaults"];
      }
      return suiteInstance;
      }

      And then you would import this category everywhere you need the -standardDefaults to be overriden. Or, you could define new category method called -sharedDefaults with the same code for more clarity, and use it everywhere instead of the -standardDefaults.

      I hope this helps.
      Lukas

      • David

        Nice and neat.

        However I am concerned that there is data stored in current standardDefaults. If I push a app update to existing users, they will lose their settings due to we retrieve data from a new suite 🙁

        • Lukas

          yes, that’s true :/. I guess you will have to do some kind of migration. But, the extension will possibly need only small subset of all the defaults, won’t it? So it won’t be that bad 😉

          • David

            Need to load some purchased items.
            Have to handle with care.

            Thanks for your replies!

    • James

      Is [initWithSuiteName:] iOS7-safe?

  • Pingback: How to show touches in iOS 8 App Previews – tutorial | Glimsoft()

  • Pingback: Confluence: Technical Documentation()

  • Pingback: Day 11 | Journ3y()

  • http://onepagerapp.com/gr77 Android App Development

    Hi there to every , as I am really eager of reading this website’s post to be updated on a regular
    basis. It carries good stuff.

  • atul

    Hello Sir,
    Thnx for nice Tutorial.But i want to know one more thing if possible Let me tell something how actually Action Extension/Share Extension Will use.I have watched WWDC2014 but got no more idea,but with your tutorial i have learned very much.So please if possible then please please help me.

  • atul awasthi

    Hello Sir,
    Thnx for nice Tutorial.But i want to know one more thing if possible Let me tell something how actually Action Extension/Share Extension Will use.I have watched WWDC2014 but got no more idea,but with your tutorial i have learned very much.So please if possible then please please help me.

    • Lukas

      Hi Atul,
      I understand that it might be daunting at first. Make sure you are comfortable with view controllers in general, and then move onto the extensions. I don’t know your background, but it’s always a good idea to have solid understanding of the basics before moving further. In programming, there is no ‘skipping’. Now regarding the tutorial: I am not planning to write about it here, but maybe an article will be on Tuts+. In that case, I’ll let you know.
      Lukas

  • Bandan Preet Kaur

    Thanku ! it works perfectly , i wasted my 5 – 6 hours on updating the today widget ! atlast i got the solution thank you 🙂

    • Lukas

      You are welcome! I am glad to hear that it helped you :).

  • Ali

    Great tutorial. I’m having trouble with the App Group entitlements that I’m hoping you can help with. After creating my unique App Group, and making sure that it has App Group enabled in the Apple Developer center with its provisioning profile, I’m still getting an error which prompts me to Add the “App Groups” and “App Groups containters” entitlements to my App ID.

    I’ve tried to fix this by creating new App IDs and a new provisioning profile, but nothing has helped. Would love your input! I’m using XCode 6.1.

    • Lukas

      Hi Ali,
      I’ve had similar problem, and what helped me was to let the App Extension’s target’s provisioning profiles be managed by Xcode. In build settings inside Code Signing section, try setting ‘iOS Developer’ for the Code Signing identity, and ‘Automatic’ for Provisioning Profile. The main target could theoretically be managed by Xcode as well, though I couldn’t do that because I have the App ID in use on the App Store and I can’t change it. Also, make sure that the your widget target’s bundle identifier starts with your main target’s bundle identifier. Otherwise it doesn’t work.

      Please let me know if this helped,
      Lukas

  • Max

    Thank you soooo much for this tutorial Lukas! Helped me a lot!

    I’ve got a question about remote data in widgets that you might have an answer to:

    Let’s say that you – instead of typing – fetch the number from a remote source. To display it in your ‘main’ app and in the widget, you can make a GET request (with AFNetworking or whatever you prefer) in viewDidLoad and then proceed pretty much the same way you’ve done.

    What is unclear to me is where we put the fetch code if we want it to be called every time the user pulls down the notification center. For example: if we display the score in a hockey game, we want the number(s) displayed in our widget to be up to date without having to enter the ‘main’ app.

    Any idea?

    Thanks again!

    • Lukas

      Hi Max,
      you are welcome! I am glad it helped you.

      Regarding your question: I suggest you start the update process in -viewWillAppear. It’s called every time user (A) opens Notification Center and your widget is visible, or (B) user scrolls to your widget (in case it was outside of the visible space, if you know what I mean). That’s what I am doing in my app, Routie, and it works good.

      Let me know if this helped,
      Lukas

      • Max

        Perfect Lukas; it works! Didn’t realize it was that straight forward (and obvious) 🙂

  • Pingback: 라이브 카지노()

  • Podster

    Is there any way to use the Today Extension with iCloud and Core Data? I have not been able to get it working.

    Thanks for a great tutorial

  • http://www.emreoktem.com Wmew

    Thanks for the tutorial. This is the best explanation I could found on the internet.

    However, it doesn’t work on my case even when I tried the example code from GitHub. There is no problem about reading the data saved into the shared user defaults. When the main app has saved the value into the defaults, extension can read it when I run the code second time. However, NSUserDefaultsDidChangeNotification is not fired and the extension cannot recognize when there is a change on the main app. I am using Xcode 6.1 and also tried all methods in the comments section including signing the app.

    Thanks in advance.

    Emre

  • Pingback: TODAY EXTENSION WITH RAY | A blog about david's journey to Master Swift, one day at a time.()

  • http://WebOrCode.com Sasa

    Addind NSUserDefaultsDidChangeNotification in initWithCoder is not needed and is also misleading, because it is not working. NSNotificationCenter is not working between iOS app and app extension, it is working only in same process. Reason why new number is updated is because evert time when you do drop down of notification viewDidLoad is called and inside in you call [self updateNumberLabelText];. So please remote all code from initWithCoder because it is not working. I just spend one day figure it out.
    Your tutorial is very good as demo how to share data, but this part with NSNotificationCenter is completely wrong.

  • Jeet Chaudhary

    Thank you. It works perfectly. Best example on the internet about Today extension.I have an additional question .If possible let me tell how i can change the value of Label that used on today widget suppose I am using stopwatch In the background app. and I am displaying the value of stopwatch on the widget so how it change while the stopwatch running in background app.I want that timer value display on widget label.

  • cheulwon jung

    Thank for the good tutorial.
    This was very helpful for me.
    I have an idea about the NSUserDefaultsDidChangeNotification issue.

    please refer to the link below.

    https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/Notifications/Articles/NotificationCenters.html

    1. NSNotificationCenter
    This notification center handles notifications within a single process. For communication between processes on the same machine, use a distributed notification center (see NSDistributedNotificationCenter).

    2. NSDistributedNotificationCenter
    This distributed notification center handles notifications that can be sent between processes on a single machine.

    • cheulwon jung

      I’m afraid that NSDistributedNotificationCenter is not available on iOS.

  • Pingback: Looking back at my year 2014 | Glimsoft()

  • Rayyan

    How can i change the widget to show text instead of numbers?

    • Lukas

      Hi,
      sorry for such late reply; the blog was flooded with spam comments and I haven’t gone through them for a long time. In case you haven’t figured it out yet: it’s simple. You just need to store the text in NSUserDefaults (using methods stringForKey: and setObject:forKey:), and then set this retrieved string directly in the label.text.
      Lukas

  • Keyur Modi

    Hi Lukas,
    thats the simplest and upto the point tutorial. Thanks.
    I have a question, do you know how to make a call to the containing app from the click on a button in today widget. What should be the code in objective c?

    • Lukas

      Hi Keyur,
      thanks! I am glad you liked it.
      Now regarding your question: unfortunately, it’s not possible to call containing app like this. I’ve used a custom mechanism involving shared user defaults and pulling them every X seconds to facilitate this in my app Routie. So I would suggest doing something like that. But it really depends on your use case. By the way, what do you need the widget to do? Perhaps I could come up with some advice.
      Best regards,
      Lukas

      • keyur modi

        Hey Lukas,

        Thanks for the reply.
        I got the solution. Actually my question was like I have a button on the today widget and on the click of that button, the container app should open. I used URL scheme to open the container app.

        Regards,
        keyur

  • Pingback: Anonymous()

  • poorna sharma

    Great tutorial..

    Can u help me out with the code how to add the address book iOS SDK selected Contact when clicked as a shortcut to our Widget.?

  • Pingback: Using App Extensions for iOS 8: Today Extension | AyeOhYes!()

  • Ivette ϟ

    Gracias 😀 estoy integrando UrbanAirship pero su documentación es mala, really is so bad, tu tutorial me ayudo muchisimo a entender una parte en la que me equivocaba.

  • http://appsunited.net/ appsunited

    Lukas, you saved my day! Thanks for this great tutorial!

    • http://lukaspetr.com Lukáš Petr

      You are welcome!

  • Bikram Dhiman

    Hello Lukas, Thanks for sharing wonderful tutorials. Lukas One time I have successfully show the value but I want to change the value widget Label overtime when I submit value into textbox . Please help me. Thanks

    • http://lukaspetr.com Lukáš Petr

      Hi Bikram, I am glad you enjoyed the tutorial. You can set the value by calling the -setString: on the shared defaults. For completely live updates, you can use something like MMWormhole. Hope that helps.

  • chetan dhandal

    hi lukas, i am trying to start main (host app) from share extension.
    will you help me with that..

    • http://lukaspetr.com Lukáš Petr

      Hi Chetan, you can use the following code:
      [[self extensionContext] openURL:[NSURL URLWithString:@”yourapp://”] completionHandler:nil];
      – the “yourapp” part has to be a url scheme that is defined inside your app. Hope that helps.

      • chetan dhandal

        actually i am doing it in xamarin.mac
        and
        ExtensionContext.openURL(NSUrl (youapp://), completionHandler:null);
        this is not working…
        i am doing something wrong ..
        don’t know how to fix it…
        and i have few questions….
        how will share extension understand urlscheme of host app?
        and how can i pass arguments from share extension to app?
        Thanks and sorry to bother you.

        • http://lukaspetr.com Lukáš Petr

          Hey,
          sorry I forgot to get back to you. I don’t really know Xamarin so I can’t help you there. The url scheme of the main app obviously has to be defined in the plist file of the main app. Then, it will (should) work.

          • chetan dhandal

            ooh!,thanks a lot.
            url scheme do work fine..

  • Shrawan

    Can we share the data from the Main application to widget without provision profile . As group.yourcompany.TodayExtensionSharingDefaults requires the development account to update the capabilities . So currently i am creating the demo app With widget to share the information on it .

  • Mohamed ElBasyouni

    Lukas, can you provide the same for swift ? not Obj-C..