mirror of
https://github.com/yattee/yattee.git
synced 2026-02-19 17:29:45 +00:00
120 lines
4.1 KiB
Swift
120 lines
4.1 KiB
Swift
//
|
|
// ShareViewController.swift
|
|
// YatteeShareExtension
|
|
//
|
|
// Handles shared URLs and opens them in Yattee.
|
|
//
|
|
|
|
import UIKit
|
|
import UniformTypeIdentifiers
|
|
|
|
class ShareViewController: UIViewController {
|
|
|
|
override func viewDidLoad() {
|
|
super.viewDidLoad()
|
|
view.backgroundColor = .clear
|
|
}
|
|
|
|
override func viewDidAppear(_ animated: Bool) {
|
|
super.viewDidAppear(animated)
|
|
handleSharedItems()
|
|
}
|
|
|
|
private func handleSharedItems() {
|
|
guard let extensionItems = extensionContext?.inputItems as? [NSExtensionItem] else {
|
|
close()
|
|
return
|
|
}
|
|
|
|
for extensionItem in extensionItems {
|
|
guard let attachments = extensionItem.attachments else { continue }
|
|
|
|
for attachment in attachments {
|
|
// Try to get URL first
|
|
if attachment.hasItemConformingToTypeIdentifier(UTType.url.identifier) {
|
|
attachment.loadItem(forTypeIdentifier: UTType.url.identifier, options: nil) { [weak self] item, _ in
|
|
DispatchQueue.main.async {
|
|
if let url = item as? URL {
|
|
self?.openInYattee(url: url)
|
|
} else {
|
|
self?.close()
|
|
}
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
// Try plain text (might contain a URL)
|
|
if attachment.hasItemConformingToTypeIdentifier(UTType.plainText.identifier) {
|
|
attachment.loadItem(forTypeIdentifier: UTType.plainText.identifier, options: nil) { [weak self] item, _ in
|
|
DispatchQueue.main.async {
|
|
if let text = item as? String, let url = self?.extractURL(from: text) {
|
|
self?.openInYattee(url: url)
|
|
} else {
|
|
self?.close()
|
|
}
|
|
}
|
|
}
|
|
return
|
|
}
|
|
}
|
|
}
|
|
|
|
close()
|
|
}
|
|
|
|
private func extractURL(from text: String) -> URL? {
|
|
let trimmed = text.trimmingCharacters(in: .whitespacesAndNewlines)
|
|
if let url = URL(string: trimmed),
|
|
url.scheme == "http" || url.scheme == "https" {
|
|
return url
|
|
}
|
|
|
|
let detector = try? NSDataDetector(types: NSTextCheckingResult.CheckingType.link.rawValue)
|
|
let range = NSRange(text.startIndex..., in: text)
|
|
if let match = detector?.firstMatch(in: text, options: [], range: range),
|
|
let url = match.url {
|
|
return url
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
private func openInYattee(url: URL) {
|
|
guard let encodedURL = url.absoluteString.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed),
|
|
let yatteeURL = URL(string: "yattee://open?url=\(encodedURL)") else {
|
|
close()
|
|
return
|
|
}
|
|
|
|
openURLViaApplication(yatteeURL)
|
|
|
|
DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) { [weak self] in
|
|
self?.close()
|
|
}
|
|
}
|
|
|
|
private func openURLViaApplication(_ url: URL) {
|
|
let sharedSelector = NSSelectorFromString("sharedApplication")
|
|
|
|
guard let appClass = NSClassFromString("UIApplication") as? NSObject.Type,
|
|
appClass.responds(to: sharedSelector),
|
|
let shared = appClass.perform(sharedSelector)?.takeUnretainedValue() else {
|
|
return
|
|
}
|
|
|
|
typealias OpenURLMethod = @convention(c) (AnyObject, Selector, URL, [UIApplication.OpenExternalURLOptionsKey: Any], ((Bool) -> Void)?) -> Void
|
|
|
|
let openSelector = NSSelectorFromString("openURL:options:completionHandler:")
|
|
guard shared.responds(to: openSelector) else { return }
|
|
|
|
let methodIMP = shared.method(for: openSelector)
|
|
let method = unsafeBitCast(methodIMP, to: OpenURLMethod.self)
|
|
method(shared, openSelector, url, [:], nil)
|
|
}
|
|
|
|
private func close() {
|
|
extensionContext?.completeRequest(returningItems: nil, completionHandler: nil)
|
|
}
|
|
}
|