How can I create a custom UIActivity in iOS?

IosObjective CUiactivityviewcontrollerUiactivity

Ios Problem Overview


How can I create a custom UIActivity in iOS?

The reason I want this is to add a Review App button in one of my apps that takes the user to the review section in the App Store. How can I create such a custom UIActivity?

Ios Solutions


Solution 1 - Ios

First, create the files. I chose to name mine ActivityViewCustomActivity

Make ActivityViewCustomActivity.h look like this:

#import <UIKit/UIKit.h>

@interface ActivityViewCustomActivity : UIActivity

@end

Make ActivityViewCustomActivity.m look like this:

#import "ActivityViewCustomActivity.h"

@implementation ActivityViewCustomActivity

- (NSString *)activityType
{
    return @"yourappname.Review.App";
}

- (NSString *)activityTitle
{
    return @"Review App";
}

- (UIImage *)activityImage
{  
    // Note: These images need to have a transparent background and I recommend these sizes:
    // iPadShare@2x should be 126 px, iPadShare should be 53 px, iPhoneShare@2x should be 100 
    // px, and iPhoneShare should be 50 px. I found these sizes to work for what I was making.

    if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
    {
        return [UIImage imageNamed:@"iPadShare.png"];
    }
    else
    {
        return [UIImage imageNamed:@"iPhoneShare.png"];
    }
}

- (BOOL)canPerformWithActivityItems:(NSArray *)activityItems
{
    NSLog(@"%s", __FUNCTION__);
    return YES;
}

- (void)prepareWithActivityItems:(NSArray *)activityItems
{
    NSLog(@"%s",__FUNCTION__);
}

- (UIViewController *)activityViewController
{
    NSLog(@"%s",__FUNCTION__);
    return nil;
}

- (void)performActivity
{   
    // This is where you can do anything you want, and is the whole reason for creating a custom 
    // UIActivity

    [[UIApplication sharedApplication] openURL:[NSURL URLWithString:@"itms-apps://ax.itunes.apple.com/WebObjects/MZStore.woa/wa/viewContentsUserReviews?type=Purple+Software&id=yourappid"]];
    [self activityDidFinish:YES];
}

@end

This is what my image looked like: Here is the .PSD I made: -- malicious link removed -- And here is the original 250 px .png http://i.imgur.com/pGWVj.png

Now in your view controller do this:

#import "ActivityViewCustomActivity.h"

And now wherever you want to display your UIActivityViewController:

   NSString *textItem = @"Check out the yourAppNameHere app: itunes http link to your app here";
   UIImage *imageToShare = [UIImage imageNamed:@"anyImage.png"];
                
   NSArray *items = [NSArray arrayWithObjects:textItem,imageToShare,nil];
                
   ActivityViewCustomActivity *aVCA = [[ActivityViewCustomActivity alloc]init];
                
   UIActivityViewController *activityVC =
   [[UIActivityViewController alloc] initWithActivityItems:items
                                                  applicationActivities:[NSArray arrayWithObject:aVCA]];
     
   activityVC.excludedActivityTypes = @[UIActivityTypePostToWeibo, UIActivityTypeAssignToContact, UIActivityTypePrint, UIActivityTypeCopyToPasteboard, UIActivityTypeSaveToCameraRoll];
                
   activityVC.completionHandler = ^(NSString *activityType, BOOL completed)
   {
        NSLog(@"ActivityType: %@", activityType);
        NSLog(@"Completed: %i", completed);
   };
                
   if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
   {
      self.popoverController = [[UIPopoverController alloc] initWithContentViewController:activityVC];
                    
      CGRect rect = [[UIScreen mainScreen] bounds];

      [self.popoverController
                     presentPopoverFromRect:rect inView:self.view
                     permittedArrowDirections:0
                     animated:YES];
   }
   else
   {
       [self presentViewController:activityVC animated:YES completion:nil];
   }

Solution 2 - Ios

Here is my Swift Version - I needed multiple custom actions so I created this class. No need for delegates or protocols.

1. Add the custom Class

class ActivityViewCustomActivity: UIActivity {

    var customActivityType = ""
    var activityName = ""
    var activityImageName = ""
    var customActionWhenTapped:( (Void)-> Void)!
    
    init(title: String, imageName:String, performAction: (() -> ()) ) {
        self.activityName = title
        self.activityImageName = imageName
        self.customActivityType = "Action \(title)"
        self.customActionWhenTapped = performAction
        super.init()
    }
    
    override func activityType() -> String? {
        return customActivityType
    }
    
    override func activityTitle() -> String? {
        return activityName
    }
    
