4

I have the following code in my share extension to get the URL that is shared.

    if let item = extensionContext?.inputItems.first as? NSExtensionItem {
        for (index, _) in (item.attachments?.enumerated())! {
            if let itemProvider = item.attachments?[index] as? NSItemProvider {
                if itemProvider.hasItemConformingToTypeIdentifier("public.url") {
                    itemProvider.loadItem(forTypeIdentifier: "public.url", options: nil, completionHandler: { (url, error) -> Void in
                        if let shareURL = url as? NSURL {
                            // send url to server to share the link
                            print (shareURL.absoluteString!)

For some reason the iOS YouTube app returns false for itemProvider.hasItemConformingToTypeIdentifier("public.url").

And below is my Info.plist for the share extension.

<key>NSExtension</key>
<dict>
    <key>NSExtensionAttributes</key>
    <dict>
        <key>NSExtensionActivationRule</key>
        <string>
            SUBQUERY (
                extensionItems,
                $extensionItem,
                SUBQUERY (
                    $extensionItem.attachments,
                    $attachment,
                    ANY $attachment.registeredTypeIdentifiers UTI-CONFORMS-TO "public.url"
                ).@count == 1
            ).@count == 1
        </string>
    </dict>
    <key>NSExtensionMainStoryboard</key>
    <string>MainInterface</string>
    <key>NSExtensionPointIdentifier</key>
    <string>com.apple.share-services</string>
</dict>

How can I get the URL for the YouTube video shared in my share extension?

Charlie Fish
  • 18,491
  • 19
  • 86
  • 179
  • If the `ItemProvider` can't offer you a URL, what types can it offer? If you ask the item provider for it's `registeredTypeIdentifiers` what UTI are given? – Scott Thompson May 13 '17 at 16:08
  • `p itemProvider.registeredTypeIdentifiers[0] as! String (String) $R4 = "public.plain-text"` – Charlie Fish May 13 '17 at 16:17
  • @ScottThompson Printing `itemProvider.registeredTypeIdentifiers[0] as! String` returns `"public.plain-text"` – Charlie Fish May 13 '17 at 16:18
  • Ok. That's the first one. Are there others? If you actually ask for the plain text what does it contain? – Scott Thompson May 13 '17 at 16:20
  • @ScottThompson `item.attachments?.count` returns `1`. Working on seeing what it contains now. – Charlie Fish May 13 '17 at 16:26
  • @ScottThompson Oh it returns `https://www.youtube.com/watch?v=VIDEOIDHERE&feature=share`. Is there a best way to adjust my code to get that plain-text IF it's in a URL form? I don't want to get some random text. I only want to get it if it's a URL. – Charlie Fish May 13 '17 at 16:28
  • Get the text and see if you can convert it to a `URL` using `init?(string: String)` if the text is not a URL, that function will return nil – Scott Thompson May 13 '17 at 16:30
  • @ScottThompson so like `if let myURL = URL.init?(string: text) {`? – Charlie Fish May 13 '17 at 16:31
  • @ScottThompson Or that gives an error so would `if URL.init(string: text as! String) != nil {` work? – Charlie Fish May 13 '17 at 16:34

2 Answers2

4

My first recommendation is to find out what types are actually provided by the itemProvider:

if let item = extensionContext?.inputItems.first as? NSExtensionItem {
    for (index, _) in (item.attachments?.enumerated())! {
        if let itemProvider = item.attachments?[index] as? NSItemProvider {

            // print out the registered type identifiers so we can see what's there
            itemProvider.registeredTypeIdentifiers.forEach { print String(describing: $0) }

In this case, according to your comments, you are able to get plain text or kUTTypePlainText and that text contains a URL so:

if let item = extensionContext?.inputItems.first as? NSExtensionItem {
for (index, _) in (item.attachments?.enumerated())! {
    if let itemProvider = item.attachments?[index] as? NSItemProvider {
        if itemProvider.hasItemConformingToTypeIdentifier(kUTTypePlainText) {
            itemProvider.loadItem(forTypeIdentifier: kUTTypePlainText, options: nil, completionHandler: { (string, error) -> Void in
                if let string = (string as? String), let shareURL = URL(string) {
                    // send url to server to share the link
                    print (shareURL.absoluteString!)

My second recommendation is to always use the kUTType constants instead of raw strings :-)

Scott Thompson
  • 22,629
  • 4
  • 32
  • 34
1

Youtube will provide a kUTTypePlainText. To obtain an URL you have to convert from NSSecureCoding to String and then build the URL with that string.

func getUrl() {
  if let content = extensionContext!.inputItems[0] as? NSExtensionItem {

    let contentTypePlain = kUTTypePlainText as String

    if let contents = content.attachments {
      for attachment in contents {
        if attachment.hasItemConformingToTypeIdentifier(contentTypePlain) {
          attachment.loadItem(forTypeIdentifier: contentTypePlain, options: nil, completionHandler: { data, error in
            let urlString = data as! String
            let url = URL(string: urlString)!

            // USE URL 

          })
        }
      }
    }
  }
}