跳到主內容

使用 dart:ffi 與原生 macOS 程式碼繫結

要在 Flutter 程式中使用 C 程式碼,請使用 dart:ffi 庫。

Flutter 移動和桌面應用可以使用 dart:ffi 庫呼叫原生 C API。FFI外部函式介面 的縮寫。其他類似的術語包括原生介面語言繫結

在您的庫或程式可以使用 FFI 庫繫結到原生程式碼之前,您必須確保已載入原生程式碼及其符號對 Dart 可見。此頁面重點介紹在 Flutter 外掛或應用程式中編譯、打包和載入 macOS 原生程式碼。

本教程演示瞭如何在 Flutter 外掛中捆綁 C/C++ 原始碼,並使用 Dart FFI 庫在 macOS 上與其繫結。在本演練中,您將建立一個實現 32 位加法的 C 函式,然後透過名為“native_add”的 Dart 外掛將其公開。

動態連結與靜態連結

#

原生庫可以動態或靜態地連結到應用中。靜態連結庫嵌入到應用的 executables 映像中,並在應用啟動時載入。

可以使用 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 Desktop 應用程式,請使用以下說明

  1. 按照 Flutter desktop 的說明建立 Flutter desktop 應用程式。
  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. 在某個小部件中呼叫您的原生函式。
  4. 執行 flutter run 並檢查您的原生函式是否被呼叫。
  5. 執行 flutter build macos 構建應用程式的自包含釋出版本。

其他資源

#

要了解更多關於 C 互操作性的資訊,請檢視以下影片