Meet Shortcuts for macOS

submited by
Style Pass
2021-06-15 15:00:03

Shortcuts is coming to macOS, and your apps are a key part of that process. Discover how you can elevate the capabilities of your app by exposing those features as Shortcuts actions. We'll show you how to build actions for your macOS apps built with Catalyst or AppKit, deploy actions across platforms, publish and share shortcuts, and enable your app to run shortcuts from other apps. We'll also take you through how Shortcuts fits in with existing Mac automation technologies like Automator and AppleScript.

Hi, everyone! My name is Ayaka, and I'm so happy to be here to introduce you to Shortcuts for Mac.

I wanna first start with a quick overview of Shortcuts for Mac, and also some of the other exciting new updates we're bringing this year to Shortcuts. Shortcuts lets people automate repetitive tasks and connect together functionality from different apps to solve problems. It lets you be creative with how you use your technology. And Shortcuts for Mac is gonna make automation more fun and accessible than ever before.

When you open the app for the first time, you'll see all of your shortcuts already synced from your iPhone. The app also includes a Shortcuts Gallery, where you can discover new shortcuts that are ready to use, including brand-new Mac-specific ones. And if you want to create your own shortcuts, you can also use the Shortcuts Editor, which is re-designed from the ground up to feel at home on the Mac. By the way, we wrote almost the entire Mac app in SwiftUI, which allows us to maintain a unified codebase between our iOS and Mac apps while letting us tailor the details to each platform.

Like on iOS, any app on the Mac can provide actions to Shortcuts. In this session, we're gonna cover how supporting Shortcuts in your apps can enable powerful workflows on macOS, whether you're developing an iOS app, a native Mac app, or an app built with Mac Catalyst.

We'll also cover how Shortcuts fits into the bigger picture of Mac automation, including existing tools that we know and love like AppleScript and Automator.

This year, we also added two new automation types for Focus and Sound Recognition, along with a whole new suite of actions that let you manage your windows and files, plus many more, which we'll highlight later.

We'll cover how your app, too, can provide custom actions for people to create powerful shortcuts.

By the way, if your app integrates with file providers, these new Files actions will automatically work with the files that your app provides. And, if you have an app that adopts the existing SiriKit messages intent, we'll now automatically expose this capability via a custom Send Message action from your app.

We also have some exciting new updates to Sharing, and we know developers love to build and share shortcuts. This year, we're making Shortcuts much easier to distribute. We also have a new file format that lets you distribute Shortcuts as files. And we've enabled private sharing, which is useful for sharing Shortcuts with your peers. Let's take a look.

Now, anyone can download Shortcuts, without having to turn on any special settings. This means that you can distribute your own Shortcuts on your website or in your app.

For example, let's say, you wanna give people an awesome Shortcut that uses actions from your app. Now, if you build that Shortcut and share it to iCloud, Apple will notarize the Shortcut and turn it into a link, which you can feature in your app or website and make it easy for people to download.

We're also keeping people in control of their data by presenting more specific permission prompts when they download a Shortcut that passes data into your app like a photo from their library. And there's more. Shortcuts can now also be shared as files, which is useful if you need to distribute Shortcuts outside of iCloud. And just like iCloud links, Shortcuts files are notarized by Apple to make sure they're safe.

Last but not least, there's a new mode for sharing Shortcuts privately, without uploading to iCloud, that you can use for sharing with contacts or for saving personal backups.

Shortcuts files are signed with the identity of the person who sent them. If you need to re-sign a Shortcut, you can use the new Shortcuts command-line tool. So those are all the exciting new updates for Shortcuts this year. Now let's take a look at how Shortcuts fits in with our existing Mac automation technologies. The Mac has a long history of deep support for Automation, including AppleScript, Shell Scripting, and Automator. We're excited to share that Shortcuts has full support for AppleScripts and Shell Scripting. We have new actions, built right into Shortcuts, that let you write and run scripts directly inside the Shortcuts editor.

Next, let's take a look at Automator. Automator is an existing automation tool on the Mac that lets you create workflows to automate repetitive tasks. Shortcuts is the future of Mac automation. But we still care deeply about Automator and everyone who relies on it. In order to make the transition from Automator to Shortcuts as smooth as possible, we've built a migration tool that can convert most Automator workflows into Shortcuts. For example, if you have a great workflow that makes images from PDF documents selected in Finder, Shortcuts can import that and turn each Automator action into one or more Shortcuts actions.

