(224) App Extension Best Practices

Part I. Action & Share Extensions: Sophia Teutschler ‘UIKit Engineer’

Part II. Today Widget Enhancements: Ian Baird ‘CoreOS Engineer’

  1. URL Schemes: interactions take user to app !
    • use your app’s registered URL schemes: 
    • system URL Schemes: like https (Safari)
  2. User Defaults
    • used for small pieces of configuration data
    • let defaults = NSUserDefaults.initWithSuiteName(“group.com.example.my-app”) // App Group identifier
  3.  Containers
    • store Model Data in shared container (can be accessed by all extensions)
    • store Documents & Media too
    • HowTo: Setup Persistent Store CoreData in shared container: 
      fm = NSFileManager.defaultManager() 
      dir = fm.containerURLForSecurityApplicationGroupIdentifier(“group.com.example.my-app”)   
      url = dir.URLByAppendingPathComponent(“myFile.sqlite”)  
      // create storeCoordinator   
      storeCoordinator.addPersistentStoreWithType(NSSQLiteStoreType, configuration: nil, URL: url, options:…)   
      managedObjectContxt .persistentStoreCoordinator = storeCoordinator
  • Task Assertions: you want to do something uninterrupted, if interrupted -> you should clean up!
    pi = NSProcessInfo.processInfo()
    pi.performExpiringActivityWithReason(“clean-up”) {
    if (!expired) self.serializeData()
    else self.cleanupSerializeData()
  • Darwin Notification Center: similar to NSNotificationCenter
    • let nc = CFNotificationCenterGetDarwinNotifyCenter()
    • CFNotificationCenterPostNotification(nc, “com.exp.app”, nil, nil, CFBooleanGetValue(true))
  • Background Refresh 
    • System will call a function to update the View for us
    • As TodayViewController conforms to NCWidgetProviding
    • widgetPerformUpdateWithCompletionHandler(completionHandler)  {
    • let updated = refreshTheModel()
    • if (updated) { view.setNeedsDisplay()   }
    • completionHandler(updated? .NewData: .NoData)
    • }
  • Networking in Background Sessions 
    • Widget can call to the Internet by itself 
    • Important: create SessionConfiguration, set sharedContainerIdentifier for SessionConfiguration, 
    • create NSURLSession, passing the SC, use the delegate form (only the delegate form can serve the background session)
    • create NSURLRequest 
    • task = session.downloadTaskWithRequest(request)
    • task?.resume()
    • Have the Containing app handle background sessions (in case the Extension suspended or killed), the app will have to handle the session with application: handleEventsForBackgroundURLSession: completionHandler:)
    • make sure the identifier is the one we want to handle
    • make sure we save the completionHandler to a property
    • URLSessionDidFinishEventsForBackgroundURLSession
    • this function will handle all the response that come back from session started by Extension !!! 

4.  Keychain Items

To share the secret information in keychain: 

  • // Add an item: 
  • SecItemAdd ( { kSecAttrAccessGroup:”your-app-group” }, result: NULL )
  • SecItemUpdate, SecItemDelete, SecItemCopyMatching (Watch Security and your apps Video)


The 2nd part of this WWDC session presented some important tips about how to implement Today extension. We learned about how to:

  1. Use URL Scheme to handle user clicks on the Today widget
  2. How to share stuffs (configs etc.) between widget and the app using NSUserDefault,
  3. Share more stuffs, and Persistence using shared container
  4. Use Task Assertion to clean up in case the Extension is killed
  5. Use Background refresh to allow the system to update the Widget for us
  6. How to let Widget do it’s own networking in background session, and backup in containing app if Extension killed
  7. Sharing Security with the app in Keychain!