我添加以下代码:
- (IBAction)done { // Return any edited content to the host app. // This template doesn't do anything, so we just echo the passed in items. NSURL *url = [NSURL URLWithString:@"lister://today"]; [self.extensionContext openURL:url completionHandler:^(BOOL success) { NSLog(@"fun=%s after completion. success=%d", __func__, success); }]; [self.extensionContext completeRequestReturningItems:self.extensionContext.inputItems completionHandler:nil]; }
在我创建Action Extension目标之后.但它无法奏效.
我的目的是:当用户在Photos.app(iOS的默认Photos.app或被调用的图库)中查看照片时,他点击分享按钮以启动我们的扩展视图.我们可以将Photos.app中的图像传输到我自己的应用程序,并在我的应用程序中处理或上传图像.
我也尝试"CFBundleDocumentTypes"但它也无法工作.
任何帮助将不胜感激.
这就是我以前做的事情:
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方案
更新2015年4月17日:这不适用于iOS 8.3.我们正在寻找解决方案,我们会尽快更新答案
更新06/01/2015:我们找到了适用于iOS 8.3的解决方案
var responder = self as UIResponder? while (responder != nil){ if responder!.respondsToSelector(Selector("openURL:")) == true{ responder!.callSelector(Selector("openURL:"), object: url, delay: 0) } responder = responder!.nextResponder() }
这将找到一个合适的响应者来发送openURL.
您需要添加此扩展来替换swift的performSelector并帮助构建机制:
extension NSObject { func callSelector(selector: Selector, object: AnyObject?, delay: NSTimeInterval) { let delay = delay * Double(NSEC_PER_SEC) let time = dispatch_time(DISPATCH_TIME_NOW, Int64(delay)) dispatch_after(time, dispatch_get_main_queue(), { NSThread.detachNewThreadSelector(selector, toTarget:self, withObject: object) }) } }
更新2015年6月15日:Objective-C
有人要求Objective-C中的代码,所以在这里.我不打算运行它,因为我现在没有时间,但它应该非常简单:
UIResponder *responder = self; while(responder){ if ([responder respondsToSelector: @selector(OpenURL:)]){ [responder performSelector: @selector(OpenURL:) withObject: [NSURL URLWithString:@"www.google.com" ]]; } responder = [responder nextResponder]; }
如上所述,我没有运行这个Objective-C代码,它只是从Swift代码转换而来.如果您遇到任何问题和解决方案,请告诉我,我会更新.如今,我只是使用swift,不幸的是我的大脑正在弃用Objective-C
更新05/02/2016:不推荐使用的功能
正如@KyleKIM指出的那样,Selector函数已经被#selector替换为Swift 2.2.此外,还有一个已弃用的功能,可能会在Swift 3.0中删除,所以我正在做一些研究以找到替代方案.
更新2016年9月16日:XCode 8,Swift 3.0和iOS10 以下代码仍在处理上述版本.你会得到一些警告:
let url = NSURL(string:urlString) let context = NSExtensionContext() context.open(url! as URL, completionHandler: nil) var responder = self as UIResponder? while (responder != nil){ if responder?.responds(to: Selector("openURL:")) == true{ responder?.perform(Selector("openURL:"), with: url) } responder = responder!.next }
更新日期:6/15/2017:XCode 8.3.3
let url = NSURL(string: urlString) let selectorOpenURL = sel_registerName("openURL:") let context = NSExtensionContext() context.open(url! as URL, completionHandler: nil) var responder = self as UIResponder? while (responder != nil){ if responder?.responds(to: selectorOpenURL) == true{ responder?.perform(selectorOpenURL, with: url) } responder = responder!.next }
Apple接受了以下解决方案,即主机应用程序将使用的"相同"代码.它适用于迄今为止所有iOS 8版本(在iOS 8.0 - iOS 8.3上测试).
NSURL *destinationURL = [NSURL URLWithString:@"myapp://"]; // Get "UIApplication" class name through ASCII Character codes. NSString *className = [[NSString alloc] initWithData:[NSData dataWithBytes:(unsigned char []){0x55, 0x49, 0x41, 0x70, 0x70, 0x6C, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6F, 0x6E} length:13] encoding:NSASCIIStringEncoding]; if (NSClassFromString(className)) { id object = [NSClassFromString(className) performSelector:@selector(sharedApplication)]; [object performSelector:@selector(openURL:) withObject:destinationURL]; }
键盘扩展的工作解决方案(在iOS 9.2上测试).此类别添加了访问隐藏sharedApplication
对象的特殊方法,然后调用openURL:
它.(当然,你必须使用openURL:
你的应用程序方案的方法.)
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) } }
试试这个代码.
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]]; } }
NSExtensionContext仅支持今天扩展中的openURL函数,这在Apple的文档中有关NSExtensionContext的描述.原始单词是"每个扩展点确定是否支持此方法,或者在哪种条件下支持此方法.在iOS 8.0中,只有今日扩展名point支持这种方法."
这似乎是一个错误,因为文档说:
打开包含应用程序
在某些情况下,扩展请求打开包含的应用程序是有意义的.例如,当用户单击某个事件时,OS X中的"日历"小组件将打开"日历".要确保您的包含应用程序以在用户当前任务的上下文中有意义的方式打开,您需要定义应用程序及其扩展可以使用的自定义URL方案.
扩展程序不直接告诉其包含的应用程序打开; 相反,它使用NSExtensionContext的openURL:completionHandler:方法告诉系统打开其包含的应用程序.当扩展使用此方法打开URL时,系统会在完成请求之前验证该请求.
我今天报告了这个问题:http://openradar.appspot.com/17376354如果你有空闲时间,你应该欺骗它.
Swift 3.0和4.0中的工作解决方案:
// For skip compile error. func openURL(_ url: URL) { return } func openContainerApp() { 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: "containerapp://")!) return } responder = responder?.next } }
说明:
在扩展中,api受编译器限制,不允许您像容器应用程序一样使用openURl(:URL).然而,api仍然在这里.
在我们声明它之前我们不能在我们的类中执行方法,我们真正想要的是让UIApplication执行这个方法.
回想一下响应者链,我们可以使用
var responder: UIResponder? = self as UIResponder responder = responder?.next
循环到UIApplication对象.
我使用此方法的应用程序通过了审核流程,因此请不要担心使用它.
可能的解决方法:创建并添加一个小的UIWebView到您的视图,并运行它与你上面设置的URL方案的loadRequest方法.这是一种解决方法,我不确定Apple会对此发表什么.祝好运!
这是设计的.我们不希望自定义操作成为应用程序启动器.