All you have to do, is open the workflow file in the Shortcuts app by dragging it into the app or by using the right-click menu, and that's it! Your workflow is turned into a Shortcut. In order to enable the migrator, we added all of the most popular Automator actions to Shortcuts, actions that run Shell Scripts and AppleScripts, manage your files, and more. And, of course, all of these actions are supported by our migrator. Now, let's talk about how your app fits in to Shortcuts and the value it can create for customers. The main way your app can integrate with Shortcuts is by exposing its capabilities via "actions." By exposing actions to Shortcuts, people can use your app's functionality faster, create powerful workflows using your apps, and last but not least, use your app in conjunction with other apps. Let's take a deeper look at these. There are so many places in macOS where people can run their shortcuts. If you expose an action from your app, all of a sudden, people will be able to use it from the Shortcuts app itself, the Shortcuts menu bar, by typing a Keyboard shortcut, by searching in Spotlight, and much more.

So you're opening people up to use your features faster and in more places than ever before. And on top of that, your app's actions can be used as a part of powerful, multi-step Shortcuts. Let's say you make a to-do app that lets people manage their tasks. If you expose the app's capabilities as actions, all of a sudden, people can use those actions to make powerful workflows. For example, I can create a Shortcut that finds all of my to-do’s that are due tomorrow, sets the priority to high, and shows them to me in a list, all in one click. Because of all the different ways you can hook actions together, by exposing just a few actions, you can enable thousands of new use cases for your app's functionality. By exposing actions from your app, you can also enable people to use your app's functionality in conjunction with other apps.

For example, if you make an image editing app and expose an action to apply your app's custom image filters, all of a sudden, people can use that action to make workflows like this one that lets me select a photo, applies an image filter, and posts it to social media, all in one click. So, those are just a few examples of how exposing actions can supercharge what people can do with your apps. Be sure to check out the session covering designing great actions to learn more about what kinds of actions you can provide to empower people with your apps. I'm gonna hand it off to Ian now who will show you how to actually build these actions. Hi, I'm Ian, and today I'm going to show you how to build Shortcuts actions for your Mac apps. Later, I'll cover some special considerations you should keep in mind for your integration. Let's get started with building actions. Just like on iOS, actions for Shortcuts are built using the Intents framework, which is also known as SiriKit. For this session, I'm gonna pretend that I'm developing a collaborative task management app which lets people keep track of a list of tasks that they need to do, each with their own due date, and share those tasks with others. It's really important for people to be able use my app's functionality from anywhere on the Mac. By integrating with Shortcuts, I can allow my users to build multi-step Shortcuts involving tasks in my app.

Looking at the app, the primary type of content the user interacts with is a task. Each task has a couple of important attributes. First, there's the title, which is some text that describes what needs to be done. Tasks also have a due date and a link to share the task with others. There's a bunch of operations you can perform related to tasks in the app, as well, which we can think of as the verbs. You can add new tasks, edit or delete existing tasks, get tasks that match a certain criteria, and, of course, the app can display a specific task to you. So, for each of those verbs, I'm going to create actions. These will form the primitive operations that users can invoke, and these actions are designed so that people can use them together.

For example, you could get a task, and then delete it, by pairing those two together.

With just Create Task, someone could create an automated workflow that takes selected text from Notes, capitalizes the text if necessary, and asks the user to enter a due date. Then, the shortcut can pass that text and due date into the Create Task action, which will deliver an intent to create the task to my app. Once the task has been created in my app, my intent will return the task, including the sharing URL, and the Shortcut can send that link to someone in a message.

Now, that's just one example. Because there are so many different actions in Shortcuts, people can utilize the Create Task action in nearly infinite ways. Now that I know which actions the app will expose, I'm going to get started implementing them.

The first step of implementing is creating an intent definition file for your app. Add this file to your Xcode project, and it will compile alongside your source code.

For this presentation, I have a fairly basic SwiftUI app for Mac. However, regardless of the UI framework that you use, the process of adding intents will be very similar. First, I'll create an intent definition file.

In the template pane, I'll search for intent definition.

The default name is fine. Make sure to add it to the app target so it compiles.

Here's the new, empty intent definition file.

Inside the file, I'll need to define each intent that the app implements, as well as other types that are used, like task, in this case. This app will have a number of intents, each which reference this task type, so I'll start by defining our task type. To do that, click the + button in the bottom left and select "New Type." Each type will automatically have identifier and displayString properties.

The displayString property will work for the title of the task, but we'll need to add more properties to the type for the due date and sharing link. First, I'll add the due date property, which specifies when the task has to be completed by.

I'm going to choose the Date Components type since this will represent a date and time.

I'll also add the URL, which is a link to the task that can be shared with others.

Now that the first task is complete, no pun intended, I'll move on and define an intent. This will be the intent that lets you create a task.

I'll give it a name, "Create Task," and change the category to Create.

I'll also write a short description, describing what the intent does.

Users will see this when they're looking through the list of actions that the app implements. Next, I will define the parameters for the intent. Think of the intent like a function, and parameters as the arguments that must be passed in for the function to do its work.

