Andy Dent
Andy Dent

Reputation: 17971

XCode11 error "open(_:options:completionHandler:) is unavailable in application extensions"

After launching Touchgram v1.0, which is 99% iMessage app extension, I tried to update to XCode11.

I started getting an error open(_:options:completionHandler:) is unavailable in application extensions

I confirmed this occurs even in a trivial sample that tries to launch a web URL from an iMessage app:

For example:

    let openSel = #selector(UIApplication.open(_:options:completionHandler:))
    while (responder != nil){
        if responder?.responds(to: openSel ) == true {
            // cannot package up multiple args to openSel 
            // so we explicitly call it on the iMessage application instance

            // found by iterating up the chain
            (responder as? UIApplication)?.open(url, completionHandler:handler) 
            return
        }
        responder = responder!.next
    }

Update 2020

My own answer to this question, below, details how the workaround works. Note that the sample linked above has been fixed to both use this workaround and also show opening a web URL inside a WKWebView inside the iMessage extension itself.

Upvotes: 4

Views: 3094

Answers (2)

MrHim
MrHim

Reputation: 421

Because of this question' s title is generic and doesn' t refer specifically to Touchgram, i would suggest another workaround for two purposes:

  1. Try to help others that land on this question just reading the title;
  2. Look for opinions about this workaround and Apple' s policy compatibility.

It could be enough to go to your Extension' s Build settings and change the value for "Require Only App-Extension-Safe API" to "NO". This does the trick but it would be really helpful to read someone other' s comment about that.

In Addition to above, if someone have some pod dependency in the Extension Target, and error is happening in the files of the included Pod, then this error can be solved by setting Require Only App-Extension-Safe API to No for that particular Pod. Following would be the path for it:

Pods -> Targets -> Your-Problematic-Pod -> Build Settings -> Require Only App-Extension-Safe API set this to NO.

Upvotes: 4

Andy Dent
Andy Dent

Reputation: 17971

As documented in the (sole) issue on that sample, this was an intentional change in iOS 13 as confirmed by DTS. My belief is this was part of a crackdown on abusive behaviour in keyboard extensions, which picked up iMessage extensions as a side-effect.

I'd already come up with a workaround, which is the same as they recommend.

  1. Forward the URL to your parent app using self.extensionContext?.open
  2. Have the parent app then launch the external app or URL on your behalf.

Here's the complete working extension from Touchgram

// UIViewController+iMessageContext.swift
// applied to class MessagesViewController: MSMessagesAppViewController, UrlOpeningInIMessage 

protocol UrlOpeningInIMessage {
    func openFromiMessageContext(url:URL)
}


extension UrlOpeningInIMessage where Self:UIViewController {
    func openFromiMessageContext(url:URL) {
        let handler = { (success:Bool) -> () in
            if success {
                os_log("Finished opening URL", log:tgEnv.logImUI, type:.debug)
            } else {
                os_log("Failed to open URL", log:tgEnv.logImUI, type:.debug)
            }
        }
        // logic same as onLaunchMainPressed, since XCode11 unable to compile extension using UIApplication.open
        // so we pass the URL through to the parent app to launch on our behalf
        let appName = Bundle.appName()
        let encodedUrl = url.dataRepresentation.base64EncodedString()
        guard let appUrl: URL = URL(string: "\(appName)://?url=\(encodedUrl)") else { return }
        // can only open our app, not generalised URLs
        self.extensionContext?.open(appUrl, completionHandler: handler)
    }
}

Upvotes: 4

Related Questions