11

Works for Safari, Doesn't work for Chrome

Maybe the question is simple and stupid but I am new to iOS Development and I cannot find any right solution to solve this issue.

I need to get:
1) page url
2) page name

Extension

Info.plist

<dict>
    <key>NSExtensionAttributes</key>
    <dict>
        <key>NSExtensionActivationRule</key>
        <dict>
            <key>NSExrensionActivationSupportsText</key>
            <true/>
            <key>NSExtensionActivationSupportsFileWithMaxCount</key>
            <integer>1</integer>
            <key>NSExtensionActivationSupportsImageWithMaxCount</key>
            <integer>1</integer>
            <key>NSExtensionActivationSupportsMovieWithMaxCount</key>
            <integer>20</integer>
            <key>NSExtensionActivationSupportsWebPageWithMaxCount</key>
            <integer>1</integer>
            <key>NSExtensionActivationSupportsWebURLWithMaxCount</key>
            <integer>0</integer>
        </dict>
        <key>NSExtensionJavaScriptPreprocessingFile</key>
        <string>DemoPreprocessor</string>
    </dict>
    <key>NSExtensionMainStoryboard</key>
    <string>MainInterface</string>
    <key>NSExtensionPointIdentifier</key>
    <string>com.apple.share-services</string>
</dict>

I've added more to Chrome but it still does not work. For Safari, this is enough:

NSExtensionActivationSupportsWebPageWithMaxCount, NSExtensionActivationSupportsWebURLWithMaxCount, NSExrensionActivationSupportsText, NSExtensionJavaScriptPreprocessingFile

I try three approaches, with and without DemoPreprocessor.js. But all don't work for Chrome:

1. ShareViewController.swift

override func viewDidLoad() {
    super.viewDidLoad()

    let items = extensionContext?.inputItems
    var itemProvider: NSItemProvider?

    if items != nil && items!.isEmpty == false {
        let item = items![0] as! NSExtensionItem
        if let attachments = item.attachments {
            if !attachments.isEmpty {
                itemProvider = (attachments[0] as? NSItemProvider)!
            }
        }
    }

    let urlType = kUTTypePropertyList as String
    if ((itemProvider?.hasItemConformingToTypeIdentifier(urlType)) != nil) {
        itemProvider?.loadItemForTypeIdentifier(urlType, options: nil, completionHandler: {
            (item: NSSecureCoding?, error: NSError!) -> Void in
            if let resultDict = item as? NSDictionary {
                self.linkName = resultDict[NSExtensionJavaScriptPreprocessingResultsKey]!["URL"] as! String
                self.linkUrl = resultDict[NSExtensionJavaScriptPreprocessingResultsKey]!["title"] as! String
            }

        })
    }

}

2 ShareViewController.swift

override func viewDidLoad() {
    super.viewDidLoad()

    let items = extensionContext?.inputItems
    var itemProvider: NSItemProvider?

    if items != nil && items!.isEmpty == false {
        let item = items![0] as! NSExtensionItem
        if let attachments = item.attachments {
            if !attachments.isEmpty {
                itemProvider = (attachments[0] as? NSItemProvider)!
            }
        }
    }

    let urlType = kUTTypeURL as NSString as String

    if ((itemProvider?.hasItemConformingToTypeIdentifier(urlType)) != nil) {
       itemProvider?.loadItemForTypeIdentifier(urlType, options: nil, completionHandler: {
           item, error in
           self.linkName = self.contentText
           self.linkUrl = "\(item!)"
       })
    }

}

3 ShareViewController.swift

override func viewDidLoad() {
    super.viewDidLoad()

    let items = extensionContext?.inputItems
    var itemProvider: NSItemProvider?

    if items != nil && items!.isEmpty == false {
        let item = items![0] as! NSExtensionItem
        if let attachments = item.attachments {
            if !attachments.isEmpty {
                itemProvider = (attachments[0] as? NSItemProvider)!
            }
        }
    }

    if self.linkUrl.characters.count < 1 {
        if ((itemProvider?.hasItemConformingToTypeIdentifier("public.url")) != nil) {
            itemProvider?.loadItemForTypeIdentifier("public.url", options: nil, completionHandler: {
                item, error in self.linkUrl = "\(item!)"
            })
        }
    }

}