In order to create a new task, my app will need to know the title and the due date, so I will make a parameter for each of those. The sharing link will not need to be collected up front, since the app will generate one when the task is made. Let's start by adding a parameter for the title.

We'll select String as the type.

Each type of parameter has some configuration options associated with it. You can specify a default value, if that makes sense. But for this case, I'll just leave it as an empty string. Next, I'll add the due date parameter, with a Date Components type.

And I'll add a prompt here, so if the user doesn't enter a date ahead of time, the app can ask them for one at runtime.

Now that both parameters have been defined, we're almost done. Finally, I need to scroll down to the Shortcuts app section and fill in a few more things. First, I'll specify an input parameter. Since often users will be taking text from somewhere else and passing it into our action, I will pick the title parameter to be the input. This will improve the experience when building the shortcut, so if the user already has text from a previous action in their shortcut, it'll be filled in automatically for them when they add our action. The last thing I need to do is define a summary. This string is displayed to the user when they look at this action in a shortcut. I will call it "Create task with due date." Both of our parameters are required to create a task, so I'm putting both of those in the summary, so they are always visible when you look at the action. If you have more parameters that you don't wanna put in the summary, feel free to leave them out. If you do this, the user will be able to expand the action and edit those.

Once you've defined intents, Xcode will generate classes and protocols for you to use in your implementation. Now, I'm going to build the app. This will make sure there's no problems with the intent definition before we continue. In the build log, I now see some new code getting built. These source files are generated by Xcode based on what was put into the intent definition. Xcode generated source code for the Task type, as well as the CreateTaskIntent.

These new types can now be used in our app's codebase. Additionally, now that the intent has been defined, I can launch the Shortcuts app and create a new shortcut and search for the new Create Task action. It won't work yet, since I haven't written any code. Next, the app will need to dispatch and handle incoming intents. This code will run when someone runs the action through Shortcuts or Siri.

Apps need to decide which process will handle their intents, and there's two options. First, handling them in-app, or second, building a separate intents extension.

In-app intent handling allows an app to manipulate its state in response to incoming intents which get delivered to the app delegate. Most apps should start with this and move to an intents extension, if necessary.

An intents extension is a lightweight, standalone process that can handle intents on behalf of an app. Since every time an intent is run a process needs to be launched, building an intents extension can help be as efficient as possible, since the app itself won't have to launch.

Apps and intents extensions will be asked to instantiate and return an intent handler object for each incoming intent. Let's look at the APIs you should implement to do this.

For in-app intent handling, there are AppDelegate methods that let you return your intent handler.

In macOS Monterey, this API is now available for NSApplicationDelegate, as well. For intents extensions, subclasses of INExtension can override the handlerForIntent method.

For more information about the differences between in-app intent handling and intents extensions, watch the "Empower your intents" session from WWDC 2020.

Now, I'll go into the app and implement in-app intent handling. The first thing I need to do is add the CreateTaskIntent as a supported intent for the app. This lets the system know that this intent should be delivered into the app delegate.

Next, go to the main app source code.

First, I'll create an app delegate for the app. Since this is using the SwiftUI app life cycle, I'll also need to create a delegate adaptor to hook the object up to SwiftUI.

To receive intents, import the intents framework and implement the handlerForIntent method.

Now that there's a dispatch method, the next step is to implement a handler for the intent.

For this example, I'll create a new class to handle the intent, and this can be any object in your app. The intent handler must conform to the generated protocol for this intent which ends with the word "Handling." For the Create Task intent, it's named CreateTaskIntentHandling.

Then, I'll update the handlerForIntent method to return a new IntentHandler object when the intent is a CreateTaskIntent.

Xcode should let you know which methods you need to implement.

Intent handling protocols can contain four different types of methods: resolve, provide options, confirm, and handle. A resolve method will be generated for each of your parameters. This will be your chance to check if the parameter is valid and tell the system what to do if it's not.

For this intent, there are two resolve methods, one for the title, and another for the due date.

For the title parameter, the app needs to make sure the value is not nil and isn't empty.

If the title's empty, it returns needsValue, which tells the system to prompt the user to enter a value.

For the due date parameter, something similar is implemented where the due date is validated to make sure it's not nil. Looking at the app's requirements for due dates, the resolve method also needs to ensure that all due dates are in the future and show an error to the user if the date is in the past.

To do this, I'll go back to our intent definition file and add a custom validation error.

I'll give it a code, invalidDate, and an error message saying that the due date must be in the future.

Now, the app can return the unsupported result with the custom validation error that I just added, which will display the error message about the date being invalid. Another type of method is provide options. You'll see this for any parameter with the Dynamic Options setting enabled. If any of your parameters only has a finite set of possible values, and you don't want users to be able to enter their own arbitrary values, you can enable dynamic options for that parameter.

