本指南將向您展示如何將 iOS 應用擴充套件與 Flutter 應用結合使用。

概述

#

iOS 應用擴充套件允許您在 iOS 應用之外擴充套件功能。您的應用可以顯示為主螢幕小部件,或者您可以將應用的部分功能提供給其他應用使用。

在以下示例中,當用戶在 iOS 照片應用中選擇要共享的照片時,“Example App With Extension”這個 Flutter 應用會顯示在照片應用的分享表中。

Share sheet with a Flutter app in it.

為您的 Flutter 應用新增 iOS 應用擴充套件

#

如果您想將 Flutter 應用與 iOS 作業系統整合,可以為您的 Flutter 專案新增 iOS 應用擴充套件。為了實現無縫的工作流程,以下步驟將展示如何為名為 example_app_with_extension 的新 Flutter 應用新增一個 分享 應用擴充套件,但您也可以從現有專案開始。

  1. 在控制檯中,建立一個名為 example_app_with_extension 的新 Flutter 專案。

    flutter create example_app_with_extension
  2. 在控制檯中,開啟 example_app_with_extension 專案的 Xcode 工作區。

    cd example_app_with_extension && open ios/Runner.xcworkspace
  3. 在 Xcode 中,新增一個名為 Share 的應用擴充套件,並將其命名為 ShareExtension

    • 在 Xcode 選單欄中,選擇 **檔案** > **新建** > **目標**。

    • 新增 **分享擴充套件**。

    • 在 **名稱** 欄位中,輸入 **ShareExtension**。

    • 點選 Finish(完成)。

    • 在出現的 **啟用…方案** 對話方塊中,選擇 **啟用**。

  4. 在 Xcode 中,更改構建過程的順序。

    • 開啟 **專案導航器** (**檢視** > **導航器** > **專案**)。

    • 在 **專案導航器** 的頂部,選擇 **Runner**。

    • 在主視窗的 **TARGETS** 下,選擇 **Runner**。

    • 開啟 **構建階段** 選項卡。

    • 將 **嵌入 Foundation 擴充套件** 拖到 **執行指令碼** 的上方。

  5. 請確保您的 **最低部署** iOS 值設定正確,並且在 **Runner** 和 **ShareExtension** 中都匹配。

    • 開啟 **專案導航器** (**檢視** > **導航器** > **專案**)。

    • 在 **專案導航器** 的頂部,選擇 **Runner**。

    • 在主視窗的 **TARGETS** 下,選擇 **Runner**。

    • 在 **通用** 選項卡上,檢查您的 **最低部署** 下拉選單值,確保它與 **ShareExtension** > **通用** 選項卡上的值相匹配。

  6. 在控制檯中,執行以下命令以重新構建您的 iOS 應用。

    flutter build ios --config-only
  7. 使用模擬器測試您的應用.

當您新增新的應用擴充套件時,Xcode 會根據您選擇的模板生成示例程式碼。有關生成的程式碼和 WidgetKit 的更多資訊,請參閱 Apple 的應用擴充套件文件

測試 iOS 應用擴充套件

#

在將應用擴充套件新增到 Flutter 專案後,您可以使用模擬器或物理裝置對其進行測試。如果您在除錯模式下測試擴充套件,則必須使用 iOS 模擬器。

以下步驟假定您使用的是 新增 iOS 應用擴充套件中的示例應用程式和分享擴充套件。

  1. 在 Xcode 中,為您的專案新增一個應用擴充套件

  2. 在控制檯中,使用以下命令執行您的 iOS 應用。

    flutter run
  3. 在模擬器中,測試您的應用擴充套件。

    • 啟動支援分享擴充套件的應用,例如照片應用。

    • 選擇一張照片,點選分享按鈕,然後點選您應用的分享擴充套件圖示。

  1. 為您的專案新增一個應用擴充套件。

  2. 在控制檯中,以釋出模式執行您的 Flutter 應用。

    flutter run --release
  3. 在您的裝置上,測試您的應用擴充套件。

    • 啟動支援分享擴充套件的應用,例如照片應用。

    • 選擇一張照片,點選分享按鈕,然後點選您應用的分享擴充套件圖示。

與 iOS 應用擴充套件互動的更多方法

#

Flutter 應用與 iOS 應用擴充套件的互動方式與 UIKit 或 SwiftUI 應用相同。包含的應用和應用擴充套件不直接通訊。當裝置使用者與擴充套件互動時,包含的應用可能未執行。應用和您的擴充套件可以讀取和寫入共享資源,或使用更高級別的 API 進行通訊。

