Note: Updated for Swift 4. For a hack day at work I decided to try my hand at creating a share extension. I discovered that there wasn’t a fully-featured out there, and as a result I had to piece together information (much of it attributed, surprisingly, to the ). tutorial Apple documentation The Goal To save a web page URL as rich content into our app, and allow for configuration of a few options. Initially I thought an was what was needed — but it seems that is better suited for modifying content (such as removing red-eye on a photo with one tap). It seems others, Apple included, are using the share extension to create items instead. extension action This is what we’ll have built by the end: The completed extension As you can see I’ve customized the design a little, and added what’s referred to as a “configuration item” which are cells at the bottom of the sheet; commonly used to select from accounts or other options. It’s used here to select from the user’s existing “Decks” to save to. What you can’t see is it’s also running some JavaScript code to fetch the current URL of the browser, which we send to the server later. We’ll cover all of this ahead! Initial Steps Either create a new project, or open an existing one you’d like to add the extension to. Then hit Under the tab select and press Give it a name; I opted for the simple “ShareExtension”. File > New > Target. iOS Share Extension Next. It will ask if you’d like to activate the scheme. This means when you run the application it will allow you to open straight into Safari or similar to test the extension, as opposed to your main app. We want this — tap . Activate Test what you have so far by running the project as mentioned it gives you options of which app to test from, select and tap Cmd + R — Safari Run. The dialog presented when running an extension. When Safari opens, tap the share icon and your extension name with the placeholder icon should appear in the list. If not, tap and enable it. Tapping on the icon will present the default implementation, which is pretty neat right out of the box. More SLComposeServiceViewController’s Getting the URL The share sheet automatically retrieves the page title and sets it as the body text, but generally you’ll want more than that — whether it be the URL or an image on the page. For this you can have Safari run a JavaSript file to parse the document and retrieve whatever we need. First up, right click on your extensions folder in Xcode and select You’ll find inside of the tab, hit and name the file “GetURL.js”. New File. Empty Other Next You’ll need to edit your extensions file and in “NSExtension” there’s another dictionary called “NSExtensionAttributes” — add a key “NSExtensionJavaScriptPreprocessingFile” with the value of our file just created, “GetURL” (note the lack of extension). Info.plist Also add a dictionary row “NSExtensionActivationRule” which should contain the key “NSExtensionActivationSupportsWebURLWithMaxCount” with the number 1: How your extension’s Info.plist should look when viewed as a property list NSExtensionJavaScriptPreprocessingFile: this lets our app know of a JavaScript file that should be run on execution of the extension. NSExtensionActivationRule: use this dictionary to add which help the system determine what types of content to activate your extension for. Action Extension Keys Paste the following into “GetURL.js”: Coupled with the keys we set above, iOS now will look for an object named “ExtensionPreprocessingJS” to perform at runtime. This is explained in more detail in . Apple’s documentation In order to retrieve the data scraped with the javascript file above, you’ll need to run this block of code within the “ShareViewController.swift” function: viewDidLoad You’ll also need this import for kUTTypePropertyList: MobileCoreServices import Running the extension now should successfully print the URL to the console! Side note: add the following snippet if you’d like to customize the navigation bar as I have (replacing with your own image or just a title). Adding Configuration Cells The boilerplate that came with creating your share extension will have included a method to optionally supply configuration items (the cells in the bottom of the share sheet) override func configurationItems() -> [AnyObject]! { Insert the below snippet, which returns an array of “SLComposeSheetConfigurationItem”: Run your app again and you’ll see a cell at the bottom now. A Model for the Configuration Item Create a basic model called “Deck.swift”, which is used ahead to pass data between view controllers. The TableView In the gif at the beginning, you’ll have noticed when tapping on the configuration cell it pushes to a new view with a tableview. Create a new file that inherits from “UIViewController” named “ShareSelectViewController.swift”. Create a tableview property and add it to the view. I’ve also set the title and title color for this view, and prefer to keep constants like cell identifiers in a struct :) Create a property to store the Deck’s passed in from the original view controller: var userDecks = [Deck]() And conform to the required protocols for the tableview: Back in the“ShareViewController.swift”, create a property to store some dummy data and populate it within viewDidLoad: Lastly, inside the tapHandler for the configuration item we created, create an instance of the and have it push on tap, passing the decks in as well: ShareSelectViewController Run the app. Tapping the configuration cell should push to the tableview with the dummy data. However you’ll notice the configuration cell is still hardcoded to “Deck Title”. To have this update, create a property to store the deck selected and select the first by default: And update the configuration cell inside to use it: configurationItems() deck.value = selectedDeck?.title Run the app again and you’ll see it has updated. A Protocol to Update Selected Deck You’ll need a way to dismiss back to the when a new Deck is tapped, and have it update the UI. A protocol will suffice. Add the following to your ShareViewController ShareSelectViewController: Lastly, conform the to the protocol just made and ensure the delegate for the ShareSelectViewController is set to self: ShareViewController The selected Deck is updated, and the configuration items are reloaded to update the value. Then we pop to go back to the main screen. Run the app and now you should be able to change decks which will update to show the correctly selected deck :) Finishing Up All that’s left is to send the collected information to your server or app to do something with, which you can do inside another boilerplate method: override func didSelectPost() I won’t go into detail about this, but I used an to post to our server. I also replaced the dummy data with real decks by creating an and using a shared to store and retrieve data earlier retrieved within the main iOS app. NSURLSession app group NSUserDefaults let userDefaults = NSUserDefaults(suiteName: "some.group.name") let decks = userDefaults?.objectForKey(“userDecks”) as? NSArray Lastly, you’ll notice my extension is named “Vurb” in the action dialog, and has an icon. You can set an icon by . And to change the name simply change “Display Name” in the project settings for the extension_._ following this SO post That’s everything, if you found this helpful please help other’s find it by recommending. You can view the project in entirety . here