在 iOS 中使用 dart:ffi 呼叫本地程式碼

Flutter 移動版可以使用 dart:ffi 函式庫來呼叫本地的 C API。 FFI 代表 外部功能介面。類似功能的其他術語包括本地介面語言繫結

你必須首先確保本地程式碼已載入,並且其符號對 Dart 可見,然後才能在函式庫或程式使用 FFI 函式庫繫結本地程式碼。本頁主要介紹如何在 Flutter 外掛或應用程式中編譯、打包和載入 iOS 原生程式碼。

本教程示範了如何在 Flutter 外掛中捆綁 C/C++ 原始碼,並在 iOS 上使用 Dart FFI 函式庫繫結和使用。

在本範例中,你將建立一個實現 32 位的加法 C 函式,然後透過名為 “native_add” 的 Dart 外掛暴露它。

動態連結 vs 靜態連結

本地函式庫可以動態或靜態地連結到應用程式中。一個靜態連結函式庫會被嵌入到應用程式的可執行映像中,並在應用程式啟動時載入。

靜態連結中的符號可以使用 DynamicLibrary.executableDynamicLibrary.process 來載入.

相比之下,動態連結庫則分佈在應用程式中的單獨的檔案或資料夾中,並按需載入。在 iOS 上,它是作為 .framework 資料夾分發的。

動態連結庫在 Dart 中可以透過 DynamicLibrary.open 載入。

Dart dev 頻道中的 API 已經可用: Dart API 參考文件.

建立 FFI 外掛

如果要建立一個名為 “native_add” 的外掛,你需要這麼做:

$ flutter create --platforms=android,ios,macos,windows,linux --template=plugin_ffi native_add
$ cd native_add

C/C++ 原始碼會被建立至 native_add/src。這些原始碼在不同平台建立時會生成在不同平台的建立檔案夾。

FFI 函式庫只能繫結 C 語言的符號,所以 C++ 語言的符號會被標記為 extern "C"

FFI 函式庫只能與 C 符號繫結,因此在 C++ 中,這些符號新增 extern C 標記。還應該新增屬性來表明符號是需要被 Dart 引用的,以防止連結器在最佳化連結時會丟棄符號。 __attribute__((visibility("default"))) __attribute__((used)).

在 iOS 上 native_add/android/build.gradle 負責關聯這些程式碼。

原生程式碼會從 lib/native_add_bindings_generated.dart 被 Dart 呼叫。

程式碼由 package:ffigen 生成。

其他的用例

iOS 和 macOS

動態連結庫在應用程式啟動時由動態連結器自動載入。它們的組成符號可以用 DynamicLibrary.process。你還可以使用 DynamicLibrary.open 來限制符號解析的範圍,但目前仍然不確定蘋果的審查程式將如何處理兩者的使用。

你可以使用 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

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

    Swift

    @_cdecl("myFunctionName")
    

已編譯的動態函式庫

要連結到已編譯過的動態函式庫,請按照如下說明:

  1. 如果存在已進行簽名的 Framework 檔案,請開啟 Runner.xcworkspace

  2. 新增 framework 檔案到 Embedded Binaries 區域中。

  3. 同時將其新增到 Xcode 中目標的 Linked Frameworks & Libraries 部分。

開源的三方函式庫

要建立一個包含 C/C++/Objective-C Dart 程式碼的 Flutter 外掛,請按照如下說明:

  1. 在你的外掛專案開啟 ios/<myproject>.podspec.

  2. 新增本地程式碼到 source_files 欄位。

本地程式碼會被靜態連結到任何使用這個外掛的應用二進位中。

閉源三方函式庫

要建立包含 Dart 原始碼,但 C/C++ 部分是以二進位形式分發的函式庫的 Flutter 外掛,請按照如下說明:

  1. 在你的外掛目錄開啟 ios/<myproject>.podspec

  2. 新增 vendored_frameworks 欄位。參考 CocoaPods 範例

精簡 iOS 符號表

當建立一個 release 檔案(IPA)時,符號會被 Xcode 刪除。

  1. 在 Xcode 中, 點選 Target Runner > Build Settings > Strip Style.

  2. All Symbols 修改為 Non-Global Symbols

Other Resources

To learn more about C interoperability, check out these videos: