There is a way to accomplish that using the Share Extension
.
But, I would like to mention that the share extensions' intended approach is handling all of the necessary work itself. The provided solution is a workaround.
Steps
- Configure your app to handle
Deep Linking
. Here is a good article that explains how to accomplish that in SwiftUI.
- Create a new
Share Extension
(File -> New -> Target -> Share Extension). Proceed with the default settings.
- Replace the content of the newly created
Info.plist
(in the extension target) with this
<?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>NSExtensionActionWantsFullScreenPresentation</key>
<true/>
<key>NSExtensionAttributes</key>
<dict>
<key>NSExtensionActivationRule</key>
<dict>
<key>NSExtensionActivationSupportsWebURLWithMaxCount</key>
<integer>1</integer>
</dict>
</dict>
<key>NSExtensionPrincipalClass</key>
<string>ShareNavigationController</string>
<key>NSExtensionPointIdentifier</key>
<string>com.apple.share-services</string>
</dict>
</dict>
</plist>
- Replace the content of the newly created View Controller file (in the extension target) with the following code:
import UIKit
import Social
import UniformTypeIdentifiers
import SwiftUI
@objc(ShareNavigationController)
class ShareNavigationController: UINavigationController {
override func viewDidLoad() {
super.viewDidLoad()
retrieveSharedURL { [weak self] url in
guard let url = url else {
let error = NSError(domain: "your_bundle_id", code: 0, userInfo: [NSLocalizedDescriptionKey: "Failed to retrieve the url"])
self?.extensionContext?.cancelRequest(withError: error)
return
}
guard var components = URLComponents(string: "your_custom_scheme://share_extension") else {
let error = NSError(domain: "your_bundle_id", code: 0, userInfo: [NSLocalizedDescriptionKey: "Failed to create the components"])
self?.extensionContext?.cancelRequest(withError: error)
return
}
components.queryItems = [URLQueryItem(name: "share_url", value: url.absoluteString)]
guard let deepLinkURL = components.url else {
let error = NSError(domain: "your_bundle_id", code: 0, userInfo: [NSLocalizedDescriptionKey: "Failed to create the deep-link url"])
self?.extensionContext?.cancelRequest(withError: error)
return
}
_ = self?.openURL(deepLinkURL)
self?.extensionContext?.completeRequest(returningItems: [], completionHandler: nil)
}
}
func retrieveSharedURL(_ completion: @escaping (URL?) -> ()) {
let attachment = (extensionContext?.inputItems as? [NSExtensionItem])?
.reduce([], { $0 + ($1.attachments ?? []) })
.first(where: { $0.hasItemConformingToTypeIdentifier(UTType.url.identifier) })
if let attachment = attachment {
attachment.loadItem(forTypeIdentifier: UTType.url.identifier, options: nil) { (item, _) in
completion(item as? URL)
}
}
}
@objc func openURL(_ url: URL) -> Bool {
var responder: UIResponder? = self
while responder != nil {
if let application = responder as? UIApplication {
return application.perform(#selector(openURL(_:)), with: url) != nil
}
responder = responder?.next
}
return false
}
}
- Delete the MainInterface.storyboard file.
- Retrieve the share URL from the deep-link in your host app:
// ...
guard let components = URLComponents(url: deepLinkURL, resolvingAgainstBaseURL: true),
let queryItem = components.queryItems?.first(where: { $0.name == "share_url" })?.value,
let shareURL = URL(string: queryItem) else { return }
// Handle the url
print(shareURL)