WWDC Quick Look 💓 By SwiftGGTeam
Meet Shortcuts for macOS

Meet Shortcuts for macOS

元の動画を見る

ハイライト

Apple は macOS にショートカットを導入し、AppKit および Mac Catalyst アプリが Intents フレームワークを通じてカスタム アクションを提供できるようにします。ユーザーは、ショートカット、メニュー バー、キーボード ショートカット、Spotlight、AppleScript、およびコマンド ラインでこれらの自動化機能を実行できます。

主要内容

Mac ユーザーは常に自動化ツールを使用してきました。 AppleScript はアプリケーションを制御でき、シェル スクリプトはファイルを処理でき、Automator はアクションをワークフローに文字列化できます。

問題は入口が分散していること。 ToDo アプリ、画像編集アプリ、情報アプリに接続したい一般ユーザーは、多くの場合、スクリプト、ファイル形式、アプリケーション イベントについて知る必要があります。開発者は、さまざまな自動化ポータルに対してさまざまな適応を記述する必要もあります。

WWDC 2021 での変更点は、ショートカットが macOS に登場することです。ユーザーが Mac バージョンのショートカットを開くと、iPhone から同期されたショートカットが表示されます。ショートカット エディターも Mac 用に再作成され、Mac 固有のアクションをサポートしました。

開発者にとっての重要な変更点は、Mac アプリが iOS アプリと同じようにアクションを提供できることです。 To Do アプリが「タスクの作成」、「タスクの検索」、「タスクの削除」などの操作を公開すると、ユーザーはそれをメモ、メッセージ、ファイル、または他のアプリに接続して、複数ステップのワークフローを形成できます。

Apple は開発者に対し、古い Mac 自動化システムを放棄するよう求めているわけではありません。ショートカットは AppleScript とシェル スクリプトの実行をサポートしており、ほとんどの Automator ワークフローにインポートすることもできます。既存のスクリプトは引き続き使用でき、新しいアクションを同じワークフローに接続できます。

アプリ関数からコンポーザブルアクションまで

アクションは、小さくて明確な操作であることが好ましい。講演の例は、共同タスク管理アプリです。その中心となるオブジェクトはタスクであり、そのフィールドにはタイトル、期限、共有リンクが含まれます。タスクの周囲に、作成、編集、削除、検索、表示などの動詞を指定できます。

この方法で分割した後、ユーザーは Notes からテキストを選択し、形式を自動的に調整し、期限を入力して、タスクの作成アクションを呼び出すことができます。タスクが作成されると、アクションによって共有リンクが返され、後続の手順でそのリンクを他の人に送信できます。

iOS から Mac まで同じインテント セット

macOS Monterey では、Mac Catalyst アプリで同じ Intents API を使用できるようになります。 Mac バージョンでインテント統合をコンパイルした既存の iOS アプリがある場合は、コードを再チェックして、macOS Monterey でこの機能を有効にする必要があります。

アプリが iOS と Mac 向けに同時にリリースされる場合、Apple は両方のエンドで同じインテント定義ファイルをコンパイルし、インテント名とパラメータの一貫性を保つことを推奨します。あるプラットフォームでユーザーが作成したショートカットは、別のプラットフォームでも引き続き実行できます。

詳細

インテントの定義: アクションを機能設計として扱う

(09:56) ショートカット アクションを実装する最初のステップは、Xcode でインテント定義ファイルを作成することです。このファイルは App ターゲットでコンパイルされ、Xcode はそれに基づいて Swift タイプとプロトコルを生成します。

講義の Create Task インテントには 2 つの入力パラメータがあります。titleそしてdueDate。また、Taskタイプ(システムによって自動的に提供されるものを含む)identifierdisplayString、およびアプリ自体によって追加されたものdueDateそしてURL

// Intent definition 生成的类型会在构建后出现在代码中
let intent = CreateTaskIntent()
intent.title = "Review pull request"
intent.dueDate = DateComponents(calendar: .current, year: 2021, month: 6, day: 8, hour: 15)

キーポイント:

  • CreateTaskIntentから.intentdefinitionファイルの場合、手書きの型宣言は必要ありません。
  • titleタスクの作成に必要なテキスト パラメータです。
  • dueDate講義の締め切りに選択されたパラメータ タイプに対応する Date Components タイプを使用します。
  • プロジェクトをビルドした後、Xcode はTaskタイプとCreateTaskIntentタイプ。

(13:17) ショートカット アプリ領域でも、入力パラメーターと概要を構成する必要があります。スピーチ中にtitle入力パラメータに設定します。このようにして、ユーザーがテキストの前の段落をタスクの作成アクションに接続すると、タイトルが自動的に入力されます。

Summary: Create task with due date
Input parameter: title
Required parameters: title, dueDate

