2014-06-05 35 views
13

我正尝试使用新的iOS 8应用程序扩展创建共享扩展。我尝试获取Safari网站的当前网址,以便在UILabel中显示它。够简单。在IOS8 beta中共享扩展

我正在从苹果这里工作槽通过官方扩展指南https://developer.apple.com/library/content/documentation/General/Conceptual/ExtensibilityPG/Share.html#//apple_ref/doc/uid/TP40014214-CH12-SW1但有些东西没有按预期工作。我知道它只是在测试版中,但也许我只是在做一些错误的事情。

这里是我的代码,以获得扩展内从Safari浏览器的URL的ViewController:

-(void)viewDidAppear:(BOOL)animated{ 
NSExtensionContext *myExtensionContext = [self extensionContext]; 
NSArray *inputItems = [myExtensionContext inputItems]; 
NSMutableString* mutableString = [[NSMutableString alloc]init]; 
for(NSExtensionItem* item in inputItems){ 
    NSMutableString* temp = [NSMutableString stringWithFormat:@"%@, %@, %lu, 
      %lu - ",item.attributedTitle,[item.attributedContentText string], 
      (unsigned long)[item.userInfo count],[item.attachments count]]; 

    for(NSString* key in [item.userInfo allKeys]){ 
     NSArray* array = [item.userInfo objectForKey:@"NSExtensionItemAttachmentsKey"]; 
     [temp appendString:[NSString stringWithFormat:@" in array:%[email protected]",[array count]]]; 
    } 
    [mutableString appendString:temp]; 
} 
self.myLabel.text = mutableString; 
} 

这是我的我的分机的Info.plist文件的内容:

<dict> 
    <key>NSExtensionMainStoryboard</key> 
    <string>MainInterface</string> 
    <key>NSExtensionPointIdentifier</key> 
    <string>com.apple.share-services</string> 
    <key>NSExtensionActivationRule</key> 
    <dict> 
     <key>NSExtensionActivationSupportsWebURLWithMaxCount</key> 
     <integer>200</integer> 
    </dict> 
</dict> 

当我访问Safari中的苹果iPod支持页面,并尝试将其分享到我的扩展程序,我得到以下值但没有网址:

item.attributedTitle = (null) 
item.attributedContentText = "iPod - Apple Support" 
item.userInfo.count = 2 (two keys: NSExtensionAttributedContentTextKey and 
    NSExtensionItemAttachmentsKey) 
item.attachments.count = 0 

字典对象内的数组始终为空。

当我使用系统邮件应用程序共享苹果站点时,该URL会发布到邮件中。那么为什么我的扩展中没有URL?

回答

13

以下是如何获取网址。注意类型标识符是kUTTypeURL,块参数是NSURL。另外,plist也需要像我的一样正确。该文档缺乏,从number4 on the Apple dev forums获得帮助。 (你需要注册并登录才能看到它)。

代码:

NSExtensionItem *item = self.extensionContext.inputItems.firstObject; 
NSItemProvider *itemProvider = item.attachments.firstObject; 
if ([itemProvider hasItemConformingToTypeIdentifier:(NSString *)kUTTypeURL]) { 
    [itemProvider loadItemForTypeIdentifier:(NSString *)kUTTypeURL options:nil completionHandler:^(NSURL *url, NSError *error) { 
     self.urlString = url.absoluteString; 
    }]; 
} 

的Info.plist

<key>NSExtension</key> 
<dict> 
    <key>NSExtensionAttributes</key> 
    <dict> 
     <key>NSExtensionActivationRule</key> 
     <dict> 
      <key>NSExtensionActivationSupportsWebURLWithMaxCount</key> 
      <integer>1</integer> 
     </dict> 
     <key>NSExtensionPointName</key> 
     <string>com.apple.share-services</string> 
     <key>NSExtensionPointVersion</key> 
     <string>1.0</string> 
    </dict> 
    <key>NSExtensionPointIdentifier</key> 
    <string>com.apple.share-services</string> 
    <key>NSExtensionMainStoryboard</key> 
    <string>MainInterface</string> 
</dict> 
+0

