import UIKit import UniformTypeIdentifiers class ShareViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() handleSharedItems() } private func handleSharedItems() { guard let items = extensionContext?.inputItems as? [NSExtensionItem] else { closeExtension() return } let fileManager = FileManager.default guard let containerURL = fileManager.containerURL(forSecurityApplicationGroupIdentifier: "group.com.fishestlife.note") else { closeExtension() return } let sharedDir = containerURL.appendingPathComponent("SharedFiles", isDirectory: true) try? fileManager.createDirectory(at: sharedDir, withIntermediateDirectories: true) var sharedTexts: [String] = [] var sharedFileNames: [String] = [] let group = DispatchGroup() for item in items { guard let attachments = item.attachments else { continue } for attachment in attachments { group.enter() if attachment.hasItemConformingToTypeIdentifier(UTType.plainText.identifier) { attachment.loadItem(forTypeIdentifier: UTType.plainText.identifier, options: nil) { data, _ in defer { group.leave() } if let text = data as? String { sharedTexts.append(text) } else if let url = data as? URL, let text = try? String(contentsOf: url, encoding: .utf8) { sharedTexts.append(text) } } } else if attachment.hasItemConformingToTypeIdentifier(UTType.url.identifier) { attachment.loadItem(forTypeIdentifier: UTType.url.identifier, options: nil) { data, _ in defer { group.leave() } if let url = data as? URL, let text = try? String(contentsOf: url, encoding: .utf8) { sharedTexts.append(text) } } } else { attachment.loadItem(forTypeIdentifier: UTType.data.identifier, options: nil) { data, _ in defer { group.leave() } if let url = data as? URL { let destURL = sharedDir.appendingPathComponent(url.lastPathComponent) try? fileManager.removeItem(at: destURL) if (try? fileManager.copyItem(at: url, to: destURL)) != nil { sharedFileNames.append(url.lastPathComponent) } } else if let fileData = data as? Data { let fileName = "shared-\(UUID().uuidString).md" let destURL = sharedDir.appendingPathComponent(fileName) if (try? fileData.write(to: destURL)) != nil { sharedFileNames.append(fileName) } } } } } } group.notify(queue: .main) { [weak self] in self?.openMainApp(texts: sharedTexts, fileNames: sharedFileNames) } } private func openMainApp(texts: [String], fileNames: [String]) { var components = URLComponents(string: "noteapp://share")! var queryItems: [URLQueryItem] = [] for (index, text) in texts.prefix(5).enumerated() { queryItems.append(URLQueryItem(name: "text\(index)", value: text)) } for (index, fileName) in fileNames.prefix(5).enumerated() { queryItems.append(URLQueryItem(name: "file\(index)", value: fileName)) } components.queryItems = queryItems.isEmpty ? nil : queryItems guard let url = components.url else { closeExtension() return } extensionContext?.open(url) { [weak self] _ in self?.closeExtension() } } private func closeExtension() { extensionContext?.completeRequest(returningItems: nil, completionHandler: nil) } }