Receiving Data from an iOS 16 Action Extension

The previous chapter covered the steps involved in creating an Action extension in iOS designed to modify and display text content from a host app. In developing the extension, steps were taken to ensure the modified content was returned to the host app when the user exited the extension. This chapter will work through creating an example host app that demonstrates how to receive data from an Action extension.

Creating the Example Project

Start Xcode and create a new project using the iOS App template with the Swift and Storyboard options selected, entering ActionHostApp as the product name.

The finished app will consist of a Text View object and a toolbar containing a Share button that will provide access to the Change it Up Action extension created in the previous chapter. When the Action extension returns, the host app will receive the modified content from the extension and display it to the user.

Designing the User Interface

Locate and load the Main.storyboard file into the Interface Builder tool and drag and drop a Toolbar instance to position it along the bottom edge of the layout canvas. Next, drag and drop a Text View object onto the canvas and resize and position it so it occupies the remaining space above the toolbar, stretching the view horizontally until the blue margin guidelines appear. With the TextView object selected, display the Attributes Inspector and change the displayed text to “This is some sample text”.

Display the Resolve Auto Layout Issues menu and select the Reset to Suggested Constraints option listed under All Views in View Controller. At this point, the layout should resemble Figure 78-1:

 

You are reading a sample chapter from Building iOS 17 Apps using Xcode Storyboards.

Buy the full book now in eBook or Print format.

The full book contains 96 chapters and 760 pages of in-depth information.

Learn more.

Preview  Buy eBook  Buy Print

 

Figure 78-1

Before proceeding, display the Assistant Editor panel and establish an outlet for the Text View object named myTextView.

Importing the Mobile Core Services Framework

The code added to this project will use a definition declared within the Mobile Core Services framework. To avoid compilation errors, this framework must be imported into the ViewController.swift file as follows:

import UIKit
import MobileCoreServices

class ViewController: UIViewController {
.
.
}Code language: Swift (swift)

Adding an Action Button to the App

To access the “Change it Up” Action extension from within this host app, it will be necessary to implement an Action button. As the user interface currently stands, the toolbar contains a single button item displaying text which reads “Item”. To change this to an Action button, select it in the storyboard layout (remembering that it may be necessary to click on it twice since the first click typically selects the parent toolbar rather than the button item).

With the button selected, display the Attributes Inspector and change the System Item menu from Custom to Action:

Figure 78-2

Once the change has been made, the button item should now have the standard appearance of an iOS Action button, as shown in Figure 78-3:

 

You are reading a sample chapter from Building iOS 17 Apps using Xcode Storyboards.

Buy the full book now in eBook or Print format.

The full book contains 96 chapters and 760 pages of in-depth information.

Learn more.

Preview  Buy eBook  Buy Print

 

Figure 78-3

Now that the button looks like an Action button, some code needs to be added to display the activity view controller when the user taps it. First, with the Assistant Editor displayed, Right-click on the button and drag the resulting line to a suitable location within the ViewController.swift file. Next, release the line and create an Action outlet named showActionView. Once created, implement the code in this method so that it reads as follows:

@IBAction func showActionView(_ sender: Any) {
    let activityViewController =
        UIActivityViewController(activityItems:
            [myTextView.text ?? ""], applicationActivities: nil)

    self.present(activityViewController,
                 animated:true, completion: nil)

    activityViewController.completionWithItemsHandler =
        { (activityType, completed, returnedItems, error) in

        }
}Code language: Swift (swift)

The code within the method creates a new UIActivityViewController instance initialized with the Text View content in the user interface. The activity view controller is then displayed to the user. Finally, a closure is assigned as the completion handler (the code for which will be implemented later) to be executed when the Action extension returns control to the app.

Compile and run the app and tap the Action button to test that the activity view controller appears. Next, select the “Change it Up” extension and verify that it displays the text extracted from the Text View. Finally, tap the Done button to return to the host app, noting that the original text content has not yet been converted to uppercase. This functionality now needs to be implemented within the completion handler method.

Receiving Data from an Extension

When the user exits from an Action extension, the completion handler assigned to the UIActivityViewController instance will be called and passed various parameters. One of those parameters will be an array of NSExtensionItem objects containing NSItemProvider objects that can be used to load any data the extension has returned.

Using the same techniques described in the previous chapter (Creating an iOS 16 Action Extension), this data can be extracted by making the following changes to the completion handler closure:

 

You are reading a sample chapter from Building iOS 17 Apps using Xcode Storyboards.

Buy the full book now in eBook or Print format.

The full book contains 96 chapters and 760 pages of in-depth information.

Learn more.

Preview  Buy eBook  Buy Print

 

.
.
import UniformTypeIdentifiers
.
.
activityViewController.completionWithItemsHandler =
                { (activityType, completed, returnedItems, error) in

           if let items = returnedItems, items.count > 0 {
            
            let textItem: NSExtensionItem =
                items[0] as! NSExtensionItem
   
            let textItemProvider =
                textItem.attachments![0]
            
            if textItemProvider.hasItemConformingToTypeIdentifier(
                UTType.text.identifier) {
                
                textItemProvider.loadItem(
                    forTypeIdentifier: UTType.text.identifier,
                    options: nil,
                    completionHandler: {(string, error) -> Void in
                        let newtext = string as! String
                        DispatchQueue.main.async(execute: {
                            self.myTextView.text = newtext
                        })
                })
            }
        }     
    }
}
.
.
.Code language: Swift (swift)

The method obtains a reference to the item provider and verifies that at least one item has been returned from the extension. A test is then performed to ensure that it is a text item. If the item is text-based, the item is loaded from the extension, and a completion handler is used to assign the new text to the Text View object. Note that the code to set the text on the TextView object is dispatched to the main thread for execution. This is because all user interface changes must be performed on the app’s main thread, and completion handler code such as this is executed in a different thread.

Testing the App

Compile and run the app, select the Action button, and launch the “Change it Up” extension. On returning to the host app, the original text should now have been updated to be displayed in uppercase as modified within the extension.

Summary

In addition to providing an alternative view of the content in a host app, Action extensions can be used to somehow transform that content. This transformation can be performed and viewed within the extension, and a mechanism is also provided to return that modified content to the host app. By default, most host apps will not use the returned content. In reality, adding this support is a relatively simple task that involves implementing a completion handler method to handle the content returned from the extension into the host app and assigning that handler method to be called when the activity view controller is displayed to the user.


Categories