Skip to content

Instantly share code, notes, and snippets.

@yccheok
Created September 8, 2024 09:40
Show Gist options
  • Save yccheok/cf7358a2f8a813da290ab36240f81c52 to your computer and use it in GitHub Desktop.
Save yccheok/cf7358a2f8a813da290ab36240f81c52 to your computer and use it in GitHub Desktop.
class ShareViewController: UIViewController {
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
// Get the all encompasing object that holds whatever was shared. If not, dismiss view.
guard let extensionItem = extensionContext?.inputItems.first as? NSExtensionItem else {
self.extensionContext?.completeRequest(returningItems: nil, completionHandler: nil)
return
}
accessWebpageProperties(extensionItem: extensionItem)
}
private func accessWebpageProperties(extensionItem: NSExtensionItem) {
guard let attachments = extensionItem.attachments else {
return
}
Task {
for attachment in attachments {
if let url = await handleIncomingURL(itemProvider: attachment) {
shareAndBye(url: url)
return
}
if let url = await handleIncomingText(itemProvider: attachment) {
shareAndBye(url: url)
return
}
}
bye()
}
}
private func handleIncomingURL(itemProvider: NSItemProvider) async -> String? {
do {
if let url = try await itemProvider.loadItem(forTypeIdentifier: UTType.url.identifier, options: nil) as? NSURL {
if let urlString = url.absoluteString?.trimmingCharacters(in: .whitespacesAndNewlines), ShareViewController.isValidWebsiteURL(urlString) {
return urlString
}
}
} catch {
// Handle errors appropriately here
print("Error handling incoming URL: \(error)")
}
return nil
}
private func handleIncomingText(itemProvider: NSItemProvider) async -> String? {
do {
let text = try await itemProvider.loadItem(forTypeIdentifier: UTType.text.identifier, options: nil) as? String
if let text = text?.trimmingCharacters(in: .whitespacesAndNewlines) {
do {
let detector = try NSDataDetector(types: NSTextCheckingResult.CheckingType.link.rawValue)
let matches = detector.matches(
in: text,
options: [],
range: NSRange(location: 0, length: text.utf16.count)
)
for match in matches {
if let range = Range(match.range, in: text) {
let url = String(text[range]).trimmingCharacters(in: .whitespacesAndNewlines)
if ShareViewController.isValidWebsiteURL(url) {
return url
}
}
}
} catch let error {
print("Do-Try Error: \(error.localizedDescription)")
}
}
} catch {
// Handle errors appropriately here
print("Error handling incoming text: \(error)")
}
return nil
}
// TODO: Need to fix this.
private static func isValidWebsiteURL(_ urlString: String) -> Bool {
if urlString.isEmpty {
return false
}
if let url = URL(string: urlString), url.host != nil, (url.scheme == "http" || url.scheme == "https") {
return true
}
return false
}
@MainActor
private func shareAndBye(url: String) {
self.extensionContext?.completeRequest(returningItems: nil, completionHandler: { _ in
if let encodedURL = url.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) {
let appURL = "melonote://share?url=" + encodedURL
guard let url = URL(string: appURL) else { return }
_ = self.openURL(url)
}
})
}
@MainActor
private func bye() {
self.extensionContext?.completeRequest(returningItems: nil, completionHandler: nil)
}
// Courtesy: https://stackoverflow.com/a/44499222/13363449 👇🏾
// Function must be named exactly like this so a selector can be found by the compiler!
// Anyway - it's another selector in another instance that would be "performed" instead.
@objc private 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
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment