Issue #932

Add Share extension and Action extension respectively in Xcode. We can use the same code to both extension

SwiftUI

I usually make a ShareView in SwiftUI with ShareViewModel to control the logic

struct ShareView: View {
    @ObservedObject var vm: ShareViewModel
    
    var body: some View {
        NavigationStack(path: $vm.routes) {
            List {}
        }
    }
}

In ShareViewController, we can just conform to UIViewController and add our SwiftUI view as child view controller

let vm = ShareViewModel()
let hostingController = UIHostingController(rootView: ShareView(vm: vm)
addChild(hostingController)
view.addSubview(hostingController.view)
hostingController.didMove(toParent: self)
hostingController.view.constrainEdges(to: view)

We can use this same ShareViewController for both Share and Action extension, so add it to both targets.

Info.plist

In Share extension Info.plist, we can replace the default NSExtensionActivationRule of TRUEPREDICATE with the below. I also use code instead of storyboard, so I use NSExtensionPrincipalClass instead of MainInterface

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
    <dict>
        <key>NSExtension</key>
        <dict>
            <key>NSExtensionAttributes</key>
            <dict>
                <key>NSExtensionActivationRule</key>
                <dict>
                    <key>NSExtensionActivationDictionaryVersion</key>
                    <integer>2</integer>
                    <key>NSExtensionActivationSupportsText</key>
                    <true/>
                    <key>NSExtensionActivationSupportsWebPageWithMaxCount</key>
                    <integer>1</integer>
                    <key>NSExtensionActivationSupportsWebURLWithMaxCount</key>
                    <integer>1</integer>
                </dict>
            </dict>
            <key>NSExtensionPrincipalClass</key>
            <string>$(PRODUCT_MODULE_NAME).ShareViewController</string>
            <key>NSExtensionPointIdentifier</key>
            <string>com.apple.share-services</string>
        </dict>
    </dict>
</plist>

In Action extension Info.plist, it looks like below

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
    <dict>
        <key>NSExtension</key>
        <dict>
            <key>NSExtensionAttributes</key>
            <dict>
                <key>NSExtensionActivationRule</key>
                <dict>
                    <key>NSExtensionActivationDictionaryVersion</key>
                    <integer>2</integer>
                    <key>NSExtensionActivationSupportsText</key>
                    <true/>
                    <key>NSExtensionActivationSupportsWebPageWithMaxCount</key>
                    <integer>1</integer>
                    <key>NSExtensionActivationSupportsWebURLWithMaxCount</key>
                    <integer>1</integer>
                </dict>
                <key>NSExtensionServiceAllowsFinderPreviewItem</key>
                <true/>
                <key>NSExtensionServiceAllowsTouchBarItem</key>
                <true/>
                <key>NSExtensionServiceFinderPreviewIconName</key>
                <string>NSActionTemplate</string>
                <key>NSExtensionServiceTouchBarBezelColorName</key>
                <string>TouchBarBezel</string>
                <key>NSExtensionServiceTouchBarIconName</key>
                <string>NSActionTemplate</string>
            </dict>
            <key>NSExtensionPrincipalClass</key>
            <string>$(PRODUCT_MODULE_NAME).ShareViewController</string>
            <key>NSExtensionPointIdentifier</key>
            <string>com.apple.ui-services</string>
        </dict>
    </dict>
</plist>

Icon

For Action extension, we need an icon to show in system Share dialog. We can add new App Icon to Media asset catalog

Note that we need to specify this AppIcon in Primary App Icon Set Name