This will create a method called provide options that lets you specify what those possible values are as the intent runs, and Shortcuts will ask the user to pick from one of the values. After the parameters are resolved individually, you can optionally also implement the confirm method, which is where you should make sure everything looks good, and you should be able to handle the intent and throw an error if there's a problem. If, for example, a network connection is required, here is where you should check to make sure you can actually reach the network.

Finally, the handle method is where you actually do what the intent is telling you to do.

The handle method will create the task in the app and return success. After the action creates the task, it should provide the task as output so later actions can use attributes such as the sharing URL. Back in the intent editor, I'll go to the response section for the intent. In here, I'll add a property for the task that was created.

I'll select the task type that I made before. I'll select that property as the output of the intent, to make it available to Shortcuts.

And now, back in the code, the response will have a task property where I can assign the task object.

Once this is done, your intent should appear as an action in the Shortcuts app. So, be sure to spend some time testing it and trying all the ways people could use it. To begin testing, I'll open the Shortcuts app again and look at the Create Task action.

I'll fill in a name for the task and a date-- "Tomorrow at 3:00 p.m." When I hit the run button, the task gets created successfully. However, if I change the date to "Yesterday at 3:00 p.m."...

It'll show the error message, just as we expected. So that's it for building an action in Shortcuts.

Finally, today I'll go over some considerations that you should keep in mind when developing for Shortcuts on the Mac.

I'm going to cover four different types of apps including apps that are built with Mac Catalyst, that work with files, that deploy to both iOS and Mac, and apps and tools that need to run Shortcuts.

First, if you're using Mac Catalyst to bring your iOS app to the Mac, here's a few things you need to know. In macOS Monterey, your apps can now use the same Intents APIs if it's built with Mac Catalyst. If you're building a new app, everything should work the same as it does on iOS.

However, if your app is already available on Mac, and you integrated with the Intents framework on iOS, it's likely that you have compiled out your Intents integration in the process of coming to Mac. So, make sure to audit your code to re-enable this functionality when running on macOS Monterey.

Another type of app I'd like to highlight is a document-based app. In the demo before, our task management app operates on tasks which exist entirely within the app. However, many other apps operate on documents that exist as files on disk. In iOS 15 and macOS Monterey, file parameters for intents allow users to select specific files and pass them into your app's actions. If your app deals primarily with file-based documents rather than a database, consider building a suite of actions that operate on files. For example, a spreadsheet app can create an action to open a document or to add data to a row of a specific file.

Another really cool example of how third-party Shortcuts can work with files is shown in this session from Sound Analysis.

If you are developing an app that exists on both iOS and Mac, in order for your actions to work on both platforms, you should deploy the same intents in both copies of your app. This will allow people to build a shortcut on one platform and have it work the same way on the other. To do this, you should compile the same exact intent definition to both apps, and make sure the intents share the same name and parameters.

Sometimes, your apps may have different bundle identifiers across platforms, and this is okay. Shortcuts will handle this for you, but please keep in mind that the intents with the same name will only be shared among apps deployed via the same Apple Developer team.

Also, if you ever need to upgrade users from one version of your app to another, on iOS 15, as long as the two apps are from the same developer and use the same intent name, your app's Shortcuts will automatically transfer from one to the other. Finally, if you'd like to run Shortcuts from your app or command-line tool, there are two methods to consider.

First, Shortcuts exposes a scripting interface which lets Mac apps and AppleScripts list and run Shortcuts. Additionally, there's a Shortcuts command-line tool which lets you list and run Shortcuts in your Shell Scripts or command-line tools, as well.

If you develop an app or a script that would benefit from the ability to run Shortcuts, you should use the Scripting interface. By communicating with the "Shortcuts Events" process, your app can get a list of shortcuts that the user has set up, as well as start running one.

In AppleScript, you can accomplish this by telling the "Shortcuts Events" process to run a shortcut by name.

Using the Scripting Bridge framework, you can ask the Shortcuts Events process to run a shortcut directly from your Swift or Objective-C apps. For sandbox apps, you'll need to add an entitlement called "com.apple.security.scripting targets." In order to access the list of shortcuts and run them, you'll need to add the "com.apple.shortcuts.run" target. Finally, macOS Monterey also includes a command-line tool that can list shortcuts and run them by name. If you have command-line tools or scripts, they can integrate with Shortcuts via this interface. So, to wrap up, Shortcuts is now available on the Mac, and no matter what type of app you have, you should participate in the Shortcuts ecosystem. By adding actions for your app, you can multiply what people can do with it.

Shortcuts lets people be creative with your apps. You might be delighted to find out what sorts of Shortcuts people build with your actions. [percussive music]

Leave a Comment