我想启动我的包含应用程序。
我尝试使用 URL 方案。
URL 方案从其他地方启动了应用程序 - 所以问题不存在。
看起来这个对象是零:
self.extensionContext
因此我无法运行此方法:
[self.extensionContext openURL:url completionHandler:nil];
我可以启动我的应用程序吗?URL Schemes 可以在自定义键盘中使用吗?
谢谢!
我想启动我的包含应用程序。
我尝试使用 URL 方案。
URL 方案从其他地方启动了应用程序 - 所以问题不存在。
看起来这个对象是零:
self.extensionContext
因此我无法运行此方法:
[self.extensionContext openURL:url completionHandler:nil];
我可以启动我的应用程序吗?URL Schemes 可以在自定义键盘中使用吗?
谢谢!
试试这个代码
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]];
}
}
要回答我自己的问题:
在 iOS8 自定义键盘中,extensionContext 对象为 nil,因此我无法使用它来启动包含的应用程序。
我想出的解决方法是:
我不确定 Apple 是否会允许这种情况发生,但现在可以了。
这是键盘扩展的工作解决方案(在 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
}
}
Apple 不允许除 Today 扩展之外的任何应用扩展来打开包含的应用。
从指南:
Today 小部件(并且没有其他应用程序扩展类型)可以通过调用 NSExtensionContext 类的 openURL:completionHandler: 方法来请求系统打开其包含的应用程序。
你可以在这里查看
根据 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 ;}];
我尝试为最新的 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")
这是我发现使用上述内容打开任何 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 已经取消了这种方法
在应用程序扩展(例如:自定义键盘)中,这本来可以通过 iOS 8.1.2 处理,UIViewController.extensionContext
但从 iOS 8.1.2 开始,该字段nil
位于以下 Swift 调用中:
self.extensionContext?.openURL(appURL, completionHandler: nil)
// Does nothing because extensionContext is nil (iOS 8.1)
实际上,也不可能像Apple 文档Application.sharedApplication.openURL(...)
中所述的那样在 App Extension 中使用。
因此,从 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()
}
WhereMyKeyboard://
必须相应地定义为包含应用程序中的 URL 方案。
请注意,我还不知道这是否得到 Apple 的批准。从自定义键盘转发到应用程序可能对用户体验来说已经够糟糕了。
一个 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()
}
}
我为此挣扎了几天。我无法让 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];
}