新增 iOS App Extension
本指南將說明如何在 Flutter 應用程式中使用 iOS app extension。
概述
#iOS app extension 允許你將功能擴展到 iOS 應用程式之外。你的應用程式可以作為主畫面小工具(widget)出現,或讓你的應用程式部分功能在其他應用程式中使用。
在以下範例中,當使用者在 iOS 相簿應用程式中選擇要分享的照片時,一個名為 Example App With Extension 的 Flutter 應用程式會顯示在 相簿應用程式的分享選單(share sheet)中:
將 iOS app extension 新增至你的 Flutter 應用程式
#如果你想讓 Flutter 應用程式與 iOS 作業系統整合,可以將 iOS app extension 新增到你的 Flutter 專案。為了讓流程更順暢,下列步驟將示範如何將 Share app extension 新增到一個名為 example_app_with_extension 的新 Flutter 應用程式,但你也可以從既有專案開始。
在終端機中建立一個名為
example_app_with_extension的新 Flutter 專案。flutter create example_app_with_extension在終端機中,開啟
example_app_with_extension專案的 Xcode workspace。cd example_app_with_extension && open ios/Runner.xcworkspace在 Xcode 中,新增一個名為
Share的 app extension,並將其命名為ShareExtension。在 Xcode 功能表列中,選擇 File > New > Target。
新增 Share Extension。
在 Name field(名稱欄位)中輸入 ShareExtension。
點擊 Finish。
在出現的 Activate … Scheme 對話框中, 選擇 Activate。
在 Xcode 中,調整建置流程的順序。
開啟 project navigator (View > Navigators > Project)。
在 project navigator 頂部,選擇 Runner。
在主視窗的 TARGETS 區塊下,選擇 Runner。
開啟 Build Phases 分頁。
將 Embed Foundation Extensions 拖曳到 Run Script 之上。
確認你的 Minimum Deployments iOS 值已正確設定,且在 Runner 與 ShareExtension 中一致
開啟 project navigator (View > Navigators > Project)。
在 project navigator 頂部,選擇 Runner。
在主視窗的 TARGETS 區塊下,選擇 Runner。
在 General 分頁中,檢查 Minimum Deployments 下拉選單的值,需與 ShareExtension > General 分頁中的值相同。
在終端機中執行以下指令,以重新建置你的 iOS 應用程式:
flutter build ios --config-only
當你新增一個 App Extension(應用程式擴充)時,Xcode 會根據你選擇的範本產生範例程式碼。關於這些產生的程式碼以及 WidgetKit 的更多資訊,請參考 Apple 的 App Extension 文件。
測試 iOS App Extension
#在你將 App Extension 新增至 Flutter 專案後,可以使用模擬器或實體裝置進行測試。
如果你要在偵錯模式(debug mode)下測試 extension,必須使用 iOS 模擬器。
以下步驟假設你正在使用
新增 iOS App Extension 中的範例應用程式與 Share extension(分享擴充)。
在 Xcode 中,將 App Extension 新增至你的專案。
在終端機中,使用以下指令來執行你的 iOS 應用程式:
flutter run在模擬器中測試你的 app extension(應用程式擴充功能)。
啟動一個支援 Share extension(分享擴充功能)的應用程式, 例如 Photos app(照片應用程式)。
選擇一張照片,點擊分享按鈕,然後點擊你應用程式的 share extension 圖示。
將 app extension 新增至你的專案。
在終端機中,以 release 模式執行你的 Flutter 應用程式:
flutter run --release在你的裝置上測試你的 app extension(應用程式擴充套件)。
啟動一個支援 Share extension(分享擴充套件)的應用程式, 例如「照片」(Photos) app。
選擇一張照片,點擊分享按鈕,然後點擊你應用程式的 分享擴充套件圖示。
與 iOS app extension 互動的其他方式
#Flutter 應用程式與 iOS app extension(應用程式擴充套件)互動時, 採用與 UIKit 或 SwiftUI 應用程式相同的技術。 主應用程式與 app extension 之間不會直接通訊。 當使用者與 extension 互動時,主應用程式可能並未執行中。 主應用程式與 extension 可以讀寫共用資源, 或使用更高階的 API 來彼此溝通。
使用高階 API
#部分 extension 提供 API。例如, Core Spotlight framework 可為你的應用程式建立索引, 讓使用者能從 Spotlight 與 Safari 進行搜尋。 WidgetKit framework 則可觸發 主畫面小工具(widget)的更新。
為簡化應用程式與 extension 的溝通方式, Flutter 套件會包裝這些 API。 若要尋找包裝 extension API 的套件, 請參考 Leveraging Apple's System APIs and Frameworks 或在 pub.dev 搜尋。
共用資源
#若要在 Flutter 應用程式與 app extension 之間共用資源, 請將 Runner app target 和 extension target 放入同一個 App Group。
將 target 加入 App Group 的步驟如下:
在 Xcode 中開啟該 target 的設定。
前往 Signing & Capabilities 分頁。
選擇 + Capability,然後選擇 App Groups。
從以下兩種方式選擇你要加入的 App Group:
- 從清單中選擇一個 App Group。
- 點擊 + 以新增一個新的 App Group。