我从来没有管理完成处理程序正常工作的共享扩展没有用户界面。结束使用基于JavaScript的解决方法 - 请参阅我的[答](http://stackoverflow.com/a/27389343/2797141)。 – xZenon

3

您的扩展视图控制器应采用NSExtensionRequestHandling协议。其中一个此协议的方法是:

- (void)beginRequestWithExtensionContext:(NSExtensionContext *)context 

你应该等待这个你尝试获得NSExtensionContext之前调用。它甚至提供方法中的上下文作为context参数。

这在this document中概述。

+0

仍然无法正常工作。即使提供了NSExtensionContext对象,也没有URL。 – user3422677

+0

这不应该是必须的,因为调用'beginRequestWithExtensionContext''发生在'loadView'前面https://developer.apple.com/library/prerelease/ios/documentation/Foundation/Reference/NSExtensionRequestHandling_Protocol/index.html#// apple_ref/occ/intfm/NSExtensionRequestHandling/beginRequestWithExtensionContext: – Oren

1

您需要寻找kUTTypePropertyList类型的附件。做这样的事情与第一延伸项目的扩展中的第一个附件:

NSExtensionItem *extensionItem = self.extensionContext.extensionItems.firstObject; 
NSItemProvider *itemProvider = self.extensionItem.attachments.firstObject; 
[itemProvider loadItemForTypeIdentifier:kUTTypePropertyList options:nil 
    completionHandler:^(NSDictionary *item, NSError *error) { 
    // Unpack items from "item" in here 
}]; 

您还需要设置一些JavaScript拿起你从DOM所需要的数据。有关更多详细信息,请参阅WWDC 14的第二个扩展会话。

+0

您不需要Javascript,请参阅我的回答http://stackoverflow.com/a/24225678/1672161 – guptron

+0

似乎Javascript方法是无用户共享扩展的唯一工作方式接口。看我的[回复](http://stackoverflow.com/a/27389343/2797141)。 – xZenon

9

我已经解决了它自己。我正在尝试使用“共享图像”。

- (void)didSelectPost { 


// This is called after the user selects Post. Do the upload of contentText and/or NSExtensionContext attachments. 

// Inform the host that we're done, so it un-blocks its UI. Note: Alternatively you could call super's -didSelectPost, which will similarly complete the extension context. 

// Verify that we have a valid NSExtensionItem 
NSExtensionItem *imageItem = [self.extensionContext.inputItems firstObject]; 
if(!imageItem){ 
    return; 
} 

// Verify that we have a valid NSItemProvider 
NSItemProvider *imageItemProvider = [[imageItem attachments] firstObject]; 
if(!imageItemProvider){ 
    return; 
} 

// Look for an image inside the NSItemProvider 
if([imageItemProvider hasItemConformingToTypeIdentifier:(NSString *)kUTTypeImage]){ 
    [imageItemProvider loadItemForTypeIdentifier:(NSString *)kUTTypeImage options:nil completionHandler:^(UIImage *image, NSError *error) { 
     if(image){ 
      NSLog(@"image %@", image); 
      // do your stuff here... 

     } 
    }]; 
    } 
// this line should not be here. Cos it's called before the block finishes. 
// and this is why the console log or any other task won't work inside the block 
[self.extensionContext completeRequestReturningItems:nil completionHandler:nil]; 

} 

因此,我所做的只是移动[self.extensionContext completeRequestReturningItems:无completionHandler:无]。在其他任务结束时的块内部。最终的工作版本是这样的(Mavericks OS X 10.9上的Xcode 6 beta 5)。4):

- (void)didSelectPost { 


// This is called after the user selects Post. Do the upload of contentText and/or NSExtensionContext attachments. 

// Inform the host that we're done, so it un-blocks its UI. Note: Alternatively you could call super's -didSelectPost, which will similarly complete the extension context. 

// Verify that we have a valid NSExtensionItem 
NSExtensionItem *imageItem = [self.extensionContext.inputItems firstObject]; 
if(!imageItem){ 
    return; 
} 

// Verify that we have a valid NSItemProvider 
NSItemProvider *imageItemProvider = [[imageItem attachments] firstObject]; 
if(!imageItemProvider){ 
    return; 
} 

// Look for an image inside the NSItemProvider 
if([imageItemProvider hasItemConformingToTypeIdentifier:(NSString *)kUTTypeImage]){ 
    [imageItemProvider loadItemForTypeIdentifier:(NSString *)kUTTypeImage options:nil completionHandler:^(UIImage *image, NSError *error) { 
     if(image){ 
      NSLog(@"image %@", image); 
      // do your stuff here... 

      // complete and return 
      [self.extensionContext completeRequestReturningItems:nil completionHandler:nil];  
     } 
    }]; 
    } 
// this line should not be here. Cos it's called before the block finishes. 
// and this is why the console log or any other task won't work inside the block 
// [self.extensionContext completeRequestReturningItems:nil completionHandler:nil]; 

} 

我希望它也可以用于URL共享。

+1

是的,它的工作原理,谢谢!我也努力与默认的ShareViewController,并注意到didSelectPost中的任何loadItemForTypeIdentifier被简单地忽略。 但调用[self.extensionContext completeRequestReturningItems:@ [] completionHandler:nil];在loadItemForTypeIdentifier中的所有块做了诀窍 – IPv6

+0

酷。很高兴听到。 :) – Adnan

