← 所有文章

iOS 27 的 App Intents:背景執行、跨裝置同步與 Spotlight

App Intents 隨 iOS 16 推出,是 Apple 為 Shortcuts、Siri 與 Spotlight 打造的型別化、結構化動作API;iOS 17 將它延伸到由 App Intents 驅動的小工具;iOS 18 讓它成為 Apple Intelligence 動作面的契約;iOS 26 又把它推進到 Visual Intelligence 與互動式片段。到了 iOS 27,這個賭注的形狀再次改變,而且這次的改變是機制層面的,而非表面妝點:一個 intent 現在可以執行超過 30 秒的背景時限、一個 entity 可以攜帶能跨越使用者各裝置而存續的身分,而一個 query 可以在系統提出要求時修復自己的 Spotlight 索引。iOS 27 增加的是能力,不是糖衣。1

過去每一次發行,拓寬的都是能呼叫您的 intent。iOS 27 拓寬的則是您的 intent 一旦被呼叫後能做什麼。一個處理數千筆記錄的同步 intent,過去得跟 30 秒倒數計時器賽跑而落敗;如今它能向系統要求更多執行空間,並在工作的同時回報進度。一個在 iPhone 上代表某物、在 Mac 上卻代表另一物的 entity,如今在兩者上都解析到同一個物件。本文將對照 Apple 的文件逐一檢視 iOS 27 的這片新天地,並沿用本系列其餘文章一貫的視角:一個已經出貨 App Intents 的 app,要取得每項新能力得補上什麼。

重點摘要

  • LongRunningIntent 將 intent 的背景執行時間延伸到系統 30 秒限制之外。您把工作包進 performBackgroundTask(options:operation:),並傳入 LongRunningTaskOptions;該協定精煉自 ProgressReportingIntent,因此回報進度是必要條件,而非選項。Live Activities 會自動呈現該進度。234
  • SyncableEntity 宣告某個 AppEntity 攜帶一個跨使用者各裝置一致的識別碼,讓系統能在 iPhone、Mac 與 Watch 上指向同一個物件(Siri 用它把對話從一台裝置交接到另一台)。5
  • IndexedEntityQueryEntityQuery 加上 Spotlight 重新索引支援,因此當系統標記出您 app 索引的問題時,它能要求您的 query 重新捐獻受影響的 entity。6
  • AppUnionValueAppUnionValueCasesProviding(由 @UnionValue 巨集產生)讓單一參數接受數種不同的 entity 型別,並具備妥當的選擇器 UI 與參數摘要。78
  • OwnershipProvidingEntityEntityOwnershipEntityCollection 涵蓋了具所有權意識的確認與批次效率;RunSystemShortcutIntentIntentExecutionTargets 則涵蓋了由小工具啟動的系統動作,以及由哪個行程執行 intent。910111213

30 秒之牆:LongRunningIntent

背景執行限制一直是 App Intent 能力的隱形天花板。當系統在背景執行某個 intent(使用者請 Siri 同步,接著鎖定手機放進口袋)時,傳統上大約只給 30 秒完成。2 對記錄喝了一杯水而言,這很充裕。但對同步一整個資料庫、執行裝置端推論,或處理一個大型檔案而言,30 秒形同一把鍘刀:系統在寫到一半時就終結了任務,使用者拿到的是個只完成一半的結果。

iOS 27 引入 LongRunningIntent,一個 intent 採用後即可向系統要求延長背景時段的協定。2 Apple 在文件中直接點名了適用情境:檔案操作、資料同步、機器學習推論,以及對足夠大的資料集進行的資料處理。光是宣告本身,就在您寫下第一行程式碼之前告訴了您最重要的約束:

protocol LongRunningIntent : ProgressReportingIntent

LongRunningIntent 精煉自 ProgressReportingIntent2 你無法在不一併回報進度的前提下採用這個長時間執行協定,這是設計使然。延長的執行時間是系統有條件授予的特權,而條件就是你得持續告訴它你進行到哪了。一旦停止回報,系統就可以撤回延長並提早結束任務。3