當兩個 target 屬於同一個 App Group 時, 它們可以讀寫相同的來源資料。 請根據你的資料選擇以下其中一種來源方式:
- Key/value: 使用
shared_preference_app_group套件在同一個 App Group 內讀寫UserDefaults。 - 檔案: 使用
path_provider套件取得 App Group container 路徑, 以讀寫檔案。 - 資料庫: 使用
path_provider套件取得 App Group container 路徑, 並搭配sqflite套件建立資料庫。
排程背景更新
#背景任務可讓你無論應用程式狀態為何, 皆能透過程式碼更新 extension。
若要從 Flutter 應用程式排程背景工作, 請使用 workmanager 套件。
加入深度連結
#你可能會希望從 app extension 將使用者導向 Flutter 應用程式中的特定頁面。 若要在應用程式中開啟特定路由, 可以使用 Deep Linking。
加入可捲動清單
#預設情況下,flutter view 在 Share extension 中 不會處理捲動手勢。若要在 Share extension 中支援可捲動清單, 請依照這些指示操作。
在 iOS app extension 中開啟 Flutter 應用程式
#你可以直接在某些 iOS app extension(如 Share extension)中開啟你的 Flutter 應用程式, 並搭配 FlutterViewController 使用。
以下範例中,一個名為 Example App With Extension 的 Flutter 應用程式 被開啟於 Share extension,讓使用者可在應用程式間分享內容:
請依照以下步驟,在 Share app extension 中顯示 Flutter 應用程式。 此範例中,app extension scheme 名稱為 ShareExtension, Flutter app scheme 名稱為 Runner, Flutter 應用程式名稱為 Example App With Extension:
將 extension 加入你的 Flutter 應用程式 (若尚未加入)。
在終端機中,切換至你的 Flutter 專案目錄, 然後使用以下指令在 Xcode 中開啟你的專案:
open ios/Runner.xcworkspace在 Xcode 中,停用使用者腳本沙箱(User Script Sandboxing)。
開啟專案導覽器(View > Navigators > Project)。
在主視窗下方的 TARGETS 區塊,選擇 ShareExtension。
開啟 Build Settings 分頁。
前往 Build Options。
將 User Script Sandboxing 設定為 No。
在 Xcode 中,為
ShareExtensionscheme 新增 pre-action。開啟 Manage Schemes 視窗(Product > Scheme > Manage Schemes)。
選擇 ShareExtension scheme 並進行編輯。
展開 Build 分頁。
選擇 Pre-actions。
點擊 + 並選擇 New Run Script Action。
在 Provide build settings from 下拉選單中,選擇 ShareExtension。
在 Shell 文字欄位中輸入:
/bin/sh "$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh" prepare點擊 Close(關閉)。
在 Xcode 中,共享建置組態。
開啟 project navigator (View > Navigators > Project)。
在主視窗的 PROJECT 區塊下,選取 Runner。
開啟 Info 分頁。
展開 Configuration。
展開 Debug,並將 ShareExtension 的值更新為與 Runner 相同。
針對 Profile 和 Release 重複前述步驟。
完成後,請確認組態看起來類似以下畫面:

(選用)如有需要,在 Xcode 中以 extension 類別取代任何 storyboard 檔案。
開啟 project navigator (View > Navigators > Project)。
選取 Runner > ShareExtension > Info。
展開 Information Property List。
刪除 NSExtensionMainStoryboard 鍵。
新增 NSExtensionPrincipalClass 鍵。
為
NSExtensionPrincipalClass鍵新增以下其中一個值:- (Swift)ShareExtension.ShareViewController
- (Objective-C)ShareViewController
在 Xcode 中,將
ShareViewController更新為使用FlutterViewController。開啟 project navigator (View > Navigators > Project)。
選取 Runner > ShareExtension > ShareViewController。
將
ShareViewController更新為使用FlutterViewController類別:
import UIKit
import Flutter
class ShareViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
showFlutter()
}
func showFlutter() {
let flutterEngine = FlutterEngine(name: "my flutter engine")
flutterEngine.run()
let flutterViewController = FlutterViewController(engine: flutterEngine, nibName: nil, bundle: nil)
addChild(flutterViewController)
view.addSubview(flutterViewController.view)
flutterViewController.view.frame = view.bounds
}
override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
self.extensionContext?.cancelRequest(
withError: NSError(domain: Bundle.main.bundleIdentifier!, code: 0))
}
}@import Flutter;
@import UIKit;
@interface ShareViewController : UIViewController
@end#import "ShareViewController.h"
@import Flutter;
@implementation ShareViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self showFlutter];
}
- (void)showFlutter {
FlutterEngine *flutterEngine = [[FlutterEngine alloc] initWithName:@"my flutter engine"];
[flutterEngine run];
FlutterViewController *flutterViewController =
[[FlutterViewController alloc] initWithEngine:flutterEngine nibName:nil bundle:nil];
[self addChildViewController:flutterViewController];
[self.view addSubview:flutterViewController.view];
flutterViewController.view.frame = self.view.bounds;
}
- (void)viewDidDisappear:(BOOL)animated {
[super viewDidDisappear:animated];
[self.extensionContext cancelRequestWithError:[NSError errorWithDomain:NSBundle.mainBundle.bundleIdentifier code:0 userInfo:nil]];
}
@end註冊插件(Register plugins)
#請依照以下步驟,為應用程式擴充(app extension)註冊插件(plugin)。在此範例中,應用程式擴充方案名稱為 ShareExtension,Flutter 應用程式方案名稱為 Runner,Flutter 應用程式名稱為 Example App With Extension:
若尚未完成,請將擴充功能新增至你的 Flutter 應用程式。
在 Xcode 中,將
GeneratedPluginRegistrant.m加入至應用程式擴充目標(app extension target)。開啟 project navigator (View > Navigators > Project)。
在主視窗的 TARGETS 區塊下,選取 ShareExtension。
開啟 Build Phases 分頁。
展開 Compile Sources。
點擊 +。
在 Choose item to add 對話框的清單中,選取 GeneratedPluginRegistrant.m。
點擊 Add。
(僅限 Swift)在 Xcode 中,更新
SWIFT_OBJC_BRIDGING_HEADER的 build setting。開啟 project navigator (View > Navigators > Project)。
在主視窗的 TARGETS 區塊下,選取 ShareExtension。
開啟 Build Settings 分頁。
選擇 All 篩選器。
前往 Swift Compiler - General,將 Objective-C Bridging Header 鍵值設為 Runner/Runner-Bridging-Header.h。
在 Xcode 中,更新
ShareViewController的程式碼, 以註冊GeneratedPluginRegistrant.h。開啟 project navigator (View > Navigators > Project)。
選取 Runner > ShareExtension > ShareViewController。
更新
ShareViewController檔案,使用GeneratedPluginRegistrant.h:
// Add this inside `showFlutter()` at the top
GeneratedPluginRegistrant.register(with: flutterEngine)// Add this import at the top
#import "GeneratedPluginRegistrant.h"// Add this after [flutterEngine run]
[GeneratedPluginRegistrant registerWithRegistry:flutterEngine];- (Xcode)使用模擬器測試你的應用程式。
限制條件
#你必須使用 iOS 模擬器來在偵錯模式下測試你的擴充功能(extension)。
Flutter 在建構擴充功能 UI 時,尚未完全支援在實體裝置上以偵錯模式執行應用程式擴充功能,因為實體裝置可能會發生記憶體不足的情況。
iOS 應用程式擴充功能有記憶體限制。 建議僅在應用程式擴充功能至少支援 100MB 記憶體時,才修改其 UI。
在 iOS 應用程式擴充功能中呼叫 Dart 程式碼/渲染 Flutter 內容
#home_widget 套件提供了大量功能,包括允許以下操作:
在應用程式擴充功能中使用 Dart 程式碼回應使用者輸入。
在應用程式擴充功能中將 Flutter 元件(Widgets)渲染為圖片。
從
UserDefaults儲存與讀取資料於 iOS 上。
其他資源
#如需逐步操作說明,了解如何在 Flutter iOS 應用程式中使用應用程式擴充功能,請參考 為你的 Flutter 應用程式新增主畫面小工具(Home Screen Widget) 教學。
若想進一步了解在 iOS 應用程式中新增 Flutter 螢幕的各種方式,請參閱 在 iOS 應用程式中新增 Flutter 螢幕。