    override func activityImage() -> UIImage? {
        return UIImage(named: activityImageName)
    }
    
    override func canPerformWithActivityItems(activityItems: [AnyObject]) -> Bool {
        return true
    }
    
    override func prepareWithActivityItems(activityItems: [AnyObject]) {
        // nothing to prepare
    }
    
    override func activityViewController() -> UIViewController? {
        return nil
    }
    
    override func performActivity() {
        customActionWhenTapped()
    }
}

2 Use in your View Controller

I've attached it to a UIBarButtonItem, which calls the the following

@IBAction func actionButtonPressed(sender: UIBarButtonItem) {
    
    var sharingItems = [AnyObject]() // nothing to share...

    let myCustomActivity = ActivityViewCustomActivity(title: "Mark Selected", imageName: "removePin") {
        println("Do something")
    }
    
    let anotherCustomActivity = ActivityViewCustomActivity(title: "Reset All", imageName: "reload") {
        println("Do something else")
    }
    
    let activityViewController = UIActivityViewController(activityItems:sharingItems, applicationActivities:[myCustomActivity, anotherCustomActivity])
    
    activityViewController.excludedActivityTypes = [UIActivityTypeMail, UIActivityTypeAirDrop, UIActivityTypeMessage, UIActivityTypeAssignToContact, UIActivityTypePostToFacebook, UIActivityTypePrint, UIActivityTypeCopyToPasteboard, UIActivityTypeSaveToCameraRoll]
    
    activityViewController.popoverPresentationController?.barButtonItem = sender
    
    self.presentViewController(activityViewController, animated: true, completion: nil)
}

Solution 3 - Ios

My Swift 3 Implementation based off of DogCoffee's:

class ActivityViewCustomActivity: UIActivity {
    
    // MARK: Properties
    
    var customActivityType: UIActivityType
    var activityName: String
    var activityImageName: String
    var customActionWhenTapped: () -> Void
    
    
    // MARK: Initializer
    
    init(title: String, imageName: String, performAction: @escaping () -> Void) {
        self.activityName = title
        self.activityImageName = imageName
        self.customActivityType = UIActivityType(rawValue: "Action \(title)")
        self.customActionWhenTapped = performAction
        super.init()
    }
    
    
    
    // MARK: Overrides
    
    override var activityType: UIActivityType? {
        return customActivityType
    }
    
    
    
    override var activityTitle: String? {
        return activityName
    }
    
    
    
    override class var activityCategory: UIActivityCategory {
        return .share
    }
    
    
    
    override var activityImage: UIImage? {
        return UIImage(named: activityImageName)
    }
    
    
    
    override func canPerform(withActivityItems activityItems: [Any]) -> Bool {
        return true
    }
    
    
    
    override func prepare(withActivityItems activityItems: [Any]) {
        // Nothing to prepare
    }
    
    
    
    override func perform() {
        customActionWhenTapped()
    }
}

Solution 4 - Ios

Here's an example of putting up an email composer interface using the -activityViewController method of UIActivity. This shows how to put up a UIKit viewController or your own custom viewController for whatever purpose you choose. It supplants the -performActivity method.

#import <MessageUI/MessageUI.h>
#import <UIKit/UIKit.h>

@interface EPSuggestionsActivity : UIActivity <MFMailComposeViewControllerDelegate>

@end

@implementation EPSuggestionsActivity

....

- (UIViewController *)activityViewController{
    
    MFMailComposeViewController *picker = [[MFMailComposeViewController alloc] init];
    picker.mailComposeDelegate = self;
    
    NSString *emailAddress = @"[email protected]";
    NSArray *toRecipients = @[emailAddress];
    [picker setToRecipients:toRecipients];
    [picker setSubject:@"Suggestions"];
    
    return picker;
}

#pragma mark - MFMailComposeViewControllerDelegate Method

- (void)mailComposeController:(MFMailComposeViewController*)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError*)error  {
    
    [self activityDidFinish:YES];   //  Forces the activityViewController to be dismissed
}

@end

Notice that -activityDidFinish is called from the mail composer delegate after the user has dismissed the email interface. This is required to get the UIActivityViewController interface to disappear. If you write your own viewController it will need a delegate method that it calls when finished and you will have to make your subclass of UIActivity the delegate.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionklcjr89View Question on Stackoverflow
Solution 1 - Iosklcjr89View Answer on Stackoverflow
Solution 2 - IosDogCoffeeView Answer on Stackoverflow
Solution 3 - IosjohnslayView Answer on Stackoverflow
Solution 4 - IosPaul LinsayView Answer on Stackoverflow