DemoPreprocessor.js

var MyPreprocessor = function() {};

MyPreprocessor.prototype = {
    run: function(arguments) {
        arguments.completionFunction({"URL": document.URL, "pageSource": document.documentElement.outerHTML, "title": document.title, "selection": window.getSelection().toString()});
    }
};

var ExtensionPreprocessingJS = new MyPreprocessor;
Mr. Xcoder
  • 4,719
  • 5
  • 26
  • 44
Denis
  • 2,622
  • 3
  • 22
  • 24
  • @EricD i need to delete swift tag? – Denis Jul 28 '16 at 17:59
  • @EricD i think plist - manifest, ShareViewController.swift, DemoPreprocessor.js are relevant becose i read some documentations, questions, answeres and people wrote there that some combinations work (with PreprocessingJS, and some without, with different NSExtensionActivationRule's). But all that i try work only in Safari and don't work in Chrome – Denis Jul 28 '16 at 18:09

2 Answers2

5

In my app I've made it work, however it was some time ago and I don't remember which exact steps are necessary, so I'll post my setup in hopes it will serve as a drop in solution.

The first issue I see in your plist is a 0 count for WebURLs.

This is a part of my extension's .plist. I think that allowing arbitrary loads has nothing to do with sharing and it was needed for accessing my server, nevertheless I'll put it here for reference.

<key>NSAppTransportSecurity</key>
<dict>
    <key>NSAllowsArbitraryLoads</key>
    <true/>
</dict>
<key>NSExtension</key>
<dict>
    <key>NSExtensionAttributes</key>
    <dict>
        <key>NSExtensionActivationRule</key>
        <dict>
            <key>NSExtensionActivationSupportsImageWithMaxCount</key>
            <integer>1</integer>
            <key>NSExtensionActivationSupportsWebURLWithMaxCount</key>
            <integer>1</integer>
        </dict>
    </dict>
    <key>NSExtensionPointIdentifier</key>
    <string>com.apple.share-services</string>
    <key>NSExtensionPrincipalClass</key>
    <string>ShareViewController</string>
</dict>

My controller's part of code responsible for getting a URL:

// MARK: - NSExtensionRequestHandling
extension ShareViewController {
    override func beginRequestWithExtensionContext(context: NSExtensionContext) {
        super.beginRequestWithExtensionContext(context)

        guard let provider = (context.inputItems.first?.attachments as? [NSItemProvider])?.first else { return cancel() }

        if provider.hasItemConformingToTypeIdentifier(kUTTypeURL as String) {
            provider.loadItemForTypeIdentifier(kUTTypeURL as String, options: nil) { url, error in
                guard let url = url as? NSURL else { return self.cancel() }
                // do what you want with the url
            }
        } else {
            cancel()
        }
    }
}

As for getting the site's name, well there are a few ways I think. One is to use the JS script that you already have in your project, another is to see whether the provider has an item with a text type (containing the site's name) but they are browser specific (some work only for Safari, some for browsers like Chrome). I chose to go about it in a different way, I use a fake WKWebView (which is never added to view hierarchy, it's just a property) and make a request with the url that I got from the provider. Then I'm able to intercept the site's name from it's JS code like so:

func setupHiddenWebView() {
    hiddenWebView = WKWebView()
    hiddenWebView?.navigationDelegate = self
}

func setupForURL(url: NSURL) {
    (...)
    hiddenWebView?.loadRequest(NSURLRequest(URL: url))
}

// MARK: - WKNavigationDelegate
extension ShareView: WKNavigationDelegate {
    func webView(webView: WKWebView, didFinishNavigation navigation: WKNavigation!) {
        webView.evaluateJavaScript("document.title") { result, error in
            guard let title = result as? String else { return }
            // do what you want with the page's title
        }
    }
}
  • Can you clarify the code? hiddenWebview is not declared, (...) is unclear, and it's also not clear why you are using extensions, and what exactly you are extending, and for what reasons. Thanks! – lucius degeer May 27 '20 at 23:14
0

Add NSExtensionActivationSupportsText and NSExtensionActivationSupportsWebPageWithMaxCount under NSExtensionActivationRule with the type as Number and set them to 1.

That was what did it for me.

omygaudio
  • 631
  • 5
  • 6