UIActivityViewController completion handler still calls action if user presses cancel
Asked Answered
A

8

10

In my UIActivityViewController, I use completion handler to execute a "successfully shared" notification. It works but my only problem is, it still shows the notification if the user presses cancel.

Here is my completion handler code,

[controller setCompletionHandler:^(NSString *activityType, BOOL completed) {


    CWStatusBarNotification *notification = [CWStatusBarNotification new];
    [notification displayNotificationWithMessage:@"✓ Successfully Shared Centre!"
                                          forDuration:3.0f];

    notification.notificationLabelBackgroundColor = [UIColor colorWithRed:38.0f/255.0f green:81.0f/255.0f blue:123.0f/255.0f alpha:1.0f];
    notification.notificationLabelTextColor = [UIColor whiteColor];



}];

Thanks for the help!

Arta answered 28/2, 2014 at 0:42 Comment(2)
Suggestion: don't show "Successfully shared" notification. It's likely to be annoying.Weiner
My designer wants it, I don't agree with it but he's the head :/Arta
M
12

That's what the completed argument is for:

[controller setCompletionHandler:^(NSString *activityType, BOOL completed) {
    if (!completed) return;

    CWStatusBarNotification *notification = [CWStatusBarNotification new];
    [notification displayNotificationWithMessage:@"✓ Successfully Shared Centre!"
                                     forDuration:3.0f];

    notification.notificationLabelBackgroundColor = [UIColor colorWithRed:38.0f/255.0f green:81.0f/255.0f blue:123.0f/255.0f alpha:1.0f];
    notification.notificationLabelTextColor = [UIColor whiteColor];
}];
Millimeter answered 28/2, 2014 at 0:51 Comment(0)
S
19

Note: the completionHandler property is deprecated in iOS8, so it's not possible anymore to know the result of a share action. https://developer.apple.com/documentation/uikit/uiactivityviewcontroller/1622010-completionhandler

Update: Like adruzh said, on iOS8 there's a new completionHandler that Apple forgot to mention in the documentation:

[activityController setCompletionWithItemsHandler:
    ^(NSString *activityType, BOOL completed, NSArray *returnedItems, NSError *activityError) {
}];

https://developer.apple.com/documentation/uikit/uiactivityviewcontroller/1622022-completionwithitemshandler

Stereochrome answered 14/8, 2014 at 9:54 Comment(1)
Looks like a bug in the documentation - there is a new handler, it is referred in UIKit changesTuscany
M
12

That's what the completed argument is for:

[controller setCompletionHandler:^(NSString *activityType, BOOL completed) {
    if (!completed) return;

    CWStatusBarNotification *notification = [CWStatusBarNotification new];
    [notification displayNotificationWithMessage:@"✓ Successfully Shared Centre!"
                                     forDuration:3.0f];

    notification.notificationLabelBackgroundColor = [UIColor colorWithRed:38.0f/255.0f green:81.0f/255.0f blue:123.0f/255.0f alpha:1.0f];
    notification.notificationLabelTextColor = [UIColor whiteColor];
}];
Millimeter answered 28/2, 2014 at 0:51 Comment(0)
R
4

For Swift, this is what worked for us:

    ...

    // Configure UIActivityViewController
    let activityViewController = UIActivityViewController(activityItems: objectsToShare, applicationActivities: nil)
    activityViewController.excludedActivityTypes = [UIActivityTypeAirDrop,
        UIActivityTypeAddToReadingList,
        UIActivityTypeAssignToContact,
        UIActivityTypePrint,
        UIActivityTypeCopyToPasteboard]

    // Show UIActivityViewController
    presentViewController(activityViewController, animated: true, completion: nil)

    // Define completion handler
    activityViewController.completionWithItemsHandler = doneSharingHandler

    ...

func doneSharingHandler(activityType: String!, completed: Bool, returnedItems: [AnyObject]!, error: NSError!) {
    // Return if cancelled
    if (!completed) {
        return
    }

    // If here, log which activity occurred
    println("Shared video activity: \(activityType)")
}
Relique answered 5/7, 2015 at 9:35 Comment(1)
Type of expression is ambiguous without more context when assigning the callbackJaneanjaneczka
P
3

Swift 5 - The below function covers most of the UIActivityViewController properties. It worked for me and thought so it might be helpful for you guys as well.