工作放進 performBackgroundTask(options:operation:) 之中:

@discardableResult
func performBackgroundTask<T>(
    options: LongRunningTaskOptions = [],
    operation: @escaping () async throws -> T
) async throws -> T

您從 intent 的 perform() 主體呼叫此方法,並把昂貴的程式碼放進 operation 閉包。在會施加限制的平台上,此方法會自動把您的執行時間延伸到標準 30 秒限制之外;您不必自己啟動另一個背景任務,也不必管理 UIBackgroundTaskIdentifier3 一個資料庫同步 intent 看起來是這樣:

import AppIntents

struct SyncLibraryIntent: LongRunningIntent {
    static var title: LocalizedStringResource = "Sync Library"

    func perform() async throws -> some IntentResult {
        try await performBackgroundTask(options: []) {
            let records = try await server.fetchPendingRecords()
            for (offset, record) in records.enumerated() {
                try await store.apply(record)
                progress.completedUnitCount = Int64(offset + 1)
                progress.totalUnitCount = Int64(records.count)
            }
            return ()
        }
        return .result()
    }
}

有兩件事值得說明,因為教學文章往往略過它們。

progress 屬性是契約,不是遙測資料。 Apple 講得很明白:在 operation 執行期間,要定期更新來自 ProgressReportingIntent 一致性的 Progress,若不這麼做,系統可以取消執行時間的延長並提早結束任務。3 在一般 intent 上回報進度是錦上添花。在 LongRunningIntent 上,它是讓延長持續存活的心跳。

LongRunningTaskOptions 宣告資源需求。 這個選項值(一個 OptionSet 風格、預設為 [] 的結構)告訴系統此任務有哪些額外資源需求,系統會把這納入它授予的執行時間考量。4 空集合是常見情形。當工作需要超過預設配置時,才需要動用明確的選項。

突破 30 秒之外還有額外的好處:Live Activities 會免費呈現進度。文件指出,Live Activities 會運用它從 performBackgroundTask 自動收到的資訊來顯示 intent 任務的進度,並從您程式碼回報的值繪出標題、副標題與進度條。3 一個由語音啟動的長時間同步,會以即時進度條的形式出現在鎖定畫面上,而您完全不必為它打造任何一個 Live Activity 視圖。intent 負責回報,系統負責呈現。

Watch on Apple Developer ↗
Apple 示範一個照片上傳 intent 透過 LongRunningIntent 撐過 30 秒限制,並在 Live Activity 上附帶一個停止按鈕,讓使用者隨時都能取消。

在第 345 場議程中,Apple 針對一個真實的失敗案例示範 LongRunningIntent——一個老是在 30 秒視窗內陣亡的照片上傳——並展示系統如何管理背景任務的生命週期,同時以 Live Activity 的形式浮現進度與一個取消控制項。14

一致的身分:SyncableEntity

AppEntity 有一個 id。在單一裝置上,這個識別碼只需在 app 範圍內唯一即可。麻煩從使用者擁有不只一台裝置那一刻開始——而在 Apple 的生態系裡,這是常態。使用者在 iPhone 上與 Siri 討論的「Project Atlas」,當他在 Mac 上接續對話時,必須能被辨認為同一個「Project Atlas」。如果 iPhone 的本地識別碼與 Mac 的不同,系統手上就是兩個毫不相干的物件,無從連結。

SyncableEntity 是 iOS 27 的解答:5

protocol SyncableEntity : AppEntity

採用它,即宣告您 entity 的識別碼在各裝置間是相同的。這個協定的存在,告訴系統它能從一台裝置一致地指向您的 entity 到另一台裝置。Apple 給出了具體的好處:Siri 運用這項能力把一段對話從一台裝置轉移到另一台。5

