2014-06-16 6 views
8

Ich bin mit dem loadItemForTypeIdentifier: Optionen: completionHandler: Methode auf einem NSItemProvider Objekt über einen Anteil Erweiterung eine URL von Safari zu extrahieren in iOS 8.iOS 8 Teilen Erweiterung loadItemForTypeIdentifier: Optionen: completionHandler: Abschluss Schließung Ausführung nicht

In Objective-C, dieser Code und funktioniert und der Block läuft.

[itemProvider loadItemForTypeIdentifier:(@"public.url" options:nil completionHandler:^(NSURL *url, NSError *error) { 
    //My code 
}]; 

In Swift sieht es sehr ähnlich aus, aber die Schließung läuft nicht. Auch itemProvider.hasItemConformingToTypeIdentifier("public.url") kehrt YES so muss ein gültiges Objekt sein, die URL zu analysieren aus dem Innern der itemProvider.

itemProvider.loadItemForTypeIdentifier("public.url", options: nil, completionHandler: { (urlItem, error) in 
    //My code 
}) 

Der Info.plist NSExtension Teil ist genau das gleiche sowohl für Objective-C und Swift-Version und sieht wie folgt aus:

<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> 

Was mache ich falsch?

+0

Ich hasse es, derjenige zu sein, der es sagt, aber verstößt dies nicht gegen die allgemeinen Geschäftsbedingungen des Entwicklers? NDAs für neue Releases usw. – ScottMcGready

+2

@ScottMcGerade, Sie müssen das Memo verpasst haben, aber sie haben die NDA ein wenig gelockert. Google es. –

+0

Ich habe gerade die Ansicht von, es ist Apple- es ist wahrscheinlich unter NDA. Froh, dass sie sich ein bisschen mehr öffnen. Sie müssen die Dokumente lesen, die jetzt aktualisiert wurden. – ScottMcGready

Antwort

0

Ich habe mit dieser Frage ein und aus in den letzten paar Wochen gekämpft worden und haben endlich das Problem. Ich habe nichts mit Objective C oder Swift zu tun, es scheint nur ein Fehler in Apples Code zu sein.

Es scheint, dass (wie bei iOS 8.0) der Abschlussblock nur aufgerufen wird, wenn Sie Ihre eigene UIViewController Unterklasse verwenden. Wenn Sie eine Unterklasse von SLComposeServiceViewController verwenden, wird der Completion-Block nicht aufgerufen.

Das ist wirklich ärgerlich, da standardmäßig XCode Sie mit einer Unterklasse von SLComposeServiceViewController eine ShareViewController schafft. Um dieses Problem zu umgehen, müssen Sie ShareViewController ändern, um von UIViewController zu erben. Dies wird noch geben Zugriff auf die extensionContext Eigenschaft, aber Sie werden offensichtlich alle nett Standard-Funktionalität verlieren und die Benutzeroberfläche von Grund haben zu implementieren.

Ich habe ein Radar mit Apple eingereicht, aber noch keine Antwort noch. Hoffentlich wird dies in einem zukünftigen Update behoben werden.

+0

Nicht zutreffend, siehe Antwort von pJes2 – Jesse

+0

Wie ist das "nicht wahr"? Die Antwort von pJes2 macht genau das, was ich hier sage, indem ich UIViewController und nicht SLComposeServiceViewController unterklassifiziere. das heißt 'Klasse SendingViewController: UIViewController' –

+0

Die Arbeit hier erwähnt (Subklassen Ihre eigene 'UIViewController') ist grundsätzlich die gleiche Lösung von pJes2 vorgeschlagen. Ohne sich auf den Code von jemand anderem verlassen zu müssen. – ajmccall

9

Anruf

self.extensionContext!.completeRequestReturningItems([], completionHandler: nil) 

am Ende completionHandler statt es am Ende des didSelectPost() aufrufen

+0

Perfekt. Sollte akzeptiert werden. Funktioniert auf iOS 8 (auf Simulator) –

+0

funktioniert nicht auf meinem Gerät. Weißt du, warum? –

0

Ich war nie completionHandler verwaltet ohne Benutzeroberfläche richtig für Teile Erweiterung arbeiten (in einem solchen Die Klasse der Fallerweiterung ist eine Unterklasse für NSObject.

Trotz der [itemProvider hasItemConformingToTypeIdentifier:(NSString *)kUTTypeURL] kehrt YES die completionHandler nie beide auf dem Gerät oder Simulator genannt.

Nach verschiedenen Ansätzen versucht, landete ich mit Abhilfe up basiert auf JavaScript-URL zurück zur Verlängerung vorbei (sorry ich ObjC nicht Swift für mein Beispiel zu verwenden).

Info.plist NSExtension Teil:

<key>NSExtension</key> 
<dict> 
    <key>NSExtensionAttributes</key> 
    <dict> 
     <key>NSExtensionActivationRule</key> 
     <dict> 
      <key>NSExtensionActivationSupportsWebURLWithMaxCount</key> 
      <integer>1</integer> 
     </dict> 
     <key>NSExtensionJavaScriptPreprocessingFile</key> 
     <string>Action</string> 
    </dict> 
    <key>NSExtensionPointIdentifier</key> 
    <string>com.apple.services</string> 
    <key>NSExtensionPrincipalClass</key> 
    <string>ActionRequestHandler</string> 
</dict> 

Javascript Action.js Datei:

var Action = function() {}; 
Action.prototype = { 
    run: function(arguments) { 
     arguments.completionFunction({ "currentURL" : window.location.href }) 
    }, 
    finalize: function(arguments) { 
    } 
}; 
var ExtensionPreprocessingJS = new Action 

ActionRequestHandler.h Header-Datei:


ActionRequestHandler.m basierend auf Standard-Action-Erweiterung Vorlage:

#import "ActionRequestHandler.h" 
#import <MobileCoreServices/MobileCoreServices.h> 

@interface ActionRequestHandler() 

@property (nonatomic, strong) NSExtensionContext *extensionContext; 

@end 

@implementation ActionRequestHandler 

- (void)beginRequestWithExtensionContext:(NSExtensionContext *)context { 
    // Do not call super in an Action extension with no user interface 
    self.extensionContext = context; 

    BOOL found = NO; 

    // Find the item containing the results from the JavaScript preprocessing. 
    for (NSExtensionItem *item in self.extensionContext.inputItems) { 
     for (NSItemProvider *itemProvider in item.attachments) { 
      if ([itemProvider hasItemConformingToTypeIdentifier:(NSString *)kUTTypePropertyList]) { 
       [itemProvider loadItemForTypeIdentifier:(NSString *)kUTTypePropertyList options:nil completionHandler:^(NSDictionary *dictionary, NSError *error) { 
        [[NSOperationQueue mainQueue] addOperationWithBlock:^{ 
         [self itemLoadCompletedWithPreprocessingResults:dictionary[NSExtensionJavaScriptPreprocessingResultsKey]]; 
        }]; 
       }]; 
       found = YES; 
      } 
      break; 
     } 
     if (found) { 
      break; 
     } 
    } 

    if (!found) { 
     // We did not find anything - signal that we're done 
     [self.extensionContext completeRequestReturningItems:@[] completionHandler:nil]; 
     // Don't hold on to this after we finished with it 
     self.extensionContext = nil; 
    } 
} 

- (void)itemLoadCompletedWithPreprocessingResults:(NSDictionary *)javaScriptPreprocessingResults 
{ 
    // Get the URL 
    if ([javaScriptPreprocessingResults[@"currentURL"] length] != 0) { 
     NSLog(@"*** URL: %@", javaScriptPreprocessingResults[@"currentURL"]); 
    } 

    // Signal that we're done 
    [self.extensionContext completeRequestReturningItems:@[] completionHandler:nil]; 
    // Don't hold on to this after we finished with it 
    self.extensionContext = nil; 
} 

@end 

Hoffe, dass es jemand helfen paar Stunden mit dem completionHandler Problem kämpfen, um zu sparen.

2

Da completeRequestReturningItems aufgerufen werden muss, nachdem alle completionHandler zurückgerufen wurden, ist unten, was ich tue.

let group = dispatch_group_create() 

    for item: AnyObject in self.extensionContext!.inputItems { 
     let inputItem = item as! NSExtensionItem 
     for provider: AnyObject in inputItem.attachments! { 
      let itemProvider = provider as! NSItemProvider 
      if itemProvider.hasItemConformingToTypeIdentifier("public.url") { 
       dispatch_group_enter(group) 
       itemProvider.loadItemForTypeIdentifier("public.url", options: nil, completionHandler: { 
        (result: NSSecureCoding!, error: NSError!) -> Void in 
        //... 
        dispatch_group_leave(group) 
       }); 
      } 
      if itemProvider.hasItemConformingToTypeIdentifier(kUTTypeImage as String) { 
       dispatch_group_enter(group) 
       itemProvider.loadItemForTypeIdentifier(kUTTypeImage as String, options: nil, completionHandler: { (result, error) -> Void in 
        if let resultURL = result as? NSURL { 
         if let image = UIImage(data: NSData(contentsOfURL: resultURL)!) { 
          // ... 
         } 
        } 
        dispatch_group_leave(group) 
       }); 
      } 
     } 
    } 
    dispatch_group_notify(group,dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), { 
     self.extensionContext!.completeRequestReturningItems([], completionHandler: nil) 
    }) 
+0

zu komplizierte Antwort. Es kann sehr einfach gemacht werden. –

+1

Ich wünsche es auch. Es wäre großartig, wenn Sie sich beraten lassen könnten, wenn Sie etwas im Sinn haben. – hebinda

Verwandte Themen