dart:ffiを使ってDartでC++を動かす。🤖
なぜやるか
OpenCVを利用するFlutterアプリを実装するために、技術調査としてDartでC++を動かしてみました。
ゴール
C++で書いた関数をDartから呼び出します。ios/androidどちらもやりますよ。
方法
dart:ffiを使用します。
dart:ffiってなに?
「ffi」はforeign function interface (外部関数インターフェース)の略です。
- C/C++でネイティブ言語のライブラリを使用できる
- メモリ上の特定アドレス(ポインタ)に直接書き込み、読み込み、割り当て機能がある
こういった機能を持つプラグインです。
実装
ios→androidの順で実装します。
iOS編
①C++ファイルの準備
まずはiosフォルダ内にios>Classes>native_add.cpp
のような構成でC++ファイルを準備します。
// 🔽 dartから呼び出したいC++関数で、引数を足して返す単純な関数です。
// 先に言っておくと、iosフォルダの中のファイルをandroidでも参照する構成にしていきます。
#include <stdint.h>
extern "C" __attribute__((visibility("default"))) __attribute__((used))
int32_t native_add(int32_t x, int32_t y) {
return x + y;
}
②Dartから呼び出す処理の準備
次に、libフォルダ内でdartファイルを作成します。
例ではlib>native_add.dart
のように配置していきます。
import 'dart:ffi'; // For FFI
import 'dart:io'; // For Platform.isX
// ネイティブライブラリをロードするためのDynamicLibraryオブジェクトを作成
final DynamicLibrary nativeAddLib = Platform.isAndroid
? DynamicLibrary.open('libnative_add.so')
: DynamicLibrary.process();
// DynamicLibraryオブジェクトから検索された関数をDartの関数型に変換
final int Function(int x, int y) nativeAdd = nativeAddLib
.lookup<NativeFunction<Int32 Function(Int32, Int32)>>('native_add')
.asFunction();
③Xcode上からシンボル(関数や変数)のビルド設定を追加
①で作成したC++ファイルをXcodeからCompile Sourcesに設定します。ios/Classes
フォルダの中にあるので、外部フォルダから参照させましょう。
native_add.dart
で変換した関数を呼び出す
④シンプル✅
Text('1 + 2 == ${nativeAdd(1, 2)}')
Android編
①CMakeListsの作成
AndroidではCMakeLists.txtに共有ライブラリ(先程作ったios/Classes/native_add.cpp
)をビルドするための設定を記述していきます。
フォルダ構成はandroid/app/CMakeLists.txt
とします。
cmake_minimum_required(VERSION 3.4.1)
add_library(native_add
SHARED
../../ios/Classes/native_add.cpp)
②build.gradleでCMakeListsのビルド設定
android {
<..上記省略>
sourceSets {
main.java.srcDirs += 'src/main/kotlin'
}
// ⭐外部ネイティブビルド設定を追加️
externalNativeBuild {
// CMakeLists.txtからcmakeを実行
cmake{
path "CMakeLists.txt"
}
}
defaultConfig {
<以下省略..>
③ビルド
iOS編②と④で既にDartから呼び出す処理の準備を行なっているので、そのままビルドできるはずです✅
iOS編②と④をまだ作業していない場合はそれぞれファイルを追加してあげてください。
まとめ
今回は共通ライブラリを想定してフォルダを構成・実装していますが、ios/androidどちらかしか実装の必要がない、または個別に外部ライブラリを分ける場合はライブラリをios
配下に構築する必要はありません。
この記事では「DartでC++関数を呼び出す」までをゴールとしていますが、この後に続いた「FlutterアプリでOpenCVを扱う」まで記事にしたいと思います。
参考とさせていただいたもの
・Flutterプラグインでdart:ffiを使ってみる
・dart:ffi 公式
Discussion