採用的成本完全取決於您的識別碼從何而來。如果您的 entity 本來就使用一個穩定的跨裝置識別碼(一個伺服器發放的 UUID、一個 iCloud 記錄名稱),那麼採用 SyncableEntity 不需做其他任何更動,因為您早已儲存的值,正是系統所需要的值。5

import AppIntents

struct ProjectEntity: SyncableEntity {
    static var typeDisplayRepresentation: TypeDisplayRepresentation = "Project"
    static var defaultQuery = ProjectQuery()

    // A UUID issued by the backend and identical on every device.
    var id: UUID

    var displayRepresentation: DisplayRepresentation {
        DisplayRepresentation(title: "\(name)")
    }

    @Property(title: "Name") var name: String
}

陷阱在於那種會在每台裝置上各鑄造一個全新本地識別碼的 app(一個自動遞增的列 ID、一個每次安裝各自的 UUID)。那些識別碼在本地唯一,跨裝置卻毫無意義。Apple 對這種情形的建議是:採用此協定,並把您的身分繫於那個實際上穩定的值,好讓系統有個耐久之物可以錨定。5 同步一直是各團隊用自家 iCloud 管線親手反覆解決的難題。SyncableEntity 把跨裝置身分的宣告搬進了框架之中,讓 Siri 與系統其餘部分能據此行動。

自我修復的搜尋:IndexedEntityQuery

iOS 16 讓您把 IndexedEntity 實例捐獻給 Spotlight,使個別 entity 變得可搜尋。缺口在於修復。索引會漂移、會損毀,或在一次遷移之後落後,而在 iOS 27 之前,系統唯一的補救之道就是仰賴您 app 的 CSSearchableIndex 委派物件或其 CSImportExtension

IndexedEntityQuery 透過讓系統要求您的query來重新索引,補上了這道缺口:6

protocol IndexedEntityQuery : EntityQuery where Self.Entity : IndexedEntity

where 子句即是前提條件:該 query 的 entity 必須遵循 IndexedEntity,因為重新索引唯有對那些您本來就捐獻給 Spotlight 的 entity 才有意義。6 當系統碰上某個 app 索引的問題時,如果您的 query 型別採用了這個協定,它就會呼叫該協定的方法;如果您的 query 沒有採用,Spotlight 就會繼續要求您的 CSSearchableIndex 物件(或您的 CSImportExtension,前提是您是透過將 entity 與該型別關聯來捐獻的)代為完成這項工作。6 您實作這些方法以取回所要求的 entity,並透過您偏好的可搜尋索引再次捐獻它們。

import AppIntents
import CoreSpotlight

struct PhotoQuery: IndexedEntityQuery {
    func entities(for identifiers: [Photo.ID]) async throws -> [Photo] {
        try await library.photos(matching: identifiers)
    }

    func suggestedEntities() async throws -> [Photo] {
        try await library.recentPhotos(limit: 20)
    }

    // Called by the system during reindexing. Fetch the requested
    // entities and donate them again to Spotlight.
    func entities(matching string: String) async throws -> [Photo] {
        try await library.photos(matchingText: string)
    }
}

其價值在於營運層面。一個把 IndexedEntityQuery 做對的 app,會參與 Spotlight 的復原迴圈:系統察覺索引出錯,app 便按需供應新鮮資料,而不是讓使用者悄悄地流失搜尋結果,直到下一次完整重新捐獻為止。本系列的App Intents 基礎篇涵蓋了用以讓條目可搜尋的赤裸 IndexedEntity 揭露;IndexedEntityQuery 則是疊在其上的維護層。

一個參數,數種型別:AppUnionValue

不少真實的 intent,其某個參數合理地會是數種型別之一。「分享這個」,而「這個」是一張照片、一份文件,或一個連結。iOS 27 之前的權宜之計都很醜陋:每種型別各寫一個 intent,或一個字串判別子外加選擇器 UI 無法乾淨呈現的選用參數。

iOS 27 為型別化的聯集參數加入了 AppUnionValue7

