Airlist
Contact, Follow, Help & Guide
Building with SwiftUI: SwiftUI Share Extension
2021-04-15

Airlist for iPhone and iPad has a very powerful share extension thanks to SwiftUI.

Share Sheet

But the share extension API is still only available in AppKit. So how do you do it in SwiftUI? Follow below…

Setting up a share extension

Start by adding the share extension to your project

File → New → Target → Share Extension … then press Activate

During this process a new ShareViewController.swift, MainInterface.storyboard and Info.plist will be created for you.

In order to build the Share Extension with SwiftUI you will need to customize the ShareViewController.

First, replace the ShareViewController code with the below.

import SwiftUI
import UIKit

class ShareViewController: UIViewController {
    @IBOutlet var container: UIView!

    override func viewDidLoad() {
        super.viewDidLoad()

    }

    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
    }
}

Setting up SwiftUI View

Next, it’s time to setup your SwiftUI View. Let’s begin with something simple.

struct SwiftUIView {
    @State public var incoming_text: String
    
    var body: some View {
        Text(incoming_text)
    }
}

Then, back in ShareViewController add the below to viewDidLoad to capture the incoming information from the share sheet.

// in ShareViewController
override func viewDidLoad() {
    super.viewDidLoad()

    // this gets the incoming information from the share sheet
    if let item = extensionContext?.inputItems.first as? NSExtensionItem {
        if let attachments = item.attachments {
            for attachment: NSItemProvider in attachments {
                if attachment.hasItemConformingToTypeIdentifier("public.text") {
                    attachment.loadItem(forTypeIdentifier: "public.text", options: nil, completionHandler: { text, _ in

                        // text variable is the text from the share sheet...
                    })
                }
            }
        }
    }
}

Next add the code which will embed your SwiftUI View into the ShareViewController.

// this will add your SwiftUI View to the UIViewController
let childView = UIHostingController(rootView: AirlistShareView(name: text as! String, note: ""))
self.addChild(childView)
childView.view.frame = self.container.bounds
self.container.addSubview(childView.view)
childView.didMove(toParent: self)

The final viewDidLoad should look like this.

// in ShareViewController
override func viewDidLoad() {
    super.viewDidLoad()

    // this gets the incoming information from the share sheet
    if let item = extensionContext?.inputItems.first as? NSExtensionItem {
        if let attachments = item.attachments {
            for attachment: NSItemProvider in attachments {
                if attachment.hasItemConformingToTypeIdentifier("public.text") {
                    attachment.loadItem(forTypeIdentifier: "public.text", options: nil, completionHandler: { text, _ in

                        // text variable is the text from the share sheet...
                        let childView = UIHostingController(rootView: SwiftUIView(incoming_text: text as! String))
                        self.addChild(childView)
                        childView.view.frame = self.container.bounds
                        self.container.addSubview(childView.view)
                        childView.didMove(toParent: self)
                    })
                }
            }
        }
    }
}

Now go to safari in your iOS simulator and load a website. Select some text → share. Click your app’s icon and you should see your SwiftUI View!

Communicating between ShareController and your SwiftUI View

Next you’ll want to be able to communicate between the ShareViewController and your SwiftUI View. To do this, we will use NSNotifications.

// at the end of viewDidLoad
NotificationCenter.default.addObserver(forName: NSNotification.Name("close"), object: nil, queue: nil) { _ in
    self.close()
}

// add this function to UIShareViewController
func close() {
    extensionContext?.completeRequest(returningItems: [], completionHandler: nil)
}
// in your SwiftUI View
func close() {
    NotificationCenter.default.post(name: NSNotification.Name("close"), object: nil)
}

Then, to close your share extension using SwiftUI, simply call close().


We hate spam too. You’ll only receive periodic important Airlist information. Unsubscribe anytime.

We’re also posting regular and in-depth updates on twitter.

Join the Public Beta
Keep your data. Easy import & export.
No commitment required.