使用更高級別的 API

#

某些擴充套件具有 API。例如,Core Spotlight 框架會索引您的應用,允許使用者透過 Spotlight 和 Safari 進行搜尋。WidgetKit 框架可以觸發主螢幕小部件的更新。

為了簡化您的應用與擴充套件之間的通訊,Flutter 外掛封裝了這些 API。要查詢封裝了擴充套件 API 的外掛,請檢視 利用 Apple 的系統 API 和框架 或在 pub.dev 上搜索。

共享資源

#

要在您的 Flutter 應用和應用擴充套件之間共享資源,請將 Runner 應用目標和擴充套件目標放在同一個 App Group 中。

新增目標到 App Group

  1. 在 Xcode 中開啟目標設定。

  2. 導航到 **簽名與功能** 選項卡。

  3. 選擇 **+ 功能**,然後選擇 **App Groups**。

  4. 從兩個選項中選擇要將目標新增到的 App Group。

    1. 從列表中選擇一個 App Group。
    2. 點選 **+** 新增一個新的 App Group。
Selecting an App Group within an Xcode Runner target configuration.

當兩個目標屬於同一個 App Group 時,它們可以讀取和寫入同一個源。選擇以下任一資料來源:

安排後臺更新

#

後臺任務提供了一種透過程式碼更新擴充套件的方式,而不管您的應用狀態如何。

要從您的 Flutter 應用排程後臺任務,請使用 workmanager 外掛。

新增深度連結

#

您可能希望將使用者從應用擴充套件引導到 Flutter 應用中的特定頁面。要開啟應用中的特定路由,您可以使用 深度連結

新增可滾動列表

#

預設情況下,Flutter 檢視在 分享 擴充套件中不處理滾動事件。要支援分享擴充套件中的可滾動列表,請遵循 這些說明

在 iOS 應用擴充套件中開啟 Flutter 應用

#

您可以透過 FlutterViewController 直接在某些 iOS 應用擴充套件(如 分享 擴充套件)中開啟您的 Flutter 應用。

在以下示例中,名為 Example App With Extension 的 Flutter 應用在分享擴充套件中開啟,允許使用者在應用之間共享內容。

An example of an entry added to the share menu by a Flutter app

使用以下步驟在 分享 應用擴充套件中顯示 Flutter 應用。在此示例中,應用擴充套件方案名為 ShareExtension,Flutter 應用方案名為 Runner,Flutter 應用名為 Example App With Extension

  1. 如果您還沒有為 Flutter 應用新增擴充套件,請 新增一個擴充套件

  2. 在控制檯中,導航到您的 Flutter 專案目錄,然後使用以下命令在 Xcode 中開啟您的專案。

    open ios/Runner.xcworkspace
  3. 在 Xcode 中,停用使用者指令碼沙盒。

    • 開啟 **專案導航器** (**檢視** > **導航器** > **專案**)。

    • 在主視窗的 **TARGETS** 下,選擇 **ShareExtension**。

    • 開啟 **構建設定** 選項卡。

    • 導航到 **構建選項**。

    • 將 **使用者指令碼沙盒** 設定為 **否**。

  4. 在 Xcode 中,將預操作新增到 ShareExtension 方案。

    • 開啟 **管理方案** 視窗 (**產品** > **方案** > **管理方案**)。

    • 選擇 ShareExtension 方案並進行編輯。

    • 展開 **構建** 選項卡。

    • 選擇 **預操作**。

    • 點選 **+**,然後選擇 **新建執行指令碼操作**。

    • 在 **提供構建設定來自** 下拉列表中,選擇 **ShareExtension**。

    • 在 **Shell** 文字欄位中,輸入:

      /bin/sh "$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh" prepare
    • 點選 **關閉**。

  5. 在 Xcode 中,共享構建配置。

    • 開啟 **專案導航器** (**檢視** > **導航器** > **專案**)。

    • 在主視窗的 **PROJECT** 下,選擇 **Runner**。

    • 開啟 **資訊** 選項卡。

    • 展開 **配置**。

    • 展開 **Debug**,並將 **ShareExtension** 的值更新為與 **Runner** 的值相匹配。

    • 對 **Profile** 和 **Release** 重複上一步。

    • 完成後,請確保配置看起來與以下內容相似。

      Xcode configurations

  6. (可選) 在 Xcode 中,根據需要用擴充套件類替換任何故事板檔案。

    • 開啟 **專案導航器** (**檢視** > **導航器** > **專案**)。

    • 選擇 **Runner** > **ShareExtension** > **Info**。

    • 展開 **資訊屬性列表**。

    • 刪除 **NSExtensionMainStoryboard** 鍵。

    • 新增 **NSExtensionPrincipalClass** 鍵。

    • NSExtensionPrincipalClass 鍵新增以下值之一:

      • (Swift) **ShareExtension.ShareViewController**
      • (Objective-C) **ShareViewController**
  7. 在 Xcode 中,更新 ShareViewController 以使用 FlutterViewController

    • 開啟 **專案導航器** (**檢視** > **導航器** > **專案**)。

    • 選擇 **Runner** > **ShareExtension** > **ShareViewController**。

    • 更新 ShareViewController 以使用 FlutterViewController 類。