protocol AppUnionValue : TypeDisplayRepresentable

一個遵循此協定的聯集值,能作為帶有豐富中繼資料的 Shortcuts 參數運作,因此系統能在各成員型別之間呈現恰當的選擇器與合宜的參數摘要。7 您不必親手撰寫這份一致性。@UnionValue 巨集會產生它,而同一個巨集還會產生一個遵循 AppUnionValueCasesProviding 的巢狀 Cases 列舉:78

protocol AppUnionValueCasesProviding : AppEnum

AppUnionValueCasesProviding 由巨集所發出的 Cases 列舉自動遵循。8 它把這個 cases 列舉橋接回聯集值型別,並透過其 AppEnum 一致性繼承中繼資料,這正是讓每個 case 在選擇器中得到其顯示名稱的來源。8 實務上,您撰寫這個聯集並為它加上註解:

import AppIntents

@UnionValue
enum ShareTarget {
    case photo(PhotoEntity)
    case document(DocumentEntity)
    case link(URL)
}

struct ShareIntent: AppIntent {
    static var title: LocalizedStringResource = "Share Item"

    @Parameter(title: "Item")
    var target: ShareTarget

    func perform() async throws -> some IntentResult {
        // Switch over the concrete case and act accordingly.
        return .result()
    }
}

@UnionValue 巨集會處理 AppUnionValueAppUnionValueCasesProviding 兩份一致性;若您想要超出預設的自訂中繼資料,可在一個擴充中實作協定的要求。7 一個參數、三種有效型別、一個懂得如何把三者全都呈現出來的選擇器。

所有權與效率

兩件各自獨立的 iOS 27 議題共用這一節,因為兩者都在防止系統對您的資料草率行事:具所有權意識的確認,以及批次操作的效率。

確認破壞性動作:OwnershipProvidingEntity

當您的 app 把 entity 傳入 intent 並從結果中回傳它們時,Apple Intelligence、Siri 與自訂捷徑都能跨 app 對那些 entity 行動。對於破壞性或敏感的動作(刪除一個 entity、更新一個共享的 entity),您會希望有一個帶著正確情境的確認。OwnershipProvidingEntity 提供了它:9

protocol OwnershipProvidingEntity : AppEntity

讓您的 entity 遵循它,當某個 intent 對共享或可公開存取的 entity 行動時,系統便會在對話框中帶著恰當情境提示確認。9 所有權狀態本身是一個 EntityOwnership 值,一個基於旗標的結構,您可在其中指定單一狀態,或用 OptionSet 組合數個狀態:10

import AppIntents

struct AlbumEntity: OwnershipProvidingEntity {
    static var typeDisplayRepresentation: TypeDisplayRepresentation = "Album"
    static var defaultQuery = AlbumQuery()

    var id: UUID
    var isSharedWithFamily: Bool
    var isPublished: Bool

    var displayRepresentation: DisplayRepresentation {
        DisplayRepresentation(title: "\(name)")
    }

    @Property(title: "Name") var name: String

    // Reflect how the user has shared this album so the system can
    // calibrate its confirmation dialog.
    var ownership: EntityOwnership {
        var state: EntityOwnership = []
        if isSharedWithFamily || isPublished {
            state = .shared
        }
        return state
    }
}

這套機制對擁有共享內容的 app 最為要緊:一個您發布或與家人共享的相簿,理應產生比私人相簿更為謹慎的確認,而 OwnershipProvidingEntity 正是 entity 告訴系統孰為孰的方式。9

不犧牲記憶體的批次處理:EntityCollection

解析 entity 並非免費。當一個 intent 把數百個 entity 作為參數,在參數解析期間強迫系統把每個識別碼都解析成完整實例,可能在一個糟糕的時機耗掉可觀的時間與記憶體。EntityCollection 是解法:11

struct EntityCollection<Entity> where Entity : AppEntity

