Dunfey · Hotel WWDC as data, est. 1983
Front desk everything
Years
Topics

2021 App Services

WWDC21 · 27 min · App Services

Meet Shortcuts for macOS

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.

Watch at developer.apple.com ↗

Transcript all transcripts

Code shown on screen · 6 snippets

Adding Intent dispatch method in SwiftUI swift · at 17:10 ↗
import SwiftUI
import Intents

@main
struct SouperTaskApp: App {
    @NSApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
    
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}

class AppDelegate: NSObject, NSApplicationDelegate {
    func application(_ application: NSApplication, handlerFor intent: INIntent) -> Any? {

    }
}
Resolve intent swift · at 18:32 ↗
class IntentHandler: NSObject, CreateTaskIntentHandling {
    func resolveTitle(for intent: CreateTaskIntent, with completion: @escaping (INStringResolutionResult) -> Void) {
        guard let title = intent.title, !title.isEmpty else {
            return completion(.needsValue())
        }
        return completion(.success(with: title))
    }
    
    func resolveDueDate(for intent: CreateTaskIntent, with completion: @escaping (CreateTaskDueDateResolutionResult) -> Void) {
        guard let dateComponents = intent.dueDate else {
            return completion(.needsValue())
        }
        return completion(.success(with: dateComponents))
    }

    ...
}
Date range validation in dueDate resolve method swift · at 19:37 ↗
func resolveDueDate(for intent: CreateTaskIntent, with completion: @escaping (CreateTaskDueDateResolutionResult) -> Void) {
        guard
            let dateComponents = intent.dueDate,
            let dueDate = Calendar.current.date(from: dateComponents)
        else {
            return completion(.needsValue())
        }
        if dueDate < Date() {
            return completion(.unsupported(forReason: .invalidDate))
        }
        return completion(.success(with: dateComponents))
    }
Handle intent swift · at 20:40 ↗
class IntentHandler: NSObject, CreateTaskIntentHandling {
    func handle(intent: CreateTaskIntent, completion: @escaping (CreateTaskIntentResponse) -> Void) {
        let title = intent.title!
        let dueDate = intent.dueDate!
        
        let task = createTask(name: title, due: dueDate)
        
        let response = CreateTaskIntentResponse(code: .success, userActivity: nil)
        response.task = task
        completion(response)
    }
}
Running Shortcut from AppleScript markdown · at 25:39 ↗
tell application "Shortcuts Events"
	run the shortcut whose name is "Make GIF"
end tell
Using scripting bridge swift · at 25:49 ↗
import ScriptingBridge

@objc protocol ShortcutsEvents {
    @objc optional var shortcuts: SBElementArray { get }
}
@objc protocol Shortcut {
    @objc optional var name: String { get }
    @objc optional func run(withInput: Any?) -> Any?
}

extension SBApplication: ShortcutsEvents {}
extension SBObject: Shortcut {}

guard 
    let app: ShortcutsEvents = SBApplication(bundleIdentifier: "com.apple.shortcuts.events"),
    let shortcuts = app.shortcuts else {
    print("Couldn't access shortcuts")
    return
}

guard let shortcut = shortcuts.object(withName: "Make GIF") as? Shortcut else {
    print("Shortcut doesn't exist")
    return
}

_ = shortcut.run?(withInput: nil)

Resources