Home > other >  How to get the page URL shared via the Share button on macOS?
How to get the page URL shared via the Share button on macOS?

Time:03-13

I have a macOS Share Extension invoked when users tap the Share button in Safari. I'm trying to get the page's URL from the -[NSExtensionItem attachments] attribute, but it comes as an NSSecureCoding object, and I'm unable to read the URL from it.

In the loadView method, I'm filtering and loading the attachments of type public.url:

override func loadView() {
    super.loadView()

    guard let inputItem = extensionContext?.inputItems.first as? NSExtensionItem else {
        print("Didn't received input item from action.")
        return
    }

    var itemProvider: NSItemProvider?
    itemProvider = inputItem.attachments?.filter({ $0.registeredTypeIdentifiers.contains("public.url") }).first ?? inputItem.attachments?.filter({ $0.registeredTypeIdentifiers.contains("public.plain-text") }).first

    guard let itemProvider = itemProvider else {
        print("Didn't received attachments from input item.")
        return
    }

    if itemProvider.canLoadObject(ofClass: URL.self) {
        itemProvider.loadItem(forTypeIdentifier: "public.url", completionHandler: onl oadVideoURL)
    } else if itemProvider.canLoadObject(ofClass: String.self) {
        itemProvider.loadItem(forTypeIdentifier: "public.plain-text", completionHandler: onl oadVideoURL)
    } else {
        print("This action only supports URL and String.")
    }
}

The itemProvider.loadItem method runs for the type identifier public.url, calling the completion handler bellow:

@objc private func onl oadVideoURL(dict: NSSecureCoding?, error: Error?) {
    print("URL: \(dict.debugDescription)")
    // ...
}

But the content that it prints to the console is:

URL: Optional(<68747470 733a2f2f 73746163 6b6f7665 72666c6f 772e636f 6d2f7175 65737469 6f6e732f 35323231 39373030 2f686f77 2d746f2d 63617374 2d6e7373 65637572 65636f64 696e672d 746f2d6d 6b6d6170 6974656d 2d696e2d 61637469 6f6e2d65 7874656e 73696f6e>)

The same code works as expected on iOS, printing the shared URL to the console.

Do I have to somehow convert this NSSecureCoding to URL or another object? Or should I do this in a completely different way on macOS? The goal is to access the page's URL from the Share Extension activated when the user selects it in the Share Menu.

CodePudding user response:

Turns out that the NSSecureCoding content was the URL, but in hexadecimal. Here's how I'm converting it to String:

let urlHex = dict.debugDescription
    .replacingOccurrences(of: "Optional(", with: "")
    .replacingOccurrences(of: ")", with: "")
    .replacingOccurrences(of: "<", with: "")
    .replacingOccurrences(of: ">", with: "")
    .replacingOccurrences(of: " ", with: "")

guard let urlHexData = Data(fromHexEncodedString: urlHex) else { return }
guard let url = String(data: urlHexData, encoding: .utf8) else { return }
extension Data {

    // From http://stackoverflow.com/a/40278391
    init?(fromHexEncodedString string: String) {
        func decodeNibble(u: UInt16) -> UInt8? {
            switch(u) {
            case 0x30 ... 0x39:
                return UInt8(u - 0x30)
            case 0x41 ... 0x46:
                return UInt8(u - 0x41   10)
            case 0x61 ... 0x66:
                return UInt8(u - 0x61   10)
            default:
                return nil
            }
        }

        self.init(capacity: string.utf16.count/2)
        var even = true
        var byte: UInt8 = 0
        for c in string.utf16 {
            guard let val = decodeNibble(u: c) else { return nil }
            if even {
                byte = val << 4
            } else {
                byte  = val
                self.append(byte)
            }
            even = !even
        }
        guard even else { return nil }
    }
}
  • Related