launch containing app from iOS8 Custom Keyboard

2020-01-28 03:20发布

问题:

I want to launch my containing app.

I tried using URL schemes.

The URL scheme launched the app from other places - so the problem is not there.

Looks like this object is nil:

   self.extensionContext

thus i can't run this method:

[self.extensionContext openURL:url completionHandler:nil];

Can I launch my app? Do URL Schemes work in a custom keyboard?

thanks!

回答1:

Try this code

    UIResponder* responder = self;
    while ((responder = [responder nextResponder]) != nil)
    {
        NSLog(@"responder = %@", responder);
        if([responder respondsToSelector:@selector(openURL:)] == YES)
        {
            [responder performSelector:@selector(openURL:) withObject:[NSURL URLWithString:urlString]];
        }
    }


回答2:

To answer MY OWN question:

In an iOS8 custom keyboard, the extensionContext object is nil, thus I can't use it to launch the containing app.

The workaround I came up with is:

  1. create a url scheme for your app
  2. add a UIWebView to your inputView
  3. load the url scheme for your containing app in the webview

I'm not sure if Apple will allow this to happen, but it works now.



回答3:

Here is working solution (tested on iOS 9.2) for Keyboard Extension. This category adds special method for access to hidden sharedApplication object and then call openURL: on it. (Of course then you have to use openURL: method with your app scheme.)

// Usage:
// UIInputViewController.openURL(NSURL(string: "your-app-scheme://")!)
extension UIInputViewController {

    func openURL(url: NSURL) -> Bool {
        do {
            let application = try self.sharedApplication()
            return application.performSelector("openURL:", withObject: url) != nil
        }
        catch {
            return false
        }
    }

    func sharedApplication() throws -> UIApplication {
        var responder: UIResponder? = self
        while responder != nil {
            if let application = responder as? UIApplication {
                return application
            }

            responder = responder?.nextResponder()
        }

        throw NSError(domain: "UIInputViewController+sharedApplication.swift", code: 1, userInfo: nil)
    }

}

Lately I developed slightly different approach:

// Usage:
// UIApplication.