Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Sharing Extension in IOS8 beta

I'm trying to create a sharing extension using the new iOS 8 app extensions. I tried to get the current URL of a Safari site to show it in a UILabel. Simple enough.

I was working trough the official extension guide from apple here https://developer.apple.com/library/content/documentation/General/Conceptual/ExtensibilityPG/Share.html#//apple_ref/doc/uid/TP40014214-CH12-SW1 but some things are not working as expected. I know it is only in beta but maybe I'm just doing something wrong.

Here is my code to get the URL from safari inside the 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;
}

And this is the content of my Info.plist file of my 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>

When I visit apples iPod support page in Safari and try to share it to my extension, I get following values but no URL:

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

The arrays inside the objects of the dictionary are always empty.

When I share the apple site with the system mail app the URL is posted to the message. So why is there no URL in my extension?

like image 448
Masalis Avatar asked Jun 05 '14 09:06

Masalis


5 Answers

The other answers are all complicated and incomplete. They only work in Safari and do not work in Google Chrome. This works both in Google Chrome and 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
                        }
                    }
                })
            }
        }
    }
}
like image 63
Esqarrouth Avatar answered Sep 24 '22 09:09

Esqarrouth


You need to be looking for an attachment of type kUTTypePropertyList. Do something like this with the first attachment of the first extension item in your 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
}];

You'll also need to setup some JavaScript to pick up all of the data you need from the DOM. See the second extensions session from WWDC 14 for more details.

like image 26
Ian Baird Avatar answered Sep 22 '22 09:09

Ian Baird


Below is how you can get the url. Notice the type identifier is kUTTypeURL and the block argument is NSURL. Also, the plist needs to be correct like mine also. The documentation was lacking and got help from number4 on the Apple dev forums. (you'll need to be registered and logged in to see it).

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>
like image 13
abc123 Avatar answered Oct 26 '22 05:10

abc123


I've solved it for myself. I was trying with 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];

}

So what I did is just moved the [self.extensionContext completeRequestReturningItems:nil completionHandler:nil]; inside the block at the end of other tasks. The final working version look like this (Xcode 6 beta 5 on 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];

}

I hope it'll work for URL sharing as well.

like image 9
Adnan Avatar answered Oct 26 '22 05:10

Adnan


Your extension view controller should be adopting the NSExtensionRequestHandling protocol. One of this protocol's methods is:

- (void)beginRequestWithExtensionContext:(NSExtensionContext *)context

You should be waiting for this to be called before you attempt to get the NSExtensionContext. It even provides the context in the method as the context parameter.

This was outlined in this document.

like image 3
Andrew Avatar answered Oct 26 '22 05:10

Andrew