這個集合一開始只為每個 entity 儲存識別碼,並在您日後需要時提供取回完整實例的選項。11 當您持有許多識別碼時,把它當作變數型別來用;當一個 intent 要對一個大集合進行操作時,把它當作參數型別來用:

import AppIntents

struct DisableNotificationsIntent: AppIntent {
    static var title: LocalizedStringResource = "Disable Notifications"

    // Hundreds of conversations resolve lazily, not all at once.
    @Parameter(title: "Conversations")
    var conversations: EntityCollection<ConversationEntity>

    func perform() async throws -> some IntentResult {
        return .result()
    }
}

對一個持有數百個 entity 的參數而言,略過逐一識別碼的解析,恰好在使用者正等著動作開始的那一刻省下時間與記憶體。11

intent 在何處執行:RunSystemShortcutIntentIntentExecutionTargets

兩項較小的 iOS 27 新增功能補完了這片天地。RunSystemShortcutIntent 是一個僅供小工具使用的 intent,用以從小工具按鈕啟動另一個 app,或執行一個 App Shortcut、自訂捷徑或系統動作:12

struct RunSystemShortcutIntent

您只用它來以系統捷徑初始化器初始化一個 Button,並把該按鈕放進小工具;在那個情境之外它毫無用處。12 當使用者設定該小工具時,他們選擇按鈕的動作,而 intent 供應系統在設定 UI 中所需的中繼資料。它並不交給您的小工具存取某捷徑的動作、參數或實作。如果所選的捷徑需要提示輸入,系統可能會開啟 Shortcuts app 來執行它。12

IntentExecutionTargets 回答了一個問題——這問題在您透過 Swift 套件或框架,於您的 app、小工具擴充與 App Intents 擴充之間共享 intent 與 entity 後就會浮現:由哪個行程執行這個 intent?13

struct IntentExecutionTargets

預設情況下,系統會用任何可用的目標來執行 intent 或 entity query。13 您用 IntentExecutionTargets 來約束這一點。Apple 的範例是瀏覽器:新增一個書籤可以在 app 不可見時發生,所以 App Intents 擴充就行;但開啟一個新分頁唯有在 app 可見時才說得通,這需要 app 自己的行程。13 您宣告有效的目標,系統便尊重這個約束。

採用路徑

一個已經出貨 App Intents 的 app,可以漸進式地加上 iOS 27 的各項能力;沒有任何一項會重寫核心模型。

  1. 找出您最慢的 intent。 任何在做檔案 I/O、同步、裝置端推論或大型資料處理的 intent,都是 LongRunningIntent 的候選。採用此協定,把工作移進 performBackgroundTask(options:operation:),並全程回報 progress。您就能得到突破 30 秒的執行時間與免費的 Live Activities 進度。23
  2. 稽核您的 entity 識別碼。 如果它們本來就跨裝置穩定(伺服器 UUID、iCloud 記錄名稱),就讓相關 entity 遵循 SyncableEntity 並出貨。如果它們是逐裝置的,先修好身分,再讓它們遵循。5
  3. 為那些 entity 屬於 IndexedEntity 的 query 加上 IndexedEntityQuery 它純粹是增添式的:這些方法唯有在系統需要重新索引時才會被呼叫,而您的搜尋結果會在索引漂移之中維持正確。6
  4. @UnionValue 收攏多型別參數。 任何您曾用分立的 intent 或一個判別子字串假冒聯集之處,這個巨集都給您一個乾淨的參數。7
  5. OwnershipProvidingEntity 標記共享的 entity,並把大集合參數改為 EntityCollection 前者改善確認的安全性,後者改善解析的效能。911

常見問答

一個 LongRunningIntent 在背景能執行多久?