func performShareAction() {
        let itemsToShare : [Any] = ["Hello World"]
        let activityView = UIActivityViewController(activityItems: itemsToShare, applicationActivities: nil)
        
        // Apps that you want to exclude sharing the items
        let excludedActivityTypes : [UIActivity.ActivityType] = [
            .addToReadingList,
            .assignToContact,
            .copyToPasteboard,
            .mail,
            .markupAsPDF,
            .message,
            .openInIBooks,
            .postToFacebook,
            .postToFlickr,
            .postToTencentWeibo,
            .postToTwitter,
            .postToVimeo,
            .postToWeibo,
            .print,
            .saveToCameraRoll
        ]

        activityView.excludedActivityTypes = excludedActivityTypes
        self.present(activityView, animated: true, completion: nil)
        
        activityView.completionWithItemsHandler = { activityType, completed, items, error in
            
            // Event Cancelled
            if !completed {
                print("Content Sharing was cancelled.")
                return
            }
            
            // Content Shared on particular activity
            print("Shared on activity type: \(String(describing: activityType?.rawValue))")
            
            // Detect app on which the items are shared
            if let type = activityType {
                switch type {
                case .addToReadingList: print("Added To Reading List"); break
                case .airDrop: print("AirDropped to Other Device"); break
                case .assignToContact: print("Assigned To Contact"); break
                case .copyToPasteboard: print("Copied To Pasteboard"); break
                case .mail: print("Mailed"); break
                case .markupAsPDF: print("Marked-Up As PDF"); break
                case .message: print("Messaged"); break
                case .openInIBooks: print("Opened In iBooks"); break
                case .postToFacebook: print("Posted To Facebook"); break
                case .postToFlickr: print("Posted To Flickr"); break
                case .postToTencentWeibo: print("Posted To Tencent Weibo"); break
                case .postToTwitter: print("Posted To Twitter"); break
                case .postToVimeo: print("Posted To Vimeo"); break
                case .postToWeibo: print("Posted To Weibo"); break
                case .print: print("Printed"); break
                case .saveToCameraRoll: print("Saved To Camera Roll"); break
                default: print("Shared with new app"); break
                }
            }
        }
    }
Panjabi answered 7/8, 2020 at 7:9 Comment(0)
J
2

For the Swifties out there, here's how you would code this in Swift along with some share service detection:

activityViewController.completionHandler = {(activityType, completed:Bool) in
    if !completed {
        //cancelled
        return
    }

    //shared successfully

    //below is how you would detect for different sharing services
    var activity:String = "other"
    if activityType == UIActivityTypePostToTwitter {
        activity = "twitter"
    }
    if activityType == UIActivityTypeMail {
        activity = "mail"
    }
    //more code here if you like
}
Johns answered 9/1, 2015 at 23:46 Comment(1)
completionHandler is deprecated in iOS 8. For iOS 8, use completionWithItemsHandler.Relique
L
1

The completed parameter will be NO is the user cancels.

[controller setCompletionHandler:^(NSString *activityType, BOOL completed) {
    if (completed) {
        CWStatusBarNotification *notification = [CWStatusBarNotification new];
        [notification displayNotificationWithMessage:@"✓ Successfully Shared Centre!"
                                          forDuration:3.0f];

        notification.notificationLabelBackgroundColor = [UIColor colorWithRed:38.0f/255.0f green:81.0f/255.0f blue:123.0f/255.0f alpha:1.0f];
        notification.notificationLabelTextColor = [UIColor whiteColor];
    }
}];
Lewislewisite answered 28/2, 2014 at 0:50 Comment(0)
M
1

SWIFT 2.0, iOS 8.0 >, you should use completion handler like this:

self.presentViewController(activityVC, animated: true, completion: nil)

activityVC.completionWithItemsHandler = {(activityType, completed:Bool, returnedItems:[AnyObject]?, error: NSError?) in
     //do some action
}

see my answer here: https://mcmap.net/q/415935/-uiactivityviewcontroller-completion-handler-returns-success-when-tweet-has-failed

Menjivar answered 3/1, 2016 at 21:44 Comment(0)
E
1

Swift 3

   func completionHandler(activityType: UIActivityType?, shared: Bool, items: [Any]?, error: Error?) {
        if (shared) {
            print("Cool user shared some stuff")
        }
        else {
            print("Bad user canceled sharing :(")
        }
    }

    activityController.completionWithItemsHandler = completionHandler
Erdei answered 23/1, 2017 at 9:33 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.