キーポイント:

  • Summaryショートカット エディターでユーザーに表示されるアクションの概要です。
  • Input parameter前のステップの出力に対してデフォルトでどのパラメータが入力されるかを決定します。
  • 必要なパラメータを概要に配置すると、ユーザーはアクションを展開せずにキー入力を確認できます。

インテントの配布: macOS がアクションをアプリに引き渡せるようにします。

(15:15) Mac アプリがインテントを処理するには 2 つの方法があります。 1 つ目はアプリ内で処理し、インテントはアプリのデリゲートに送信されます。 2 つ目は、Intents 拡張機能を作成し、軽量の独立したプロセスを使用してそれを処理することです。

Apple は、ほとんどのアプリがアプリ内インテントの処理から始めることを推奨しています。このようにして、アクションはアプリの状態を直接変更できます。アプリ全体を起動するのにコストがかかりすぎる場合にのみ、拡張機能を検討してください。

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? {
        if intent is CreateTaskIntent {
            return IntentHandler()
        }
        return nil
    }
}

キーポイント:

  • import IntentsSiriKit が配置されている Intents フレームワークを紹介します。
  • @NSApplicationDelegateAdaptorバンドルAppDelegateSwiftUI アプリのライフサイクルにアクセスします。
  • application(_:handlerFor:)macOS モントレーでははいNSApplicationDelegate利用可能なインテント配布ポータル。
  • intent is CreateTaskIntent現在のインテントがタスクの作成アクションによってトリガーされるかどうかを判断します。
  • IntentHandler()インテントの処理を担当するオブジェクトです。
  • return nilアプリが他のインテントを処理しないことを示します。

パラメータの解析: 実行前にユーザーに入力を完了させる必要があります

(18:32) インテント ハンドラーは、Xcode によって生成されたプロトコルに準拠する必要があります。タスク作成インテントが対応するCreateTaskIntentHandling。プロトコルには、解決、オプションの提供、確認、および処理の 4 つのメソッドが含まれます。

resolve単一のパラメータを確認するために使用されます。 Create Task にはタイトルと期限という 2 つの必須パラメータがあるため、2 つの解決メソッドが生成されます。

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))
    }
}

キーポイント:

  • IntentHandler従うCreateTaskIntentHandling、これはインテント定義によって生成されたプロトコルです。
  • resolveTitle診るintent.titleそれが存在するかどうか、空ではないかどうか。
  • .needsValue()ユーザーにこの値を要求する必要があることをシステムに伝えます。
  • .success(with: title)title パラメータがチェックに合格したことを示します。
  • resolveDueDate期限が存在するかどうかを確認してください。
  • CreateTaskDueDateResolutionResultDeadline パラメータに対応する解析結果のタイプです。

カスタム検証: 過去の日付を拒否する

(19:37) トーク内のアプリでは、タスクの期限が将来である必要があります。開発者はまずインテント定義ファイルにカスタム エラーを追加します。invalidDate、その後、resolve メソッドで unsupported を返します。

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))
    }

キーポイント:

  • intent.dueDateユーザーが入力した日付コンポーネントを取得します。
  • Calendar.current.date(from:)日付コンポーネントを比較可能なものに変換Date
  • guard失敗時の返品.needsValue()、ユーザーが日付を追加できるようにします。
  • dueDate < Date()日付が現在時刻より前かどうかを判断します。
  • .unsupported(forReason: .invalidDate)インテント定義で定義されたエラー理由を返します。
  • .success(with: dateComponents)日付を使用してアクションを実行できることを示します。

アクションの実行: タスクを作成し、出力を返します。

20:34handleメソッドは実際のビジネス ロジックを実行します。スピーチでは、タイトルと期限を読み取り、タスクを作成し、応答オブジェクトを構築し、作成したタスクを応答に組み込みます。

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)
    }
}

キーポイント:

  • handleパラメータの解析が完了した後に呼び出されます。
  • intent.title!そしてintent.dueDate!解決を通過したパラメータを読み取ります。
  • createTask(name:due:)アプリ内でタスクを作成するビジネス ロジックを表します。
  • CreateTaskIntentResponse(code: .success, userActivity: nil)成功した応答を構築します。
  • response.task = task新しく作成したタスクをアクションとして出力します。
  • completion(response)結果をショートカットに返すと、後続のアクションでリンクの共有などのタスクのプロパティを読み取ることができます。

ファイル アプリ: ファイル パラメーターを使用してドキュメントを処理する

(23:24) iOS 15 および macOS Monterey のインテント ファイル パラメーターを使用すると、ユーザーはファイルを選択し、そのファイルをアプリのアクションに渡すことができます。ドキュメントベースのアプリは、ファイルに関するアクションを設計できます。

講演で挙げられた例はスプレッドシート アプリです。ドキュメントを開くアクションを提供したり、ファイルの行にデータを追加するアクションを提供したりできます。サウンド分析セッションでは、サードパーティのショートカットがファイルでどのように機能するかについても説明します。