Apple 記載的是它所抬升的下限,而非一個固定的上限。系統傳統上給一個背景任務大約 30 秒完成,而 LongRunningIntent(透過 performBackgroundTask(options:operation:))在會施加限制的平台上會自動把那個視窗延伸到標準限制之外。23 這個延長是有條件的:您得持續更新來自 ProgressReportingIntent 一致性的 Progress,而若您停止,系統就可以取消延長並提早結束您的任務。3 把回報進度當作換取額外執行時間的代價。

我必須回報進度才能使用 LongRunningIntent 嗎?

是的。LongRunningIntent 宣告為 protocol LongRunningIntent : ProgressReportingIntent,因此採用它就需要 ProgressReportingIntent 一致性及其 Progress2 除了滿足編譯器之外,定期的進度更新會讓背景執行時間的延長持續存活,並餵養 Live Activities 從 performBackgroundTask 自動呈現的標題、副標題與進度條。3

SyncableEntity 在執行期實際改變了什麼?

它宣告您 entity 的識別碼在使用者各裝置間相同,讓系統能把該物件處理成處處皆同的單一 entity,而非各裝置分立的物件。5 Apple 點名的具體能力:Siri 能把關於該 entity 的一段對話從一台裝置轉移到另一台。如果您的識別碼本來就跨裝置穩定,您採用此協定無須做其他更動;如果它們是逐裝置的,先把身分重新錨定到一個穩定的值上。5

系統何時會呼叫 IndexedEntityQuery

當它碰上您 app 的 Spotlight 索引問題,且您的 query 型別採用了 IndexedEntityQuery(其 entity 遵循 IndexedEntity)時。6 系統會呼叫該協定的方法,讓您取回受影響的 entity 並再次捐獻給 Spotlight。如果您的 query 沒有採用此協定,Spotlight 會退回去要求您的 CSSearchableIndex 物件,或您的 CSImportExtension(前提是您是透過該型別捐獻的)。6

為何要用 EntityCollection 而不用一個普通的 entity 陣列?

EntityCollection<Entity> 一開始只儲存每個 entity 的識別碼,並在需要時才取回完整實例。11 作為一個 intent 參數,它阻止系統在參數解析期間強迫每個識別碼都解析成完整實例,這對一個持有數百個 entity 的參數而言,會在一個可能很關鍵的時刻省下時間與記憶體。11 一個普通的 [Entity] 陣列則會急切地把一切都解析出來。

RunSystemShortcutIntent 能在小工具之外使用嗎?

不能。它的存在純粹是為了以系統捷徑初始化器初始化一個 Button,以便放進小工具,在其他情境中它不提供任何功能。12 它為小工具的設定 UI 浮現中繼資料並代表使用者所選的動作;它並不交給您的小工具或 app 存取底層捷徑的動作、參數或實作。12

完整的 Apple 生態系系列:型別化的 App IntentsiOS 26 的新增功能;對照 MCP 工具的路由問題Foundation Models;全新的 Foundation Models 工具呼叫控制執行期與工具LLM之別三種面單一真實來源模式與 app 並存的 MCP 伺服器Live ActivitieswatchOS 執行期SwiftUI 內部機制SwiftData 結構紀律Liquid Glass 模式多平台出貨平台矩陣Vision 框架@Observable 內部機制作為平台的無障礙。系列中樞在 Apple 生態系系列。若想了解更廣的 iOS 結合 AI 代理脈絡,請參閱 iOS 代理開發指南

