import UIKit import SwiftUI import UniformTypeIdentifiers @objc(ShareViewController) class ShareViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() let blur = UIVisualEffectView(effect: UIBlurEffect(style: .systemMaterial)) blur.frame = view.bounds blur.autoresizingMask = [.flexibleWidth, .flexibleHeight] view.addSubview(blur) extractURL() } private func extractURL() { guard let item = extensionContext?.inputItems.first as? NSExtensionItem, let attachments = item.attachments else { present(url: nil) return } func load(typeId: String) -> Bool { guard let attachment = attachments.first(where: { $0.hasItemConformingToTypeIdentifier(typeId) }) else { return false } attachment.loadItem(forTypeIdentifier: typeId, options: nil) { [weak self] item, _ in let urlString = typeId == UTType.url.identifier ? ((item as? URL)?.absoluteString ?? (item as? String)) : (item as? String) DispatchQueue.main.async { self?.present(url: urlString) } } return true } if !load(typeId: UTType.url.identifier) && !load(typeId: UTType.plainText.identifier) { present(url: nil) } } /// Hosts the SwiftUI save card. A nil URL surfaces an error state in the card. private func present(url: String?) { let root = ShareView(url: url ?? "") { [weak self] _ in self?.close() } let host = UIHostingController(rootView: root) host.view.backgroundColor = .clear addChild(host) host.view.frame = view.bounds host.view.autoresizingMask = [.flexibleWidth, .flexibleHeight] view.addSubview(host.view) host.didMove(toParent: self) if url == nil { // No URL to work with — let the card render its failure state briefly. DispatchQueue.main.asyncAfter(deadline: .now() + 1.6) { [weak self] in self?.close() } } } private func close() { extensionContext?.completeRequest(returningItems: [], completionHandler: nil) } }