func resolveDocument(for intent: AddRowIntent, with completion: @escaping (INFileResolutionResult) -> Void) {
    guard let file = intent.document else {
        return completion(.needsValue())
    }
    return completion(.success(with: file))
}

キーポイント:

  • intent.documentショートカットによって渡されるファイルパラメータを表します。
  • INFileResolutionResultファイルパラメータの解析結果を返すために使用されます。
  • .needsValue()ユーザーにファイルを選択するように依頼します。
  • .success(with: file)ファイルを後続の処理ロジックに渡すことができることを示します。
  • このタイプのアクションは、ファイルがディスクに保存されているドキュメントベースのアプリに適しています。

AppleScript からのショートカットの実行

(25:39) ショートカットにより、スクリプト インターフェイスが公開されます。 AppleScript は渡せますShortcuts Eventsプロセスは名前でショートカット コマンドを実行します。

tell application "Shortcuts Events"
	run the shortcut whose name is "Make GIF"
end tell

キーポイント:

  • Shortcuts Eventsショートカットのスクリプトインターフェイスプロセスです。
  • run the shortcut既存のショートカット コマンドをトリガーします。
  • whose name is "Make GIF"ユーザーが作成したショートカット名でターゲットを検索します。
  • 古い AppleScript ワークフローは、この方法で新しいショートカットを呼び出すことができます。

Swift または Objective-C からショートカットを実行する

(25:49) Mac アプリはスクリプト ブリッジを使用して同じものを呼び出すことができますShortcuts Eventsプロセス。サンドボックスアプリも追加する必要がありますcom.apple.security.scripting-targets権利を獲得し、参加するcom.apple.shortcuts.run target。

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)

キーポイント:

  • import ScriptingBridgeScripting Bridge フレームワークの紹介。
  • ShortcutsEvents契約書shortcuts集める。
  • Shortcut契約書nameそしてrun(withInput:)
  • SBApplication(bundleIdentifier: "com.apple.shortcuts.events")ショートカット イベントに接続します。
  • app.shortcutsユーザーの既存のショートカット リストを取得します。
  • shortcuts.object(withName: "Make GIF")指定された名前のショートカット コマンドを検索します。
  • shortcut.run?(withInput: nil)空の入力を渡してショートカットを実行します。

重要ポイント

  • 手順: タスク管理アプリに「選択したテキストからタスクを作成」アクションを追加します。 実行する価値がある理由: スピーチ内の「タスクの作成」アクションは、ショートカットが前のテキストをインテント入力パラメーターに自動的に入力できることを証明しました。 開始方法: インテント定義を作成し、定義しますtitleそしてdueDateパラメータ、入力title実装する入力パラメータとして設定しますCreateTaskIntentHandling解決して対処します。

  • 対処方法: 「指定されたファイルを処理する」アクションをドキュメント アプリに追加します。 実行する価値がある理由: iOS 15 と macOS Monterey はインテント ファイル パラメーターをサポートしており、ユーザーはファイルまたは Finder プロセスからアプリにファイルを渡すことができます。 開始方法: ファイルパラメータをアクションに追加し、ハンドラで使用します。INFileResolutionResultファイルを確認してから、handleファイルを読み取り、新しいファイルを返します。

  • やるべきこと: 画像またはオーディオ アプリ用の一連の構成可能なバッチ処理アクションを提供します。 実行する価値がある理由: ショートカットを使用すると、ファイルの選択、コンテンツの処理、結果の共有など、サードパーティのアクションをシステムのアクションに接続できます。 開始方法: まず、「フィルターの適用」、「ファイルのエクスポート」、「共有リンクの生成」などの 3 つのアトミック操作を選択し、それぞれインテントを構築し、後続のステップで使用できる各応答の出力を定義します。

  • 内容: Mac アプリで「ユーザー指定のショートカットを実行」するためのアクセスを提供します。 実行する価値がある理由: ショートカット提供Shortcuts Eventsスクリプト インターフェイスを使用すると、アプリはユーザーが既に持っているショートカットを一覧表示して実行できます。 始め方: はじめにScriptingBridge、使用SBApplication(bundleIdentifier: "com.apple.shortcuts.events")ショートカット イベントに接続し、名前でショートカットを見つけて呼び出します。run(withInput:)

  • 何をすべきか: iOS アプリのショートカット アクションが Mac を同期的にサポートするようにします。 実行する価値がある理由: macOS Monterey の Mac Catalyst アプリは、同じインテント API セットを使用できるため、ユーザーが iPhone 上で作成したショートカットは Mac でも引き続き使用できます。 開始方法: Mac ターゲットが同じインテント定義をコンパイルするかどうかを確認し、iOS と Mac のバージョンでインテント名とパラメーターが一貫していることを確認します。

関連セッション

コメント

GitHub Issues · utterances