从iOS8自定义键盘启动包含应用程序

时间:2014-06-30 17:07:40

标签: ios ios8 ios-app-extension

我想发布我的内容应用。

我尝试使用网址方案。

URL方案从其他地方启动了应用程序 - 所以问题不存在。

看起来这个对象是nil:

   self.extensionContext

因此我无法运行此方法:

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

我可以启动我的应用吗? URL方案是否可以在自定义键盘中使用?

谢谢!

11 个答案:

答案 0 :(得分:13)

试试此代码

    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]];
        }
    }

答案 1 :(得分:9)

回答我自己的问题:

在iOS8自定义键盘中,extensionContext对象为nil,因此我无法使用它来启动包含应用程序。

我想出的解决方法是:

  1. 为您的应用创建网址方案
  2. 将UIWebView添加到inputView
  3. 在webview中加载包含应用的网址方案
  4. 我不确定苹果是否允许这种情况发生,但它现在有效。

答案 2 :(得分:8)

这是工作解决方案(在iOS 9.2上测试)用于键盘扩展。此类别添加了访问隐藏sharedApplication对象的特殊方法,然后在其上调用openURL:。 (当然,您必须在您的应用方案中使用openURL:方法。)

// 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)
    }

}

最近我开发了略有不同的方法:

// Usage:
// UIApplication.sharedApplication().openURL(NSURL(string: "your-app-scheme://")!)

extension UIApplication {

    public static func sharedApplication() -> UIApplication {
        guard UIApplication.respondsToSelector("sharedApplication") else {
            fatalError("UIApplication.sharedKeyboardApplication(): `UIApplication` does not respond to selector `sharedApplication`.")
        }

        guard let unmanagedSharedApplication = UIApplication.performSelector("sharedApplication") else {
            fatalError("UIApplication.sharedKeyboardApplication(): `UIApplication.sharedApplication()` returned `nil`.")
        }

        guard let sharedApplication = unmanagedSharedApplication.takeUnretainedValue() as? UIApplication else {
            fatalError("UIApplication.sharedKeyboardApplication(): `UIApplication.sharedApplication()` returned not `UIApplication` instance.")
        }

        return sharedApplication
    }

    public func openURL(url: NSURL) -> Bool {
        return self.performSelector("openURL:", withObject: url) != nil
    }

}

答案 3 :(得分:4)

Apple不允许除今日扩展程序之外的任何应用程序扩展程序打开包含应用程序。

根据指南:

  

今天的小部件(没有其他应用程序扩展类型)可以通过调用NSExtensionContext类的openURL:completionHandler:方法来要求系统打开其包含的应用程序。

您可以查看Here

答案 4 :(得分:2)

我尝试为最新的xcode 8.2和swift 3.0做上述解决方案。

不幸的是。我无法让它发挥作用。所以我找到了自己的解决方案,它在swift 3.0,xcode 8.2

中运行良好
   func openURL(_ url: URL) {
        return
   }

   func openApp(_ urlstring:String) {

       var responder: UIResponder? = self as UIResponder
       let selector = #selector(openURL(_:))
       while responder != nil {
           if responder!.responds(to: selector) && responder != self {
              responder!.perform(selector, with: URL(string: urlstring)!)
              return
             }
             responder = responder?.next
          }
   }

  // Usage
  //call the method like below
  //self.openApp(urlString)

  //URL string need to included custom scheme.
  //for example, if you created scheme name = customApp
  //urlString will be "customApp://?[name]=[value]"
  //self.openApp("customApp://?category=1")

答案 5 :(得分:1)

根据Apple的文档https://developer.apple.com/library/ios/documentation/General/Conceptual/ExtensibilityPG/index.html,你应该像这样使用NSExtensionContext:

NSExtensionContext *ctx = [[NSExtensionContext alloc] init];
[ctx openURL:[NSURL URLWithString:@"myapp://"] completionHandler:^(BOOL success){return ;}];

答案 6 :(得分:1)

我发现这是使用上面描述的内容打开任何URL:

UIWebView * webView = [[UIWebView alloc] initWithFrame:CGRectMake(0, 0, 0, 0)];
NSString *urlString = @"https://itunes.apple.com/us/app/watuu/id304697459";
NSString * content = [NSString stringWithFormat : @"<head><meta http-equiv='refresh' content='0; URL=%@'></head>", urlString];
[webView loadHTMLString:content baseURL:nil];
[self.view addSubview:webView];
[webView performSelector:@selector(removeFromSuperview) withObject:nil afterDelay:2.0];

请注意,在这种情况下,我将从UIInputViewController实例化此调用。

此方法也可以使用包含应用程序的URL方案

注意:从iOS 8.3开始,Apple已经杀死了这种方法

答案 7 :(得分:1)

在App Extension(例如:自定义键盘)中,可以通过UIViewController.extensionContext处理,但从iOS 8.1.2起,该字段在以下Swift调用中为nil

self.extensionContext?.openURL(appURL, completionHandler: nil)
// Does nothing because extensionContext is nil (iOS 8.1)

实际上,如Apple documentation中所述,无法在App扩展程序中使用Application.sharedApplication.openURL(...)

因此,从8.1.2开始,解决方法是使用哑UIWebView重定向到包含的应用程序,如下所示:

let webView = UIWebView(frame: CGRectMake(0, 0, 0, 0));
let url = "MyKeyboard://";
let content = "<head><meta http-equiv='refresh' content='0; URL=\(url)'></head>";
webView.loadHTMLString(content, baseURL: nil);
self.view.addSubview(webView);
let delayInSeconds = 2.0
let startTime = dispatch_time(DISPATCH_TIME_NOW, Int64(delayInSeconds * Double(NSEC_PER_SEC)))
dispatch_after(startTime, dispatch_get_main_queue()) { () -> Void in
    webView.removeFromSuperview()
}

必须在包含应用程序中将MyKeyboard://相应地定义为URL方案。

请注意,我还不知道这是否得到Apple的批准。从自定义键盘转发到应用程序可能对用户体验而言非常糟糕。

答案 8 :(得分:1)

Swift 2.2版本,类似于DongHyun Jang对Objective-C的回答:

func webLink(urlString: String) {
    let url = NSURL(string: urlString)
    var responder: UIResponder? = self
    while let r = responder {
        if r.respondsToSelector("openURL:") {
            r.performSelector("openURL:", withObject: url)
            break;
        }
        responder = r.nextResponder()
    }  
}

答案 9 :(得分:1)

根据Apple针对Extension的审核指南,现在建议从扩展程序中打开外部应用程序。

供参考,请参阅apple review guidelines

第4.4.1节

  

他们不能:

     
      
  • 包括营销,广告或应用内购买;
  •   
  • 启动“设置”之外的其他应用;或
  •   

答案 10 :(得分:0)

我挣扎了几天。我无法让UIWebView在自定义键盘内工作。

修复:将它放在viewDidAppear:animated而不是viewDidLoad中(在另一个注释中,这也是键盘自定义高度的代码也应保留的位置)。

代码:

- (void)viewDidAppear:(BOOL)animated {
    UIWebView * webView = [[UIWebView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
    NSString * content = @"<a href='your_app_schema://your_params'>anchor</a>";
    [webView loadHTMLString:content baseURL:nil];
    [self.view addSubview:webView];
}