參考資料


  1. Apple Developer Documentation:App Intents。涵蓋 AppIntentAppEntity、query、參數,以及 iOS 27 新增功能的框架參考。 

  2. Apple Developer Documentation:LongRunningIntent(iOS 27.0 beta)。「一個您用以延長執行長時間任務之 app intent 背景執行時間的介面。」宣告為 protocol LongRunningIntent : ProgressReportingIntent;系統傳統上給背景任務最多 30 秒。 

  3. Apple Developer Documentation:performBackgroundTask(options:operation:)(iOS 27.0 beta)。在背景以延長的時間執行 operation,突破標準 30 秒限制;需要定期的進度更新,否則系統可以取消延長;Live Activities 會自動呈現進度。 

  4. Apple Developer Documentation:LongRunningTaskOptions(iOS 27.0 beta)。用以設定長時間任務的選項;宣告額外的資源需求,傳入 performBackgroundTask(options:operation:)。 

  5. Apple Developer Documentation:SyncableEntity(iOS 27.0 beta)。「一個指出您 entity 擁有跨裝置一致識別碼的介面。」宣告為 protocol SyncableEntity : AppEntity;Siri 用它在裝置間轉移對話。 

  6. Apple Developer Documentation:IndexedEntityQuery(iOS 27.0 beta)。「一個為您 entity query 加上 Spotlight 重新索引支援的介面。」宣告為 protocol IndexedEntityQuery : EntityQuery where Self.Entity : IndexedEntity。 

  7. Apple Developer Documentation:AppUnionValue(iOS 27.0 beta)。「一個為聯集值提供名義型別身分與中繼資料的協定。」宣告為 protocol AppUnionValue : TypeDisplayRepresentable;一致性由 @UnionValue 巨集產生。 

  8. Apple Developer Documentation:AppUnionValueCasesProviding(iOS 27.0 beta)。宣告為 protocol AppUnionValueCasesProviding : AppEnum;由 @UnionValue 巨集產生的 Cases 列舉自動遵循。 

  9. Apple Developer Documentation:OwnershipProvidingEntity(iOS 27.0 beta)。「一個為 app entity 向系統提供所有權與共享情境的型別。」宣告為 protocol OwnershipProvidingEntity : AppEntity;對共享或可公開存取的 entity 提示確認。 

  10. Apple Developer Documentation:EntityOwnership(iOS 27.0 beta)。「一個代表 app entity 所有權與共享特性的型別。」宣告為 struct EntityOwnership;基於旗標,可用 OptionSet 組合。 

  11. Apple Developer Documentation:EntityCollection(iOS 27.0 beta)。「一個 entity 識別碼的陣列,您用它來改善涉及大量 entity 之操作的效率。」宣告為 struct EntityCollection<Entity> where Entity : AppEntity;一開始儲存識別碼,並惰性解析完整實例。 

  12. Apple Developer Documentation:RunSystemShortcutIntent(iOS 27.0 beta)。「一個您在小工具中用以開啟另一個 app,或執行 App Shortcut、自訂捷徑或系統動作的 app intent。」宣告為 struct RunSystemShortcutIntent;僅可用於初始化一個小工具 Button。 

  13. Apple Developer Documentation:IntentExecutionTargets(iOS 27.0 beta)。「一組描述由哪個行程執行 intent 或 entity query 的選項。」宣告為 struct IntentExecutionTargets;把執行約束到 app、App Intents 擴充,或任何可用的目標。 

  14. Apple,WWDC26 第 345 場議程,「Discover new capabilities in the App Intents framework.」developer.apple.com/videos/play/wwdc2026/345。Apple 示範 LongRunningIntent 化解一個老是在 30 秒限制內失敗的照片上傳 intent,由框架管理背景任務的生命週期,並以 Live Activity 的形式浮現進度與一個停止控制項。 

相關文章

iOS 27 中的 Foundation Models:工具呼叫控制

iOS 27 新增 GenerationOptions.ToolCallingMode,用以引導裝置端模型如何使用工具,並內建兩個 Vision 工具:OCRTool 與 BarcodeReaderTool。

4 分鐘閱讀

iOS 26中的App Intents 2.0:視覺智慧、互動式片段與延遲屬性

iOS 26擴展了App Intents,加入用於視覺智慧的IntentValueQuery、用於非同步值的@DeferredProperty、互動式片段以及實體檢視註解。

2 分鐘閱讀

The Robots Are Taking Exams in My Search Console

First-party GSC data: 91% of 3.8M impressions fail a human-query filter. Exam questions, pasted errors, and agent sweeps…

10 分鐘閱讀