2014-06-05 107 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 
         } 
        } 
       }) 
      } 
     } 
    } 
}