app extension best practices
TRANSCRIPT
![Page 1: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/1.jpg)
© 2015 Apple Inc. All rights reserved. Redistribution or public display not permitted without written permission from Apple.
#WWDC15
App Extension Best Practices
Sophia Teutschler UIKit EngineerIan Baird CoreOS Engineer
App Frameworks
Session 224
![Page 2: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/2.jpg)
Agenda
![Page 3: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/3.jpg)
Agenda
Action and Share Extensions
![Page 4: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/4.jpg)
Agenda
Action and Share ExtensionsToday widget enhancements
![Page 5: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/5.jpg)
Agenda
Action and Share ExtensionsToday widget enhancementsReal world examples
![Page 6: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/6.jpg)
Action and Share Extensions
![Page 7: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/7.jpg)
Action and Share Extensions
ShareAction
⇄
![Page 8: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/8.jpg)
Action and Share ExtensionsAction Extensions
Action
⇄
![Page 9: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/9.jpg)
Action and Share ExtensionsAction Extensions
Acts on the current content
Action
⇄
![Page 10: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/10.jpg)
Action and Share ExtensionsAction Extensions
Acts on the current contentUses the content as the user interface
Action
⇄
![Page 11: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/11.jpg)
Action and Share ExtensionsAction Extensions
Acts on the current contentUses the content as the user interfaceOpportunity to present additional options
Action
⇄
![Page 12: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/12.jpg)
Action and Share ExtensionsAction Extensions
Acts on the current contentUses the content as the user interfaceOpportunity to present additional optionsApp can provide multiple Action Extensions
Action
⇄
![Page 13: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/13.jpg)
![Page 14: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/14.jpg)
⇄
![Page 15: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/15.jpg)
⇄⇄
![Page 16: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/16.jpg)
⇄⇄
![Page 17: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/17.jpg)
![Page 18: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/18.jpg)
![Page 19: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/19.jpg)
![Page 20: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/20.jpg)
Action and Share Extensions
ShareAction
⇄
![Page 21: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/21.jpg)
Action and Share Extensions
Share
![Page 22: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/22.jpg)
Action and Share ExtensionsShare Extensions
Share
![Page 23: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/23.jpg)
Action and Share ExtensionsShare Extensions
Shares content to your app or web service
Share
![Page 24: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/24.jpg)
Action and Share ExtensionsShare Extensions
Shares content to your app or web serviceAllows validation and editing
Share
![Page 25: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/25.jpg)
Action and Share ExtensionsShare Extensions
Shares content to your app or web serviceAllows validation and editingCan use SLComposeServiceViewController
Share
![Page 26: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/26.jpg)
Action and Share ExtensionsShare Extensions
Shares content to your app or web serviceAllows validation and editingCan use SLComposeServiceViewControllerYour app provides one Share Extension
Share
![Page 27: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/27.jpg)
![Page 28: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/28.jpg)
![Page 29: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/29.jpg)
![Page 30: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/30.jpg)
![Page 31: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/31.jpg)
![Page 32: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/32.jpg)
Action and Share ExtensionsSLComposeServiceViewController
![Page 33: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/33.jpg)
Action and Share ExtensionsSLComposeServiceViewController
![Page 34: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/34.jpg)
Action and Share ExtensionsSLComposeServiceViewController
viewController.placeholder = "Caption (Optional)"
![Page 35: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/35.jpg)
Action and Share ExtensionsSLComposeServiceViewController
viewController.placeholder = "Caption (Optional)"
![Page 36: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/36.jpg)
Action and Share ExtensionsSLComposeServiceViewController
viewController.charactersRemaining = 80
![Page 37: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/37.jpg)
Action and Share ExtensionsSLComposeServiceViewController
viewController.charactersRemaining = 80
![Page 38: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/38.jpg)
override func loadPreviewView() -> UIView! { return FaceDetectingPreviewView(…) }
Action and Share ExtensionsSLComposeServiceViewController
![Page 39: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/39.jpg)
override func loadPreviewView() -> UIView! { return FaceDetectingPreviewView(…) }
Action and Share ExtensionsSLComposeServiceViewController
![Page 40: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/40.jpg)
Action and Share ExtensionsSLComposeServiceViewController
func configurationItems() -> [SLComposeSheetConfigurationItem]
![Page 41: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/41.jpg)
Action and Share ExtensionsSLComposeServiceViewController
func configurationItems() -> [SLComposeSheetConfigurationItem]
![Page 42: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/42.jpg)
Action and Share ExtensionsSLComposeServiceViewController
override func configurationItems() -> [AnyObject]! { let item = SLComposeSheetConfigurationItem()
item.title = "Blog" item.value = "My Road Trips"
item.tapHandler = { let viewController = BlogPickerViewController() self.pushConfigurationViewController(viewController) }
return [ item ] }
![Page 43: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/43.jpg)
Action and Share ExtensionsSLComposeServiceViewController
override func configurationItems() -> [AnyObject]! { let item = SLComposeSheetConfigurationItem()
item.title = "Blog" item.value = "My Road Trips"
item.tapHandler = { let viewController = BlogPickerViewController() self.pushConfigurationViewController(viewController) }
return [ item ] }
![Page 44: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/44.jpg)
Action and Share ExtensionsSLComposeServiceViewController
override func configurationItems() -> [AnyObject]! { let item = SLComposeSheetConfigurationItem()
item.title = "Blog" item.value = "My Road Trips"
item.tapHandler = { let viewController = BlogPickerViewController() self.pushConfigurationViewController(viewController) }
return [ item ] }
![Page 45: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/45.jpg)
Action and Share ExtensionsSLComposeServiceViewController
override func configurationItems() -> [AnyObject]! { let item = SLComposeSheetConfigurationItem()
item.title = "Blog" item.value = "My Road Trips"
item.tapHandler = { let viewController = BlogPickerViewController() self.pushConfigurationViewController(viewController) }
return [ item ] }
![Page 46: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/46.jpg)
Action and Share ExtensionsSLComposeServiceViewController
override func configurationItems() -> [AnyObject]! { let item = SLComposeSheetConfigurationItem()
item.title = "Blog" item.value = "My Road Trips"
item.tapHandler = { let viewController = BlogPickerViewController() self.pushConfigurationViewController(viewController) }
return [ item ] }
![Page 47: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/47.jpg)
Action and Share ExtensionsSLComposeServiceViewController
override func configurationItems() -> [AnyObject]! { let item = SLComposeSheetConfigurationItem()
item.title = "Blog" item.value = "My Road Trips"
item.tapHandler = { let viewController = BlogPickerViewController() self.pushConfigurationViewController(viewController) }
return [ item ] }
![Page 48: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/48.jpg)
Action and Share ExtensionsSLComposeServiceViewController
override func configurationItems() -> [AnyObject]! { let item = SLComposeSheetConfigurationItem()
item.title = "Blog" item.value = "My Road Trips"
item.tapHandler = { let viewController = BlogPickerViewController() self.pushConfigurationViewController(viewController) }
return [ item ] }
![Page 49: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/49.jpg)
Action and Share ExtensionsSLComposeServiceViewController
override func configurationItems() -> [AnyObject]! { let item = SLComposeSheetConfigurationItem()
item.title = "Blog" item.value = "My Road Trips"
item.tapHandler = { let viewController = BlogPickerViewController() self.pushConfigurationViewController(viewController) }
return [ item ] }
![Page 50: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/50.jpg)
Action and Share ExtensionsSLComposeServiceViewController
override func configurationItems() -> [AnyObject]! { let item = SLComposeSheetConfigurationItem()
item.title = "Blog" item.value = "My Road Trips"
item.tapHandler = { let viewController = BlogPickerViewController() self.pushConfigurationViewController(viewController) }
return [ item ] }
![Page 51: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/51.jpg)
Action and Share ExtensionsSLComposeServiceViewController
viewController.autocompletionViewController = SuggestionViewController(…)
![Page 52: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/52.jpg)
Action and Share ExtensionsSLComposeServiceViewController
viewController.autocompletionViewController = SuggestionViewController(…)
![Page 53: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/53.jpg)
Action and Share ExtensionsSLComposeServiceViewController
![Page 54: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/54.jpg)
Action and Share ExtensionsSLComposeServiceViewController
Provides consistent and familiar UI
![Page 55: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/55.jpg)
Action and Share ExtensionsSLComposeServiceViewController
Provides consistent and familiar UICustomizable
![Page 56: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/56.jpg)
Action and Share ExtensionsSLComposeServiceViewController
Provides consistent and familiar UICustomizableCompletely custom UI using UIViewController
![Page 57: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/57.jpg)
![Page 58: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/58.jpg)
Action and Share ExtensionsBeing a good host
kUTTypePlainText
![Page 59: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/59.jpg)
Action and Share ExtensionsBeing a good host
kUTTypePDF
![Page 60: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/60.jpg)
Action and Share ExtensionsBeing a good host
kUTTypeHTML
![Page 61: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/61.jpg)
Action and Share ExtensionsBeing a good host
![Page 62: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/62.jpg)
Action and Share ExtensionsBeing a good host
kUTTypeHTMLkUTTypePDFkUTTypePlainText
![Page 63: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/63.jpg)
NSItemProvider
Action and Share ExtensionsBeing a good host
kUTTypePlainText kUTTypePDF kUTTypeHTML
![Page 64: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/64.jpg)
Action and Share ExtensionsBeing a good host
let itemProvider = NSItemProvider()
itemProvider.registerItemForTypeIdentifier(kUTTypePlainText as String) { completionHandler, expectedClass, options in completionHandler(self.renderPlainTextDocumentString(), nil) }
itemProvider.registerItemForTypeIdentifier(kUTTypePDF as String) { completionHandler, expectedClass, options in completionHandler(self.renderPDFDocument(), nil) }
let vc = UIActivityViewController(activityItems: [ itemProvider ], applicationActivities: nil) self.presentViewController(vc, animated: true, completion: nil)
![Page 65: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/65.jpg)
Action and Share ExtensionsBeing a good host
let itemProvider = NSItemProvider()
itemProvider.registerItemForTypeIdentifier(kUTTypePlainText as String) { completionHandler, expectedClass, options in completionHandler(self.renderPlainTextDocumentString(), nil) }
itemProvider.registerItemForTypeIdentifier(kUTTypePDF as String) { completionHandler, expectedClass, options in completionHandler(self.renderPDFDocument(), nil) }
let vc = UIActivityViewController(activityItems: [ itemProvider ], applicationActivities: nil) self.presentViewController(vc, animated: true, completion: nil)
![Page 66: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/66.jpg)
Action and Share ExtensionsBeing a good host
let itemProvider = NSItemProvider()
itemProvider.registerItemForTypeIdentifier(kUTTypePlainText as String) { completionHandler, expectedClass, options in completionHandler(self.renderPlainTextDocumentString(), nil) }
itemProvider.registerItemForTypeIdentifier(kUTTypePDF as String) { completionHandler, expectedClass, options in completionHandler(self.renderPDFDocument(), nil) }
let vc = UIActivityViewController(activityItems: [ itemProvider ], applicationActivities: nil) self.presentViewController(vc, animated: true, completion: nil)
![Page 67: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/67.jpg)
Action and Share ExtensionsBeing a good host
let itemProvider = NSItemProvider()
itemProvider.registerItemForTypeIdentifier(kUTTypePlainText as String) { completionHandler, expectedClass, options in completionHandler(self.renderPlainTextDocumentString(), nil) }
itemProvider.registerItemForTypeIdentifier(kUTTypePDF as String) { completionHandler, expectedClass, options in completionHandler(self.renderPDFDocument(), nil) }
let vc = UIActivityViewController(activityItems: [ itemProvider ], applicationActivities: nil) self.presentViewController(vc, animated: true, completion: nil)
![Page 68: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/68.jpg)
Action and Share ExtensionsBeing a good host
let itemProvider = NSItemProvider()
itemProvider.registerItemForTypeIdentifier(kUTTypePlainText as String) { completionHandler, expectedClass, options in completionHandler(self.renderPlainTextDocumentString(), nil) }
itemProvider.registerItemForTypeIdentifier(kUTTypePDF as String) { completionHandler, expectedClass, options in completionHandler(self.renderPDFDocument(), nil) }
let vc = UIActivityViewController(activityItems: [ itemProvider ], applicationActivities: nil) self.presentViewController(vc, animated: true, completion: nil)
![Page 69: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/69.jpg)
Action and Share ExtensionsBeing a good host
let itemProvider = NSItemProvider()
itemProvider.registerItemForTypeIdentifier(kUTTypePlainText as String) { completionHandler, expectedClass, options in completionHandler(self.renderPlainTextDocumentString(), nil) }
itemProvider.registerItemForTypeIdentifier(kUTTypePDF as String) { completionHandler, expectedClass, options in completionHandler(self.renderPDFDocument(), nil) }
let vc = UIActivityViewController(activityItems: [ itemProvider ], applicationActivities: nil) self.presentViewController(vc, animated: true, completion: nil)
![Page 70: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/70.jpg)
Action and Share ExtensionsBeing a good host
let itemProvider = NSItemProvider()
itemProvider.registerItemForTypeIdentifier(kUTTypePlainText as String) { completionHandler, expectedClass, options in completionHandler(self.renderPlainTextDocumentString(), nil) }
itemProvider.registerItemForTypeIdentifier(kUTTypePDF as String) { completionHandler, expectedClass, options in completionHandler(self.renderPDFDocument(), nil) }
let vc = UIActivityViewController(activityItems: [ itemProvider ], applicationActivities: nil) self.presentViewController(vc, animated: true, completion: nil)
![Page 71: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/71.jpg)
Action and Share ExtensionsBeing a good host
let itemProvider = NSItemProvider()
itemProvider.registerItemForTypeIdentifier(kUTTypePlainText as String) { completionHandler, expectedClass, options in completionHandler(self.renderPlainTextDocumentString(), nil) }
itemProvider.registerItemForTypeIdentifier(kUTTypePDF as String) { completionHandler, expectedClass, options in completionHandler(self.renderPDFDocument(), nil) }
let vc = UIActivityViewController(activityItems: [ itemProvider ], applicationActivities: nil) self.presentViewController(vc, animated: true, completion: nil)
![Page 72: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/72.jpg)
Action and Share ExtensionsBeing a good host
let itemProvider = NSItemProvider()
itemProvider.registerItemForTypeIdentifier(kUTTypePlainText as String) { completionHandler, expectedClass, options in completionHandler(self.renderPlainTextDocumentString(), nil) }
itemProvider.registerItemForTypeIdentifier(kUTTypePDF as String) { completionHandler, expectedClass, options in completionHandler(self.renderPDFDocument(), nil) }
let vc = UIActivityViewController(activityItems: [ itemProvider ], applicationActivities: nil) self.presentViewController(vc, animated: true, completion: nil)
![Page 73: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/73.jpg)
Action and Share ExtensionsBeing a good host
let itemProvider = NSItemProvider()
itemProvider.registerItemForTypeIdentifier(kUTTypePlainText as String) { completionHandler, expectedClass, options in completionHandler(self.renderPlainTextDocumentString(), nil) }
itemProvider.registerItemForTypeIdentifier(kUTTypePDF as String) { completionHandler, expectedClass, options in completionHandler(self.renderPDFDocument(), nil) }
let vc = UIActivityViewController(activityItems: [ itemProvider ], applicationActivities: nil) self.presentViewController(vc, animated: true, completion: nil)
![Page 74: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/74.jpg)
Action and Share ExtensionsBeing a good host
![Page 75: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/75.jpg)
Action and Share ExtensionsBeing a good host
Host apps should offer content previews
![Page 76: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/76.jpg)
Action and Share ExtensionsBeing a good host
Host apps should offer content previews• Represents what will be shared
![Page 77: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/77.jpg)
Action and Share ExtensionsBeing a good host
Host apps should offer content previews• Represents what will be shared• Simple and efficient representation of the content
![Page 78: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/78.jpg)
Action and Share ExtensionsBeing a good host
itemProvider.previewImageHandler = { completionHandler, expectedClass, options in completionHandler(self.renderThumbnail(), nil) }
![Page 79: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/79.jpg)
Action and Share ExtensionsBeing a good host
itemProvider.previewImageHandler = { completionHandler, expectedClass, options in completionHandler(self.renderThumbnail(), nil) }
![Page 80: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/80.jpg)
Action and Share ExtensionsBeing a good host
itemProvider.previewImageHandler = { completionHandler, expectedClass, options in completionHandler(self.renderThumbnail(), nil) }
![Page 81: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/81.jpg)
Action and Share ExtensionsBeing a good host
itemProvider.previewImageHandler = { completionHandler, expectedClass, options in completionHandler(self.renderThumbnail(), nil) }
![Page 82: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/82.jpg)
Action and Share ExtensionsActivation rules
![Page 83: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/83.jpg)
Action and Share ExtensionsActivation rules
Host App
kUTTypeMovie
kUTTypeImage
![Page 84: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/84.jpg)
Action and Share ExtensionsActivation rules
NSExtensionActivationSupportsImage
NSExtensionActivationSupportsMovie
NSExtensionActivationSupportsImage
NSExtensionActivationSupportsMovie
Extension
Extension
Extension
Host App
kUTTypeMovie
kUTTypeImage
![Page 85: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/85.jpg)
Action and Share ExtensionsActivation rules
Host App
kUTTypeMovie
kUTTypeImage
NSExtensionActivationSupportsImage
NSExtensionActivationSupportsMovie
NSExtensionActivationSupportsImage
NSExtensionActivationSupportsMovie
Extension
Extension
Extension
![Page 86: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/86.jpg)
Action and Share ExtensionsActivation rules
Host App
kUTTypeMovie
kUTTypeImage
NSExtensionActivationSupportsImage
NSExtensionActivationSupportsMovie
NSExtensionActivationSupportsImage
NSExtensionActivationSupportsMovie
Extension
Extension
Extension
![Page 87: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/87.jpg)
Action and Share ExtensionsActivation rules
NSExtensionActivationSupportsImage
NSExtensionActivationSupportsMovie
NSExtensionActivationSupportsImage
NSExtensionActivationSupportsMovie
Extension
Extension
Extension
Host App
kUTTypeMovie
kUTTypeImage
![Page 88: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/88.jpg)
Action and Share ExtensionsActivation rules
![Page 89: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/89.jpg)
Action and Share ExtensionsActivation rules
![Page 90: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/90.jpg)
Action and Share ExtensionsActivation rules
![Page 91: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/91.jpg)
Action and Share ExtensionsActivation rules
NSExtensionActivationSupportsImage
NSExtensionActivationSupportsMovie
NSExtensionActivationSupportsImage
NSExtensionActivationSupportsMovie
Extension
Extension
Extension
Host App
kUTTypeMovie
kUTTypeImage
![Page 92: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/92.jpg)
Action and Share ExtensionsActivation rules
SUBQUERY(extensionItems, $extensionItem, SUBQUERY($extensionItem.attachments, $attachment, ANY $attachment.registeredTypeIdentifiers UTI-CONFORMS-TO "public.image").@count == 1).@count == 1 OR SUBQUERY(extensionItems, $extensionItem, SUBQUERY($extensionItem.attachments, $attachment, ANY $attachment.registeredTypeIdentifiers UTI-CONFORMS-TO "com.adobe.pdf").@count == 1).@count == 1
![Page 93: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/93.jpg)
Action and Share ExtensionsActivation rules
SUBQUERY(extensionItems, $extensionItem, SUBQUERY($extensionItem.attachments, $attachment, ANY $attachment.registeredTypeIdentifiers UTI-CONFORMS-TO "public.image").@count == 1).@count == 1 OR SUBQUERY(extensionItems, $extensionItem, SUBQUERY($extensionItem.attachments, $attachment, ANY $attachment.registeredTypeIdentifiers UTI-CONFORMS-TO "com.adobe.pdf").@count == 1).@count == 1
![Page 94: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/94.jpg)
Action and Share ExtensionsIcons
![Page 95: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/95.jpg)
Action and Share ExtensionsIcons
Share Extensions use the containing app icon
![Page 96: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/96.jpg)
Action and Share ExtensionsIcons
Share Extensions use the containing app icon• No additional work needed
![Page 97: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/97.jpg)
Action and Share ExtensionsIcons
![Page 98: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/98.jpg)
Action and Share ExtensionsIcons
Action Extensions require template images
![Page 99: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/99.jpg)
Action and Share ExtensionsIcons
Action Extensions require template images• Two sizes for iPhone and iPad
![Page 100: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/100.jpg)
Action and Share ExtensionsIcons
Action Extensions require template images• Two sizes for iPhone and iPad• Reside in the extension bundle
![Page 101: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/101.jpg)
Action and Share ExtensionsIcons
⇄
![Page 102: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/102.jpg)
Action and Share ExtensionsAction icons
⇄
![Page 103: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/103.jpg)
Action and Share ExtensionsAction icons
76pt60pt
⇄⇄
![Page 104: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/104.jpg)
Action and Share ExtensionsAction icons
76pt60pt29pt 40pt
⇄⇄⇄⇄
![Page 105: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/105.jpg)
Today Widget Enhancements
Ian Baird CoreOS Engineer
![Page 106: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/106.jpg)
Today Widget Enhancements
Quick information at a glance
![Page 107: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/107.jpg)
Today Widget Enhancements
Quick information at a glanceEnhance your Today widget
![Page 108: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/108.jpg)
Today Widget Enhancements
Quick information at a glanceEnhance your Today widgetGeneral best practices
![Page 109: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/109.jpg)
![Page 110: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/110.jpg)
![Page 111: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/111.jpg)
![Page 112: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/112.jpg)
![Page 113: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/113.jpg)
Working with the Containing AppURL handlers
Interactions use URLs to take user to app
![Page 114: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/114.jpg)
Working with the Containing AppURL handlers
Interactions use URLs to take user to appBest practices
![Page 115: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/115.jpg)
Working with the Containing AppURL handlers
Interactions use URLs to take user to appBest practices• Use your app’s registered URL schemes
![Page 116: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/116.jpg)
Working with the Containing AppURL handlers
Interactions use URLs to take user to appBest practices• Use your app’s registered URL schemes• System URL schemes
![Page 117: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/117.jpg)
Working with the Containing AppURL handlers
Interactions use URLs to take user to app.Best practices• Use your app’s registered URL schemes• System URL schemes
func tableView(…, didSelectRowAtIndexPath indexPath: NSIndexPath) { let selectedName = names[indexPath.row] let URL = NSURL(string: "my-app://name=\(selectedName)")! extensionContext!.openURL(URL) { success in print("openURL returned: \(success)") } }
![Page 118: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/118.jpg)
Working with the Containing AppURL handlers
Interactions use URLs to take user to app.Best practices• Use your app’s registered URL schemes• System URL schemes
func tableView(…, didSelectRowAtIndexPath indexPath: NSIndexPath) { let selectedName = names[indexPath.row] let URL = NSURL(string: "my-app://name=\(selectedName)")! extensionContext!.openURL(URL) { success in print("openURL returned: \(success)") } }
![Page 119: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/119.jpg)
Working with the Containing AppURL handlers
Interactions use URLs to take user to app.Best practices• Use your app’s registered URL schemes• System URL schemes
func tableView(…, didSelectRowAtIndexPath indexPath: NSIndexPath) { let selectedName = names[indexPath.row] let URL = NSURL(string: "my-app://name=\(selectedName)")! extensionContext!.openURL(URL) { success in print("openURL returned: \(success)") } }
![Page 120: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/120.jpg)
Working with the Containing AppURL handlers
Interactions use URLs to take user to app.Best practices• Use your app’s registered URL schemes• System URL schemes
func tableView(…, didSelectRowAtIndexPath indexPath: NSIndexPath) { let selectedName = names[indexPath.row] let URL = NSURL(string: "my-app://name=\(selectedName)")! extensionContext!.openURL(URL) { success in print("openURL returned: \(success)") } }
![Page 121: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/121.jpg)
Working with the Containing AppApp groups
Defaults
![Page 122: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/122.jpg)
Working with the Containing AppApp groups
DefaultsContainers
![Page 123: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/123.jpg)
Working with the Containing AppApp groups
DefaultsContainersKeychain items
![Page 124: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/124.jpg)
Working with the Containing AppApp groups
DefaultsContainersKeychain itemsFramework data
![Page 125: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/125.jpg)
Working with the Containing AppUser defaults
![Page 126: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/126.jpg)
Working with the Containing AppUser defaults
Used for small pieces of configuration data
![Page 127: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/127.jpg)
Working with the Containing AppUser defaults
Used for small pieces of configuration data
let defaults = NSUserDefaults.initWithSuiteName("group.com.example.my-app")
![Page 128: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/128.jpg)
Working with the Containing AppWhat goes in a shared container?
Model data
![Page 129: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/129.jpg)
Working with the Containing AppWhat goes in a shared container?
Model dataDocuments
![Page 130: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/130.jpg)
Working with the Containing AppWhat goes in a shared container?
Model dataDocumentsMedia
![Page 131: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/131.jpg)
Working with the Containing AppWorking with model data in the shared container
lazy var secureAppGroupPersistentStoreURL: NSURL = { let fm = NSFileManager.defaultManager() let directory = fm.containerURLForSecurityApplicationGroupIdentifier("group.com.example.my-app")! return directory.URLByAppendingPathComponent("myFileName.sqlite") }()
![Page 132: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/132.jpg)
Working with the Containing AppWorking with model data in the shared container
lazy var secureAppGroupPersistentStoreURL: NSURL = { let fm = NSFileManager.defaultManager() let directory = fm.containerURLForSecurityApplicationGroupIdentifier("group.com.example.my-app")! return directory.URLByAppendingPathComponent("myFileName.sqlite") }()
![Page 133: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/133.jpg)
Working with the Containing AppWorking with model data in the shared container
lazy var secureAppGroupPersistentStoreURL: NSURL = { let fm = NSFileManager.defaultManager() let directory = fm.containerURLForSecurityApplicationGroupIdentifier("group.com.example.my-app")! return directory.URLByAppendingPathComponent("myFileName.sqlite") }()
![Page 134: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/134.jpg)
Working with the Containing AppWorking with model data in the shared container
lazy var secureAppGroupPersistentStoreURL: NSURL = { let fm = NSFileManager.defaultManager() let directory = fm.containerURLForSecurityApplicationGroupIdentifier("group.com.example.my-app")! return directory.URLByAppendingPathComponent("myFileName.sqlite") }()
![Page 135: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/135.jpg)
Working with the Containing AppWorking with model data in the shared container
lazy var secureAppGroupPersistentStoreURL: NSURL = { let fm = NSFileManager.defaultManager() let directory = fm.containerURLForSecurityApplicationGroupIdentifier("group.com.example.my-app")! return directory.URLByAppendingPathComponent("myFileName.sqlite") }()
![Page 136: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/136.jpg)
Working with the Containing AppWorking with model data in the shared container
lazy var persistentStoreCoordinator: NSPersistentStoreCoordinator = { let storeCoordinator = NSPersistentStoreCoordinator(managedObjectModel: self.managedObjectModel) let storeURL = self.secureAppGroupPersistentStoreURL do { try storeCoordinator.addPersistentStoreWithType(NSSQLiteStoreType, configuration: nil, URL: storeURL, options: [NSMigratePersistentStoresAutomaticallyOption: true, NSInferMappingModelAutomaticallyOption, true]) } catch let error as NSError { // handle error } return storeCoordinator }()
![Page 137: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/137.jpg)
Working with the Containing AppWorking with model data in the shared container
lazy var persistentStoreCoordinator: NSPersistentStoreCoordinator = { let storeCoordinator = NSPersistentStoreCoordinator(managedObjectModel: self.managedObjectModel) let storeURL = self.secureAppGroupPersistentStoreURL do { try storeCoordinator.addPersistentStoreWithType(NSSQLiteStoreType, configuration: nil, URL: storeURL, options: [NSMigratePersistentStoresAutomaticallyOption: true, NSInferMappingModelAutomaticallyOption, true]) } catch let error as NSError { // handle error } return storeCoordinator }()
![Page 138: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/138.jpg)
Working with the Containing AppWorking with model data in the shared container
lazy var persistentStoreCoordinator: NSPersistentStoreCoordinator = { let storeCoordinator = NSPersistentStoreCoordinator(managedObjectModel: self.managedObjectModel) let storeURL = self.secureAppGroupPersistentStoreURL do { try storeCoordinator.addPersistentStoreWithType(NSSQLiteStoreType, configuration: nil, URL: storeURL, options: [NSMigratePersistentStoresAutomaticallyOption: true, NSInferMappingModelAutomaticallyOption, true]) } catch let error as NSError { // handle error } return storeCoordinator }()
![Page 139: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/139.jpg)
Working with the Containing AppWorking with model data in the shared container
lazy var persistentStoreCoordinator: NSPersistentStoreCoordinator = { let storeCoordinator = NSPersistentStoreCoordinator(managedObjectModel: self.managedObjectModel) let storeURL = self.secureAppGroupPersistentStoreURL do { try storeCoordinator.addPersistentStoreWithType(NSSQLiteStoreType, configuration: nil, URL: storeURL, options: [NSMigratePersistentStoresAutomaticallyOption: true, NSInferMappingModelAutomaticallyOption, true]) } catch let error as NSError { // handle error } return storeCoordinator }()
![Page 140: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/140.jpg)
Working with the Containing AppWorking with model data in the shared container
lazy var persistentStoreCoordinator: NSPersistentStoreCoordinator = { let storeCoordinator = NSPersistentStoreCoordinator(managedObjectModel: self.managedObjectModel) let storeURL = self.secureAppGroupPersistentStoreURL do { try storeCoordinator.addPersistentStoreWithType(NSSQLiteStoreType, configuration: nil, URL: storeURL, options: [NSMigratePersistentStoresAutomaticallyOption: true, NSInferMappingModelAutomaticallyOption, true]) } catch let error as NSError { // handle error } return storeCoordinator }()
![Page 141: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/141.jpg)
Working with the Containing AppWorking with model data in the shared container
lazy var persistentStoreCoordinator: NSPersistentStoreCoordinator = { let storeCoordinator = NSPersistentStoreCoordinator(managedObjectModel: self.managedObjectModel) let storeURL = self.secureAppGroupPersistentStoreURL do { try storeCoordinator.addPersistentStoreWithType(NSSQLiteStoreType, configuration: nil, URL: storeURL, options: [NSMigratePersistentStoresAutomaticallyOption: true, NSInferMappingModelAutomaticallyOption, true]) } catch let error as NSError { // handle error } return storeCoordinator }()
![Page 142: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/142.jpg)
Working with the Containing AppWorking with model data in the shared container
lazy var managedObjectContext: NSManagedObjectContext = { let coordinator = self.persistentStoreCoordinator var managedObjectContext = NSManagedObjectContext(concurrencyType: .MainQueueConcurrencyType) managedObjectContext.persistentStoreCoordinator = coordinator return managedObjectContext }()
![Page 143: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/143.jpg)
Working with the Containing AppWorking with model data in the shared container
lazy var managedObjectContext: NSManagedObjectContext = { let coordinator = self.persistentStoreCoordinator var managedObjectContext = NSManagedObjectContext(concurrencyType: .MainQueueConcurrencyType) managedObjectContext.persistentStoreCoordinator = coordinator return managedObjectContext }()
![Page 144: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/144.jpg)
Working with the Containing AppWorking with model data in the shared container
lazy var managedObjectContext: NSManagedObjectContext = { let coordinator = self.persistentStoreCoordinator var managedObjectContext = NSManagedObjectContext(concurrencyType: .MainQueueConcurrencyType) managedObjectContext.persistentStoreCoordinator = coordinator return managedObjectContext }()
![Page 145: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/145.jpg)
Working with the Containing AppWorking with model data in the shared container
lazy var managedObjectContext: NSManagedObjectContext = { let coordinator = self.persistentStoreCoordinator var managedObjectContext = NSManagedObjectContext(concurrencyType: .MainQueueConcurrencyType) managedObjectContext.persistentStoreCoordinator = coordinator return managedObjectContext }()
![Page 146: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/146.jpg)
Staying ResponsiveLocking in the shared container
![Page 147: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/147.jpg)
Staying ResponsiveLocking in the shared container
Be careful taking exclusive locks for data in the shared container
![Page 148: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/148.jpg)
Staying ResponsiveLocking in the shared container
Be careful taking exclusive locks for data in the shared containerExtension killed if it’s suspended while holding an exclusive lock
![Page 149: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/149.jpg)
Staying ResponsiveTask assertions
Extensions suspended when no longer in use
![Page 150: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/150.jpg)
Staying ResponsiveTask assertions
Extensions suspended when no longer in useProtect serialization and other clean-up tasks with background task assertions
![Page 151: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/151.jpg)
Staying ResponsiveTask assertions
let pi = NSProcessInfo.processInfo() pi.performExpiringActivityWithReason("clean-up") { expired in if (!expired) { self.serializeData() } else { self.cleanupSerializingData() } }
![Page 152: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/152.jpg)
Staying ResponsiveTask assertions
let pi = NSProcessInfo.processInfo() pi.performExpiringActivityWithReason("clean-up") { expired in if (!expired) { self.serializeData() } else { self.cleanupSerializingData() } }
![Page 153: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/153.jpg)
Staying ResponsiveTask assertions
let pi = NSProcessInfo.processInfo() pi.performExpiringActivityWithReason("clean-up") { expired in if (!expired) { self.serializeData() } else { self.cleanupSerializingData() } }
![Page 154: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/154.jpg)
Staying ResponsiveTask assertions
let pi = NSProcessInfo.processInfo() pi.performExpiringActivityWithReason("clean-up") { expired in if (!expired) { self.serializeData() } else { self.cleanupSerializingData() } }
![Page 155: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/155.jpg)
Staying ResponsiveTask assertions
let pi = NSProcessInfo.processInfo() pi.performExpiringActivityWithReason("clean-up") { expired in if (!expired) { self.serializeData() } else { self.cleanupSerializingData() } }
expired == false
![Page 156: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/156.jpg)
Staying ResponsiveTask assertions
let pi = NSProcessInfo.processInfo() pi.performExpiringActivityWithReason("clean-up") { expired in if (!expired) { self.serializeData() } else { self.cleanupSerializingData() } }
expired == false –> perform protected task
![Page 157: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/157.jpg)
Staying ResponsiveTask assertions
let pi = NSProcessInfo.processInfo() pi.performExpiringActivityWithReason("clean-up") { expired in if (!expired) { self.serializeData() } else { self.cleanupSerializingData() } }
expired == true
![Page 158: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/158.jpg)
Staying ResponsiveTask assertions
let pi = NSProcessInfo.processInfo() pi.performExpiringActivityWithReason("clean-up") { expired in if (!expired) { self.serializeData() } else { self.cleanupSerializingData() } }
expired == true -> cancel protected task
![Page 159: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/159.jpg)
Staying ResponsiveTask assertions
let pi = NSProcessInfo.processInfo() pi.performExpiringActivityWithReason("clean-up") { expired in if (!expired) { self.serializeData() } else { self.cleanupSerializingData() } }
exit the block -> task assertion is released
![Page 160: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/160.jpg)
Staying ResponsiveTask assertions
let pi = NSProcessInfo.processInfo() pi.performExpiringActivityWithReason("clean-up") { expired in if (!expired) { self.serializeData() } else { self.cleanupSerializingData() } }
expired == true
![Page 161: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/161.jpg)
Staying ResponsiveTask assertions
let pi = NSProcessInfo.processInfo() pi.performExpiringActivityWithReason("clean-up") { expired in if (!expired) { self.serializeData() } else { self.cleanupSerializingData() } }
expired == true -> cancel any work and exit the block
![Page 162: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/162.jpg)
Staying ResponsiveTask assertions
Released when your code exits the block
![Page 163: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/163.jpg)
Staying ResponsiveTask assertions
Released when your code exits the blockRe-entrant execution of callback for expiration
![Page 164: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/164.jpg)
Staying ResponsiveTask assertions
Released when your code exits the blockRe-entrant execution of callback for expirationTask assertions are not always available for your extension
![Page 165: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/165.jpg)
Staying ResponsiveWorking with other queues
Task assertion scoped to callback block
![Page 166: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/166.jpg)
Staying ResponsiveWorking with other queues
Task assertion scoped to callback blockCallback block must synchronize with protected work on other queues
![Page 167: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/167.jpg)
Staying ResponsiveWorking with other queues
Task assertion scoped to callback blockCallback block must synchronize with protected work on other queuesExample
![Page 168: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/168.jpg)
Staying ResponsiveWorking with other queues
Task assertion scoped to callback blockCallback block must synchronize with protected work on other queuesExample• Dispatch block to the main queue
![Page 169: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/169.jpg)
Staying ResponsiveWorking with the main queue
let pi = NSProcessInfo.processInfo() pi.performExpiringActivityWithReason("clean-up") { expired in if (!expired) { dispatch_async(dispatch_get_main_queue(), { self.performInterruptibleWork() }) } else { self.canceled = true } }
![Page 170: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/170.jpg)
Staying ResponsiveWorking with the main queue
let pi = NSProcessInfo.processInfo() pi.performExpiringActivityWithReason("clean-up") { expired in if (!expired) { dispatch_async(dispatch_get_main_queue(), { self.performInterruptibleWork() }) } else { self.canceled = true } }
![Page 171: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/171.jpg)
Staying ResponsiveWorking with the main queue
let pi = NSProcessInfo.processInfo() pi.performExpiringActivityWithReason("clean-up") { expired in if (!expired) { dispatch_sync(dispatch_get_main_queue(), { self.performInterruptibleWork() }) } else { self.canceled = true } }
![Page 172: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/172.jpg)
Staying ResponsiveWorking with the main queue
let pi = NSProcessInfo.processInfo() pi.performExpiringActivityWithReason("clean-up") { expired in if (!expired) { dispatch_sync(dispatch_get_main_queue(), { self.performInterruptibleWork() }) } else { self.canceled = true } }
![Page 173: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/173.jpg)
Staying ResponsiveWorking with the main queue
let pi = NSProcessInfo.processInfo() pi.performExpiringActivityWithReason("clean-up") { expired in if (!expired) { dispatch_sync(dispatch_get_main_queue(), { self.performInterruptibleWork() }) } else { self.canceled = true } }
Callback block is executing on a private system queue
![Page 174: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/174.jpg)
Staying Up to DateDarwin Notification Center
Similar to NSNotificationCenter
![Page 175: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/175.jpg)
Staying Up to DateDarwin Notification Center
Similar to NSNotificationCenter
![Page 176: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/176.jpg)
Staying Up to DateDarwin Notification Center
Similar to NSNotificationCenterSmall number of use-cases
![Page 177: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/177.jpg)
Staying Up to DateDarwin Notification Center
Similar to NSNotificationCenterSmall number of use-casesExample
![Page 178: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/178.jpg)
Staying Up to DateDarwin Notification Center
Similar to NSNotificationCenterSmall number of use-casesExample• Hint to your extension to reload the model
![Page 179: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/179.jpg)
Staying Up to DateContaining app API
let nc = CFNotificationCenterGetDarwinNotifyCenter() CFNotificationCenterPostNotification(nc, "com.example.app-model-updated", nil, nil, CFBooleanGetValue(true))
![Page 180: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/180.jpg)
Staying Up to DateContaining app API
let nc = CFNotificationCenterGetDarwinNotifyCenter() CFNotificationCenterPostNotification(nc, "com.example.app-model-updated", nil, nil, CFBooleanGetValue(true))
![Page 181: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/181.jpg)
Staying Up to DateContaining app API
let nc = CFNotificationCenterGetDarwinNotifyCenter() CFNotificationCenterPostNotification(nc, "com.example.app-model-updated", nil, nil, CFBooleanGetValue(true))
![Page 182: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/182.jpg)
Staying Up to DateContaining app API
let nc = CFNotificationCenterGetDarwinNotifyCenter() CFNotificationCenterPostNotification(nc, "com.example.app-model-updated", nil, nil, CFBooleanGetValue(true))
![Page 183: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/183.jpg)
Staying Up to DateExtension API
let nc = CFNotificationCenterGetDarwinNotifyCenter() CFNotificationCenterAddObserver(nc, nil, { _ in self.reloadModel() }, "com.example.app-model-updated", nil, .DeliverImmediately)
![Page 184: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/184.jpg)
Staying Up to DateExtension API
let nc = CFNotificationCenterGetDarwinNotifyCenter() CFNotificationCenterAddObserver(nc, nil, { _ in self.reloadModel() }, "com.example.app-model-updated", nil, .DeliverImmediately)
![Page 185: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/185.jpg)
Staying Up to DateExtension API
let nc = CFNotificationCenterGetDarwinNotifyCenter() CFNotificationCenterAddObserver(nc, nil, { _ in self.reloadModel() }, "com.example.app-model-updated", nil, .DeliverImmediately)
![Page 186: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/186.jpg)
Staying Up to DateExtension API
let nc = CFNotificationCenterGetDarwinNotifyCenter() CFNotificationCenterAddObserver(nc, nil, { _ in self.reloadModel() }, "com.example.app-model-updated", nil, .DeliverImmediately)
![Page 187: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/187.jpg)
Staying Up to DateExtension API
let nc = CFNotificationCenterGetDarwinNotifyCenter() CFNotificationCenterAddObserver(nc, nil, { _ in self.reloadModel() }, "com.example.app-model-updated", nil, .DeliverImmediately)
![Page 188: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/188.jpg)
Background RefreshKeeping your widget up to date
![Page 189: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/189.jpg)
![Page 190: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/190.jpg)
Background Refresh
![Page 191: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/191.jpg)
Background Refresh
AAPL: $132.12
![Page 192: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/192.jpg)
![Page 193: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/193.jpg)
![Page 194: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/194.jpg)
Background RefreshUpdating the widget
System opportunistically refreshes content
![Page 195: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/195.jpg)
Background RefreshUpdating the widget
System opportunistically refreshes contentView controller conforms to NCWidgetProviding
![Page 196: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/196.jpg)
Background RefreshUpdating the widget
System opportunistically refreshes contentView controller conforms to NCWidgetProvidingImplements update delegate method
![Page 197: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/197.jpg)
Background RefreshUpdating the widget
System opportunistically refreshes contentView controller conforms to NCWidgetProvidingImplements update delegate method
func widgetPerformUpdateWithCompletionHandler(completionHandler: ((NCUpdateResult) -> Void)) { let updated = refreshTheModel() if (updated) { view.setNeedsDisplay() } completionHandler(updated ? .NewData : .NoData) }
![Page 198: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/198.jpg)
Background RefreshUpdating the widget
System opportunistically refreshes contentView controller conforms to NCWidgetProvidingImplements update delegate method
func widgetPerformUpdateWithCompletionHandler(completionHandler: ((NCUpdateResult) -> Void)) { let updated = refreshTheModel() if (updated) { view.setNeedsDisplay() } completionHandler(updated ? .NewData : .NoData) }
![Page 199: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/199.jpg)
Background RefreshUpdating the widget
func widgetPerformUpdateWithCompletionHandler(completionHandler: ((NCUpdateResult) -> Void)) { let updated = refreshTheModel() if (updated) { view.setNeedsDisplay() } completionHandler(updated ? .NewData : .NoData) }
System opportunistically refreshes contentView controller conforms to NCWidgetProvidingImplements update delegate method
![Page 200: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/200.jpg)
Background RefreshUpdating the widget
func widgetPerformUpdateWithCompletionHandler(completionHandler: ((NCUpdateResult) -> Void)) { let updated = refreshTheModel() if (updated) { view.setNeedsDisplay() } completionHandler(updated ? .NewData : .NoData) }
System opportunistically refreshes contentView controller conforms to NCWidgetProvidingImplements update delegate method
![Page 201: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/201.jpg)
Background RefreshUpdating the widget
func widgetPerformUpdateWithCompletionHandler(completionHandler: ((NCUpdateResult) -> Void)) { let updated = refreshTheModel() if (updated) { view.setNeedsDisplay() } completionHandler(updated ? .NewData : .NoData) }
System opportunistically refreshes contentView controller conforms to NCWidgetProvidingImplements update delegate method
![Page 202: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/202.jpg)
![Page 203: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/203.jpg)
![Page 204: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/204.jpg)
NetworkingBackground sessions
![Page 205: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/205.jpg)
NetworkingNSURLSession
Background sessions
![Page 206: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/206.jpg)
NetworkingNSURLSession
Background sessionsTask performed by the system
![Page 207: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/207.jpg)
NetworkingNSURLSession
Background sessionsTask performed by the systemUpdates delivered to your extension as long as it stays alive
![Page 208: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/208.jpg)
NetworkingNSURLSession
Background sessionsTask performed by the systemUpdates delivered to your extension as long as it stays aliveError and event handled by the containing app
![Page 209: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/209.jpg)
NetworkingNSURLSession
Background sessionsTask performed by the systemUpdates delivered to your extension as long as it stays aliveError and event handled by the containing app
![Page 210: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/210.jpg)
NetworkingExtension API
let sc = NSURLSessionConfiguration.backgroundSessionConfigurationWithIdentifier( "com.example.my-download-session") sc.sharedContainerIdentifier = "group.com.example.my-app" let session = NSURLSession(configuration: sc, delegate: self, delegateQueue: NSOperationQueue.mainQueue()) let request = NSURLRequest(URL: NSURL(string: "https://www.apple.com/")!) let task = session.downloadTaskWithRequest(request) task?.resume()
![Page 211: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/211.jpg)
NetworkingExtension API
let sc = NSURLSessionConfiguration.backgroundSessionConfigurationWithIdentifier( "com.example.my-download-session") sc.sharedContainerIdentifier = "group.com.example.my-app" let session = NSURLSession(configuration: sc, delegate: self, delegateQueue: NSOperationQueue.mainQueue()) let request = NSURLRequest(URL: NSURL(string: "https://www.apple.com/")!) let task = session.downloadTaskWithRequest(request) task?.resume()
![Page 212: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/212.jpg)
NetworkingExtension API
let sc = NSURLSessionConfiguration.backgroundSessionConfigurationWithIdentifier( "com.example.my-download-session") sc.sharedContainerIdentifier = "group.com.example.my-app" let session = NSURLSession(configuration: sc, delegate: self, delegateQueue: NSOperationQueue.mainQueue()) let request = NSURLRequest(URL: NSURL(string: "https://www.apple.com/")!) let task = session.downloadTaskWithRequest(request) task?.resume()
![Page 213: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/213.jpg)
NetworkingExtension API
let sc = NSURLSessionConfiguration.backgroundSessionConfigurationWithIdentifier( "com.example.my-download-session") sc.sharedContainerIdentifier = "group.com.example.my-app" let session = NSURLSession(configuration: sc, delegate: self, delegateQueue: NSOperationQueue.mainQueue()) let request = NSURLRequest(URL: NSURL(string: “https://www.apple.com/")!) let task = session.downloadTaskWithRequest(request) task?.resume()
![Page 214: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/214.jpg)
NetworkingExtension API
let sc = NSURLSessionConfiguration.backgroundSessionConfigurationWithIdentifier( "com.example.my-download-session") sc.sharedContainerIdentifier = "group.com.example.my-app" let session = NSURLSession(configuration: sc, delegate: self, delegateQueue: NSOperationQueue.mainQueue()) let request = NSURLRequest(URL: NSURL(string: "https://www.apple.com/")!) let task = session.downloadTaskWithRequest(request) task?.resume()
![Page 215: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/215.jpg)
NetworkingExtension API
let sc = NSURLSessionConfiguration.backgroundSessionConfigurationWithIdentifier( "com.example.my-download-session") sc.sharedContainerIdentifier = "group.com.example.my-app" let session = NSURLSession(configuration: sc, delegate: self, delegateQueue: NSOperationQueue.mainQueue()) let request = NSURLRequest(URL: NSURL(string: "https://www.apple.com/")!) let task = session.downloadTaskWithRequest(request) task?.resume()
![Page 216: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/216.jpg)
NetworkingExtension API
let sc = NSURLSessionConfiguration.backgroundSessionConfigurationWithIdentifier( "com.example.my-download-session") sc.sharedContainerIdentifier = "group.com.example.my-app" let session = NSURLSession(configuration: sc, delegate: self, delegateQueue: NSOperationQueue.mainQueue()) let request = NSURLRequest(URL: NSURL(string: "https://www.apple.com/")!) let task = session.downloadTaskWithRequest(request) task?.resume()
![Page 217: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/217.jpg)
NetworkingContaining app API
func application(application: UIApplication, handleEventsForBackgroundURLSession identifier: String, completionHandler: () -> Void) { guard (identifier == "com.example.my-download-session") else { return } let sc = NSURLSessionConfiguration.backgroundSessionConfigurationWithIdentifier(identifier) sc.sharedContainerIdentifier = "group.com.example.my-app" self.session = NSURLSession(configuration: sc, delegate: self, delegateQueue: NSOperationQueue.mainQueue()) self.completionHandler = completionHandler }
![Page 218: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/218.jpg)
NetworkingContaining app API
func application(application: UIApplication, handleEventsForBackgroundURLSession identifier: String, completionHandler: () -> Void) { guard (identifier == "com.example.my-download-session") else { return } let sc = NSURLSessionConfiguration.backgroundSessionConfigurationWithIdentifier(identifier) sc.sharedContainerIdentifier = "group.com.example.my-app" self.session = NSURLSession(configuration: sc, delegate: self, delegateQueue: NSOperationQueue.mainQueue()) self.completionHandler = completionHandler }
![Page 219: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/219.jpg)
NetworkingContaining app API
func application(application: UIApplication, handleEventsForBackgroundURLSession identifier: String, completionHandler: () -> Void) { guard (identifier == "com.example.my-download-session") else { return } let sc = NSURLSessionConfiguration.backgroundSessionConfigurationWithIdentifier(identifier) sc.sharedContainerIdentifier = "group.com.example.my-app" self.session = NSURLSession(configuration: sc, delegate: self, delegateQueue: NSOperationQueue.mainQueue()) self.completionHandler = completionHandler }
![Page 220: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/220.jpg)
NetworkingContaining app API
func application(application: UIApplication, handleEventsForBackgroundURLSession identifier: String, completionHandler: () -> Void) { guard (identifier == "com.example.my-download-session") else { return } let sc = NSURLSessionConfiguration.backgroundSessionConfigurationWithIdentifier(identifier) sc.sharedContainerIdentifier = "group.com.example.my-app" self.session = NSURLSession(configuration: sc, delegate: self, delegateQueue: NSOperationQueue.mainQueue()) self.completionHandler = completionHandler }
![Page 221: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/221.jpg)
NetworkingContaining app API
func application(application: UIApplication, handleEventsForBackgroundURLSession identifier: String, completionHandler: () -> Void) { guard (identifier == "com.example.my-download-session") else { return } let sc = NSURLSessionConfiguration.backgroundSessionConfigurationWithIdentifier(identifier) sc.sharedContainerIdentifier = "group.com.example.my-app" self.session = NSURLSession(configuration: sc, delegate: self, delegateQueue: NSOperationQueue.mainQueue()) self.completionHandler = completionHandler }
![Page 222: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/222.jpg)
NetworkingContaining app API
func application(application: UIApplication, handleEventsForBackgroundURLSession identifier: String, completionHandler: () -> Void) { guard (identifier == "com.example.my-download-session") else { return } let sc = NSURLSessionConfiguration.backgroundSessionConfigurationWithIdentifier(identifier) sc.sharedContainerIdentifier = "group.com.example.my-app" self.session = NSURLSession(configuration: sc, delegate: self, delegateQueue: NSOperationQueue.mainQueue()) self.completionHandler = completionHandler }
![Page 223: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/223.jpg)
NetworkingContaining app API
func URLSessionDidFinishEventsForBackgroundURLSession(session: NSURLSession){ let sc = session.configuration guard (sc.identifier == "com.example.my-download-session") else { return } self.completionHandler!() self.session = nil }
![Page 224: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/224.jpg)
NetworkingContaining app API
func URLSessionDidFinishEventsForBackgroundURLSession(session: NSURLSession){ let sc = session.configuration guard (sc.identifier == "com.example.my-download-session") else { return } self.completionHandler!() self.session = nil }
![Page 225: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/225.jpg)
NetworkingContaining app API
func URLSessionDidFinishEventsForBackgroundURLSession(session: NSURLSession){ let sc = session.configuration guard (sc.identifier == "com.example.my-download-session") else { return } self.completionHandler!() self.session = nil }
![Page 226: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/226.jpg)
NetworkingContaining app API
func URLSessionDidFinishEventsForBackgroundURLSession(session: NSURLSession){ let sc = session.configuration guard (sc.identifier == "com.example.my-download-session") else { return } self.completionHandler!() self.session = nil }
![Page 227: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/227.jpg)
NetworkingContaining app API
func URLSessionDidFinishEventsForBackgroundURLSession(session: NSURLSession){ let sc = session.configuration guard (sc.identifier == "com.example.my-download-session") else { return } self.completionHandler!() self.session = nil }
![Page 228: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/228.jpg)
NetworkingwatchOS
Use background task assertions to protect small tasks
![Page 229: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/229.jpg)
NetworkingwatchOS
Use background task assertions to protect small tasks
WatchKit Tips and Tricks Presidio Friday 10:00AM
![Page 230: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/230.jpg)
Sharing Secretskeychain-access-groups entitlement
![Page 231: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/231.jpg)
Sharing SecretsAPI
// Add an item SecItemAdd({ kSecAttrAccessGroup: "com.example.your-app-group"}, result: NULL)
![Page 232: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/232.jpg)
Sharing SecretsAPI
// Add an item SecItemAdd({ kSecAttrAccessGroup: "com.example.your-app-group"}, result: NULL)
![Page 233: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/233.jpg)
Sharing SecretsAPI
// Add an item SecItemAdd({ kSecAttrAccessGroup: "com.example.your-app-group"}, result: NULL)
![Page 234: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/234.jpg)
Sharing SecretsAPI
Automatic search behavior for query API
Security and Your Apps Mission Tuesday 4:30PM
![Page 235: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/235.jpg)
Sharing SecretsAPI
Automatic search behavior for query API• SecItemUpdate
Security and Your Apps Mission Tuesday 4:30PM
![Page 236: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/236.jpg)
Sharing SecretsAPI
Automatic search behavior for query API• SecItemUpdate• SecItemDelete
Security and Your Apps Mission Tuesday 4:30PM
![Page 237: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/237.jpg)
Sharing SecretsAPI
Automatic search behavior for query API• SecItemUpdate• SecItemDelete• SecItemCopyMatching
Security and Your Apps Mission Tuesday 4:30PM
![Page 238: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/238.jpg)
Sharing SecretsAPI
Automatic search behavior for query API• SecItemUpdate• SecItemDelete• SecItemCopyMatching
Security and Your Apps Mission Tuesday 4:30PM
![Page 239: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/239.jpg)
Summary
Action and Share Extensions
![Page 240: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/240.jpg)
Summary
Action and Share ExtensionsEnhanced Today widget
![Page 241: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/241.jpg)
Summary
Action and Share ExtensionsEnhanced Today widgetGeneral best practices
![Page 242: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/242.jpg)
Related Sessions
WatchKit Tips and Tricks Presidio Friday 10:00AM
Security and Your Apps Mission Tuesday 4:30PM
![Page 243: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/243.jpg)
More Information
DocumentationApp Extension Programming Guide
Sample CodeListerSample Photo Editing Extensionhttp://developer.apple.com/app-extensions
Technical SupportApple Developer ForumsDeveloper Technical Supporthttp://devforums.apple.com
General InquiriesCurt Rothert, App Frameworks [email protected]
![Page 244: App Extension Best Practices](https://reader035.vdocuments.mx/reader035/viewer/2022062219/58a1ab4c1a28aba5438ba0a2/html5/thumbnails/244.jpg)