+1

此外,请确保在完成处理物品提供商之前不要致电[super didSelectPost]。它的实现调用completeRequestReturningItems .... –

3

所有这些以前的答案是确实不错,但我只是来翻过这一问题,斯威夫特,并认为这是一个有点tidious提取从给定NSExtensionContext的URL尤其是在CFStringString转换过程和事实completionHandlerloadItemForTypeIdentifier中没有在主线程中执行。

import MobileCoreServices 

extension NSExtensionContext { 
    private var kTypeURL:String { 
     get { 
      return kUTTypeURL as NSString as String 
     } 
    } 

    func extractURL(completion: ((url:NSURL?) -> Void)?) -> Void { 
     var processed:Bool = false 

     for item in self.inputItems ?? [] { 
      if let item = item as? NSExtensionItem, 
       let attachments = item.attachments, 
       let provider = attachments.first as? NSItemProvider 
       where provider.hasItemConformingToTypeIdentifier(kTypeURL) == true { 
        provider.loadItemForTypeIdentifier(kTypeURL, options: nil, completionHandler: { (output, error) -> Void in 
         dispatch_async(dispatch_get_main_queue(), {() -> Void in 
          processed = true 
          if let url = output as? NSURL { 
           completion?(url: url) 
          } 
          else { 
           completion?(url: nil) 
          } 
         }) 

        }) 
      } 
     } 

     // make sure the completion block is called even if no url could be extracted 
     if (processed == false) { 
      completion?(url: nil) 
     } 
    } 
} 

这样,你现在可以简单地在你的UIViewController子类中使用这样的:

self.extensionContext?.extractURL({ (url) -> Void in 
    self.urlLabel.text = url?.absoluteString 
    println(url?.absoluteString) 
}) 
+0

您的解决方案对我来说看起来非常优雅,我刚刚摆脱了我在最后一天自己制定的代码并采纳了您的解决方案。谢谢!我有几个问题,如果没关系:1.你会在isContentValid()或viewDidAppear中调用extractURL吗? isContentValid()对我来说看起来是正确的,但每当用户在扩展的文本字段中键入或删除一个字符时,都会调用此方法。2.您是否尝试过从Pocket应用程序共享代码?您的扩展程序和我以前的代码都无法从Pocket列表中的项目中提取url,而Message或Mail扩展可以。任何想法为什么? – cdf1982

+0

另一个注意事项:仅为我检索kUTTypeURL仅适用于某些应用程序,对于其他人我必须在“public.url”中添加另一个provider.hasItemConformingToTypeIdentifier()。尽管如此,不适用于Pocket应用程序或Ebay应用程序(我尝试过的30个左右) – cdf1982

+1

我已经把'viewDidAppear'放在里面了,但是你把这个放在'isContentValid()'中会触发代码每次进行更新。我不确定这里有一个最佳选择,但现在我会坚持使用'viewDidAppear'。至于其他应用程序,我还没有尝试过很多。如果他们不使用'kUTTypeURL',我想你已经转储了整个上下文来查看它们返回的内容。 – apouche

3

其他的答案都是复杂和不完整的。他们只能在Safari中工作,并且不能在Google Chrome中工作。这适用于谷歌浏览器和Safari:

override func viewDidLoad() { 
    super.viewDidLoad() 

    for item in extensionContext!.inputItems { 
     if let attachments = item.attachments { 
      for itemProvider in attachments! { 
       itemProvider.loadItemForTypeIdentifier("public.url", options: nil, completionHandler: { (object, error) -> Void in 
        if object != nil { 
         if let url = object as? NSURL { 
         print(url.absoluteString) //This is your URL 
         } 
        } 
       }) 
      } 
     } 
    } 
}