J'essaie de créer une extension de partage à l'aide des nouvelles extensions d'applications iOS 8. J'ai essayé d'obtenir l'URL actuelle d'un site Safari pour l'afficher dans un UILabel. Assez simple.
Je travaillais ici dans le guide d'extension officiel d'Apple/ https://developer.Apple.com/library/content/documentation/General/Conceptual/ExtensibilityPG/Share.html#//Apple_ref/doc/uid/TP40014214-CH12 -SW1 mais certaines choses ne fonctionnent pas comme prévu. Je sais que c'est seulement en version bêta mais peut-être que je fais quelque chose de mal.
Voici mon code pour obtenir l'URL de safari à l'intérieur des extensions 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:%lu@",[array count]]];
}
[mutableString appendString:temp];
}
self.myLabel.text = mutableString;
}
Et voici le contenu de mon fichier Info.plist de mon extension:
<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>
Lorsque je visite la page de support Apple iPod dans Safari et que je tente de le partager sur mon extension, les valeurs suivantes sont affichées, mais pas d'URL:
item.attributedTitle = (null)
item.attributedContentText = "iPod - Apple Support"
item.userInfo.count = 2 (two keys: NSExtensionAttributedContentTextKey and
NSExtensionItemAttachmentsKey)
item.attachments.count = 0
Les tableaux à l'intérieur des objets du dictionnaire sont toujours vides.
Lorsque je partage le site Apple avec l'application de messagerie système, l'URL est publiée dans le message. Alors pourquoi n'y a-t-il pas d'URL dans mon extension?
Voici comment vous pouvez obtenir l'URL. Notez que l'identificateur de type est kUTTypeURL et que l'argument de bloc est NSURL. En outre, le plist doit être correct comme le mien aussi. La documentation faisait défaut et a obtenu l'aide de number4 sur les forums Apple . (vous devez être enregistré et connecté pour le voir).
Code:
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>
Je l'ai résolu pour moi-même. J'essayais avec Sharing Image.
- (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];
}
Donc, ce que j'ai fait est de déplacer les [self.extensionContext completeRequestReturningItems: nil completionHandler: nil]; à l'intérieur du bloc à la fin d'autres tâches. La version de travail finale ressemble à ceci (Xcode 6 beta 5 sur Mavericks OS X 10.9.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];
}
J'espère que cela fonctionnera également pour le partage d'URL.
Votre contrôleur de vue d’extension doit adopter le protocole NSExtensionRequestHandling
. Une des méthodes de ce protocole est:
- (void)beginRequestWithExtensionContext:(NSExtensionContext *)context
Vous devriez attendre que cette personne soit appelée avant d’essayer d’obtenir NSExtensionContext
. Il fournit même le contexte dans la méthode en tant que paramètre context
.
Ceci a été décrit dans ce document .
Les autres réponses sont toutes compliquées et incomplètes. Ils ne fonctionnent que dans Safari et non dans Google Chrome. Cela fonctionne à la fois dans Google Chrome et 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
}
}
})
}
}
}
}
Toutes ces réponses précédentes sont vraiment bonnes, mais je viens juste de comprendre ce problème dans Swift et je pense qu'il était un peu fastidieux d'extraire l'URL d'un NSExtensionContext
donné, en particulier dans le processus de conversion de CFString
à String
et du fait que completionHandler
dans loadItemForTypeIdentifier
n'est pas exécuté dans le fil principal.
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)
}
}
}
De cette façon, vous pouvez maintenant simplement l'utiliser comme ceci dans votre sous-classe UIViewController
:
self.extensionContext?.extractURL({ (url) -> Void in
self.urlLabel.text = url?.absoluteString
println(url?.absoluteString)
})
let itemProvider = item.attachments?.first as! NSItemProvider
itemProvider.loadItemForTypeIdentifier("public.url", options: nil) { (object, error) -> Void in
println(object)
}
so println: http://detail.m.tmall.com/item.htm?id=38131345289&spm=a2147.7632989.mainList.5
Vous devez rechercher une pièce jointe de type kUTTypePropertyList. Faites quelque chose comme ceci avec la première pièce jointe du premier élément d'extension de votre extension:
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
}];
Vous aurez également besoin de configurer JavaScript pour collecter toutes les données nécessaires dans le DOM. Voir la deuxième session d'extensions de WWDC 14 pour plus de détails.