ShareViewController.swift
swift
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))
    }
}
ShareViewController.h
objc
@import Flutter;
@import UIKit;

@interface ShareViewController : UIViewController

@end
ShareViewController.m
objc
#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
  1. 使用模擬器測試您的應用.

註冊外掛

#

使用以下步驟為應用擴充套件註冊外掛。在此示例中,應用擴充套件方案名為 ShareExtension,Flutter 應用方案名為 Runner,Flutter 應用名為 Example App With Extension

  1. 如果您還沒有為 Flutter 應用新增擴充套件,請 新增一個擴充套件

  2. 在 Xcode 中,將 GeneratedPluginRegistrant.m 新增到應用擴充套件目標。

    • 開啟 **專案導航器** (**檢視** > **導航器** > **專案**)。

    • 在主視窗的 **TARGETS** 下,選擇 **ShareExtension**。

    • 開啟 **構建階段** 選項卡。

    • 展開 **編譯原始檔**。

    • 點選 **+**。

    • 在“選擇要新增的項”對話方塊的列表中,選擇 **GeneratedPluginRegistrant.m**。

    • 點選 **新增**。

  3. (僅限 Swift) 在 Xcode 中,更新 SWIFT_OBJC_BRIDGING_HEADER 構建設定。

    • 開啟 **專案導航器** (**檢視** > **導航器** > **專案**)。

    • 在主視窗的 **TARGETS** 下,選擇 **ShareExtension**。

    • 開啟 **構建設定** 選項卡。

    • 選擇 **所有** 過濾器。

    • 導航到 **Swift 編譯器 - 通用**,並將 **Objective-C 橋標頭檔案** 鍵的值更改為 Runner/Runner-Bridging-Header.h

  4. 在 Xcode 中,更新 ShareViewController 的程式碼以註冊 GeneratedPluginRegistrant.h

    • 開啟 **專案導航器** (**檢視** > **導航器** > **專案**)。

    • 選擇 **Runner** > **ShareExtension** > **ShareViewController**。

    • 更新 ShareViewController 檔案以使用 GeneratedPluginRegistrant.h

ShareViewController.swift
swift
// Add this inside `showFlutter()` at the top
GeneratedPluginRegistrant.register(with: flutterEngine)
ShareViewController.m
objc
// Add this import at the top
#import "GeneratedPluginRegistrant.h"
ShareViewController.m
objc
// Add this after [flutterEngine run]
[GeneratedPluginRegistrant registerWithRegistry:flutterEngine];
  1. (Xcode) 使用模擬器測試您的應用

約束

#
  • 您必須使用 iOS 模擬器在除錯模式下測試您的擴充套件。

  • Flutter 對在物理裝置上以除錯模式執行構建了擴充套件 UI 的應用擴充套件的支援不完全,因為物理裝置可能會耗盡記憶體。

  • iOS 應用擴充套件的記憶體有限。建議僅在應用擴充套件支援至少 100MB 記憶體時修改應用擴充套件的 UI。

在 iOS 應用擴充套件中呼叫 Dart 程式碼/渲染 Flutter 內容

#

home_widget 包提供了大量功能,包括允許以下操作:

其他資源

#

有關將應用擴充套件與 Flutter iOS 應用結合使用的分步說明,請檢視 為 Flutter 應用新增主螢幕小部件 Codelab。

要了解有關將 Flutter 螢幕新增到 iOS 應用的各種方法的更多資訊,請參閱 將 Flutter 螢幕新增到 iOS 應用