Fresh Beginning
  • Home
  • Portfolio
  • Buy Me A Coffee
  • Patreon
  • Speaking
  • Reading
  • About Me
Subscribe
Swift

Using UIActivityViewController (Swift)

  • Jayesh Kawli

Jayesh Kawli

May 28, 2016 • 3 min read

Last week at work I found myself into interesting problem. We had to show the share action sheet. Not just Facebook, Twitter or Google plus, but the one iOS natively offers like this,

activity_view_controller

At the first look it looked quite daunting. So as usual I inflated my estimate to 4 hours. Though I was not quite sure if that would be enough in spite of escalated time.

  • Creating custom UIActivity objects:
    In the following paragraph we will create two custom application activities as follows

  • Custom application activity object to show Google search


class CustomActivityOne: UIActivity {
    override func activityType() -> String? {
        return "jayesh.activityType.Search"
    }
    
    override func activityTitle() -> String? {
        return "Search Engine"
    }
    
    override func activityImage() -> UIImage? {
        return UIImage(named: "google")
    }
    
    override func canPerformWithActivityItems(activityItems: [AnyObject]) -> Bool {
        return true
    }
    
    override func prepareWithActivityItems(activityItems: [AnyObject]) {
        
    }
    
    override func performActivity() {
        UIApplication.sharedApplication().openURL(NSURL(string: "https://www.google.com")!)
    }
}
  • Custom application activity object to show custom view controller

class CustomActivityTwo: UIActivity {
    
    var navController: UINavigationController = UINavigationController()
    
    override func activityType() -> String? {
        return "jayesh.activityType.Obama"
    }
    
    override func activityTitle() -> String? {
        return "President"
    }
    
    override func activityImage() -> UIImage? {
        return UIImage(named: "obama_icon")
    }
    
    override func canPerformWithActivityItems(activityItems: [AnyObject]) -> Bool {
        return true
    }
    
    override func prepareWithActivityItems(activityItems: [AnyObject]) {
        
    }
    
    override func activityViewController() -> UIViewController? {
        let presidentViewController = UIStoryboard(name: "Main", bundle: nil).instantiateViewControllerWithIdentifier("president")
        navController = UINavigationController(rootViewController: presidentViewController)
        presidentViewController.title = "Barack Obama"
        presidentViewController.navigationItem.leftBarButtonItem = UIBarButtonItem(barButtonSystemItem: .Cancel, target: self, action: #selector(dismissViewController))
        return navController
    }
    
    func dismissViewController() {
        navController.dismissViewControllerAnimated(true, completion: nil)
        activityDidFinish(true)
    }
}

So we have created two custom application activity objects. We will then add these custom objects to our UIActivityViewController during initialization.

We will first create a button. When user presses this button, we will present an activity view controller

activity_view_controller_button

activity_view_controller

As you can see in the above screenshot, two custom application activities I have added are visible in the activities list. Viz. Google Search and President


@IBAction func openActivityControllerButtonPressed(sender: UIButton) {
        
        let activityItems = ["Please check out my website", NSURL(string: "https://www.jayeshkawli.ghost.io")!, "Awesome Donuts", UIImage(named: "donuts.jpg")!]
        
        let searchActivity = CustomActivityOne()
        let presidentActivity = CustomActivityTwo()
        let customActivityTypes = [searchActivity, presidentActivity]
        
        let activityIndicatorView = UIActivityViewController(activityItems: activityItems, applicationActivities: customActivityTypes)
        
        activityIndicatorView.popoverPresentationController?.sourceView = sender
        activityIndicatorView.completionWithItemsHandler = { (activityType, completed, returnedItems, error) in
            if let activityName = activityType?.componentsSeparatedByString(".").last {
                let completedString = completed ? "Completed" : "Cancelled"
                let operationFinishMessage = "Activity '\(activityName)' \(completedString)"
                self.showMessage(operationFinishMessage)
            }
        }
        self.presentViewController(activityIndicatorView, animated: true, completion: nil)
    }

Also, when user performs any action from activity items, based on the action taken, we will also show an alert dialogue whether action was completed or cancelled.


func showMessage(alertDetail: String) {
        let alertController = UIAlertController(title: "Activity View Controller Demo", message: alertDetail, preferredStyle: .Alert)
        let alertAction = UIAlertAction(title: "OK", style: .Default, handler: nil)
        alertController.addAction(alertAction)
        self.presentViewController(alertController, animated: true, completion: nil)
    }
  • Please note that in addition to application activities, I have also added another set of activityItems as follows :
  1. Item to share an URL. User can add it to reading list of open with Safari

  2. Item to share an image. User can store it in the photos or share it though a message


 let activityItems = ["Please check out my website", NSURL(string: "https://www.jayeshkawli.ghost.io")!, "Awesome Donuts", UIImage(named: "donuts.jpg")!]

And then we initialize out UIActivityViewController with these custom activities and present it on the viewport.


let activityIndicatorView = UIActivityViewController(activityItems: activityItems, applicationActivities: customActivityTypes)
self.presentViewController(activityIndicatorView, animated: true, completion: nil)

You can also get a callback when user selects activity items from list, action is successfully performed or cancelled as follows :


activityIndicatorView.completionWithItemsHandler = { (activityType, completed, returnedItems, error) in
            if let activityName = activityType?.componentsSeparatedByString(".").last {
                let completedString = completed ? "Completed" : "Cancelled"
                let operationFinishMessage = "Activity '\(activityName)' \(completedString)"
                self.showMessage(operationFinishMessage)
            }
        }

I have hosted the full code for this project on GitHub too. Feel free to give any suggestions or comments. Any pull requests or critics are most welcome.

Please check out my Patreon and BuyMeACoffee pages too.
If you like my articles and want to keep me going on this journey, please consider donating on these platforms.
Your support in any form is much appreciated.
Buy me a coffee support

Patreon support

Sign up for more like this.

Enter your email
Subscribe
Portfolio

Portfolio

Hello, I am Jayesh Kawli. I have been writing iOS applications for the last 9 years. During this time, I got a chance to work on iOS applications from various domains. Below is the list of all the apps I was responsible for developing and releasing in the app store.
Jan 30, 2023 6 min read
Using MVVM Architecture with SwiftUI - Clean Architecture

Using MVVM Architecture with SwiftUI - Clean Architecture

MVVM has been a choice of architecture in iOS development for a long time. It survived the Objective-C era and has been quite popular in Swift world too. However, things became slightly complicated when SwiftUI came along. It was a bit confusing to see how it can be used in
Oct 24, 2022 8 min read
A Better Way to Generate Reuse Identifiers in Swift and iOS

A Better Way to Generate Reuse Identifiers in Swift and iOS

iOS offers an elegant way to improve table view and collection view performance by cell reuse. These scroll views may have millions of cells, but iOS only stores the visible cells in memory and reuses them as they go out of view. This enables OS to save on memory and
Oct 20, 2022 2 min read
Fresh Beginning © 2023
Powered by Ghost