跳至主要內容

使用 dart:ffi 綁定原生 macOS 程式碼

Flutter 行動裝置和桌面應用程式可以使用 dart:ffi 函式庫來呼叫原生 C API。FFI 代表 外部函式介面。類似功能的其他術語包括原生介面語言綁定

在您的函式庫或程式可以使用 FFI 函式庫來綁定原生程式碼之前,您必須確保原生程式碼已載入,並且其符號對 Dart 可見。本頁重點說明如何在 Flutter 外掛程式或應用程式中編譯、封裝和載入 macOS 原生程式碼。

本教學示範如何在 Flutter 外掛程式中綁定 C/C++ 原始碼,並在 macOS 上使用 Dart FFI 函式庫來綁定它們。在本逐步解說中,您將建立一個實作 32 位元加法的 C 函式,然後透過名為「native_add」的 Dart 外掛程式公開它。

動態與靜態連結

#

原生函式庫可以動態或靜態連結到應用程式中。靜態連結的函式庫會嵌入到應用程式的可執行映像檔中,並在應用程式啟動時載入。

可以使用 DynamicLibrary.executableDynamicLibrary.process 載入靜態連結函式庫中的符號。

相反地,動態連結的函式庫會以應用程式內獨立的檔案或資料夾形式散佈,並依需求載入。在 macOS 上,動態連結的函式庫會以 .framework 資料夾形式散佈。

可以使用 DynamicLibrary.open 將動態連結的函式庫載入到 Dart 中。

API 文件可從Dart API 參考文件取得。

建立 FFI 外掛程式

#

如果您已經有外掛程式,請跳過此步驟。

若要建立名為「native_add」的外掛程式,請執行下列動作

flutter create --platforms=macos --template=plugin_ffi native_add
cd native_add

這將建立一個在外掛程式 native_add/src 中具有 C/C++ 原始碼的外掛程式。這些原始碼由各種作業系統建置資料夾中的原生建置檔案建置。

FFI 函式庫只能針對 C 符號進行綁定,因此在 C++ 中,這些符號會標記為 extern "C"

您也應該新增屬性以指示符號是從 Dart 參考的,以防止連結器在連結時最佳化期間捨棄符號。__attribute__((visibility("default"))) __attribute__((used))

在 iOS 上,native_add/macos/native_add.podspec 會連結程式碼。

原生程式碼是從 lib/native_add_bindings_generated.dart 中的 dart 叫用。

綁定是使用 package:ffigen 產生的。

其他使用案例

#

iOS 和 macOS

#

當應用程式啟動時,動態連結的函式庫會由動態連結器自動載入。可以使用 DynamicLibrary.process 解析它們的組成符號。您也可以使用 DynamicLibrary.open 取得函式庫的控制代碼,以限制符號解析的範圍,但不清楚 Apple 的審查流程如何處理此問題。

可以使用 DynamicLibrary.executableDynamicLibrary.process 解析靜態連結到應用程式二進位檔中的符號。

平台函式庫

#

若要連結到平台函式庫,請使用下列指示

  1. 在 Xcode 中,開啟 Runner.xcworkspace
  2. 選取目標平台。
  3. 在「Linked Frameworks and Libraries」(連結的框架和函式庫)區段中,按一下「+」。
  4. 選取要連結的系統函式庫。

第一方函式庫

#

第一方原生函式庫可以包含為原始碼或 (已簽署) .framework 檔案。可能也可以包含靜態連結的封存檔,但需要測試。

原始碼

#

若要直接連結到原始碼,請使用下列指示

  1. 在 Xcode 中,開啟 Runner.xcworkspace

  2. 將 C/C++/Objective-C/Swift 原始程式碼檔案新增至 Xcode 專案。

  3. 將下列前置詞新增至匯出的符號宣告,以確保它們對 Dart 可見

    C/C++/Objective-C

    objc
    extern "C" /* <= C++ only */ __attribute__((visibility("default"))) __attribute__((used))

    Swift

    swift
    @_cdecl("myFunctionName")

已編譯 (動態) 函式庫

#

若要連結到已編譯的動態函式庫,請使用下列指示

  1. 如果存在正確簽署的 Framework 檔案,請開啟 Runner.xcworkspace
  2. 將框架檔案新增至「Embedded Binaries」(嵌入的二進位檔)區段。
  3. 也將其新增至 Xcode 中目標的「Linked Frameworks & Libraries」(連結的框架和函式庫)區段。

已編譯 (動態) 函式庫 (macOS)

#

若要將封閉原始碼函式庫新增至 Flutter macOS 桌面應用程式,請使用下列指示

  1. 依照 Flutter 桌面的指示來建立 Flutter 桌面應用程式。
  2. 在 Xcode 中開啟 yourapp/macos/Runner.xcworkspace
    1. 將您預先編譯的函式庫 (libyourlibrary.dylib) 拖曳到 Runner/Frameworks 中。
    2. 按一下 Runner 並前往「Build Phases」(建置階段)索引標籤。
      1. libyourlibrary.dylib 拖曳到「Copy Bundle Resources」(複製套件資源)清單中。
      2. 在「Embed Libraries」(嵌入函式庫)下,勾選「Code Sign on Copy」(複製時進行程式碼簽署)。
      3. 在「Link Binary With Libraries」(連結二進位檔與函式庫)下,將狀態設定為「Optional」(可選)。(我們使用動態連結,無需靜態連結。)
    3. 按一下 Runner 並前往「General」(一般)索引標籤。
      1. libyourlibrary.dylib 拖曳到「Frameworks, Libraries and Embedded Content」(框架、函式庫和嵌入內容)清單中。
      2. 選取「Embed & Sign」(嵌入和簽署)。
    4. 按一下「Runner」(執行器)並前往「Build Settings」(建置設定)索引標籤。
      1. 在「Search Paths」(搜尋路徑)區段中,設定「Library Search Paths」(函式庫搜尋路徑)以包含 libyourlibrary.dylib 所在的目錄路徑。
  3. 編輯 lib/main.dart
    1. 使用 DynamicLibrary.open('libyourlibrary.dylib') 動態連結到符號。
    2. 在 widget 中的某處呼叫您的原生函式。
  4. 執行 flutter run 並檢查您的原生函式是否被呼叫。
  5. 執行 flutter build macos 以建置應用程式的獨立發行版本。

其他資源

#

若要深入了解 C 互通性,請查看下列影片