この記事では、備忘録も兼ねて、FlutterにおいてAndroid実機でOpenCV(C++,FFI)を搭載してデバッグビルドする方法と、それに付随して発生する問題やその解決法について記述する。
この方法でOpenCVを搭載するメリットについては、iOSに向けてビルドする場合とAndroidに向けてビルドする場合とで(KotlinやSwiftなどに)コードを分ける必要が無く、メソッドチャンネルなどの理解が難しい手法を取る必要もないとだけ簡潔に述べておく。
最初にビルドを行うまでの作業
Integrating C library in a Flutter app using Dart FFI | by Igor Kharakhordin | Flutter Community | Medium
まずはここを見るべし。
大前提として、OpenCVのライブラリをプロジェクトにブチ込んだり、ライブラリの依存関係をどう記述するかについての情報が載っている。なお、iOSの場合についても書いてある。
ただし、当ページの
In order to build and link the library and our code from native_opencv.cpp must be added to cmake (or ndk-build). Create CMakeLists.txt configuration file in android folder of the plugin:
の次に書いてある
cmake_minimum_required(VERSION 3.4.1)
include_directories(../include)
add_library(lib_opencv SHARED IMPORTED)
set_target_properties(lib_opencv PROPERTIES IMPORTED_LOCATION ${CMAKE_CURRENT_SOURCE_DIR}/src/main/jniLibs/${ANDROID_ABI}/libopencv_java4.so)
add_library(native_opencv SHARED ../ios/Classes/native_opencv.cpp)
target_link_libraries(native_opencv lib_opencv)
において、../include
と../ios/Classes/native_opencv.cpp
に関しては、もう一つ../
を付けないとパスが合わないと思われるので注意。
ここがミスっていると、前者は「opencvが見つからないぜ!」と言われ、後者は「C++のソースコードが無いぜ!」と言われる。
ここまでで無事にビルドできれば万々歳だが、自分が作業を行った際は追加で
FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':app:stripDebugDebugSymbols'.
> No toolchains found in the NDK toolchains folder for ABI with prefix: arm-linux-androideabi
という内容のエラーが発生した。以下に参考ページと、原因と思われるものを記述する。
Gradle Pluginのバージョンが古い
今回の結論ではそうなった。プロジェクトを作ったのが半年以上前で、諸々の設定が古かったということも原因として考えられるため、最新の環境でプロジェクトを作り、上記の作業を行った場合は以下の作業が必要ない可能性もある。
あるいは、Gradle Pluginとその他の環境との食い合わせが悪かった可能性もある。
なんにせよ、今回採った対策としては、
(ProjectRoot)/android/build.gradle
において、
buildscript {
dependencies {
classpath 'com.android.tools.build:gradle:4.0.0'
}
}
とし、Gradle Pluginのバージョンを4.0.0
以上にする(変更箇所以外は省略してある)。
最終的には4.0.1
や4.0.2
でも通ったが、あまり重要ではないので割愛。
Gradleのバージョンも古い
しかし、これだけだと
> Failed to apply plugin [id 'com.android.internal.version-check'] > Minimum supported Gradle version is 6.1.1. Current version is *.*.*. If using the gradle wrapper, try editing the distributionUrl in (ProjectRoot)/android/gradle/wrapper/gradle-wrapper.properties to gradle-6.1.1-all.zip
とツッコまれる。
要約すると、「Gradleのバージョンが古いぜ!」ということ。
さっきGradle Pluginのバージョンを上げたのに、こっちではGradleのバージョンが古いとはどういうこっちゃ? となるが、Gradle と Gradle Plugin のバージョンについて - Qiitaによれば、Gradle Pluginとは
これはgradleって書いていますがAndroid plugin for Gradle(人によっては Gradle Plugin)と呼ばれているものでGradleそのものではありません。
簡単に言えば_GraldeをAndroid Studioで使用するためのプラグイン_です。
とのこと。つまりは別物。
とりあえず、上記のエラーログにはどこをどう変更すれば良いのか親切に書いてあるので、指摘通りに(ProjectRoot)/android/gradle/wrapper/gradle-wrapper.properties
を開き、
distributionUrl=https\://services.gradle.org/distributions/gradle-6.1.1-all.zip
に変更。
NDKのバージョンも古い
しかしこれでもまだ、
> No version of NDK matched the requested version 21.0.6113669. Versions available locally: 23.0.7123448
とツッコまれる。少々疲れてくるが、次で最後。
これは、上記参考ページのdeakjahn氏がその答えを述べており、(ProjectRoot)/android/app/build.gradle
(←先程のbuild.gradle
とは別物なので注意)を
android {
ndkVersion '23.0.7123448-rc1'
}
のように変更(該当箇所が無い場合は追記)することでビルドが通るようになる。
ただし、上記参考ページでdeakjahn氏が述べているように、GradleやGladle Plugin、NDKのバージョンを変更するたびにこの部分で引っかかる可能性がある。とはいってもビルドが通らないのはもっと困るので、今後注意を払うしかない。
ここで指定されるバージョンのNDKがインストールされているかどうかは、AndroidStudioを起動し、(Macでは)出てきたウインドウの右下からConfigure > SDK Manager > Android SDK
のSDK Tools
タブにおいて、右下のShow Package Details
にチェックを入れ、NDK
のツリーを見ればわかる。
該当するバージョンにチェックが入っていない場合はインストールされていないので、チェックを入れてApply
を押せばインストールウィザードが開始する。
なお、Version
欄に記載されているバージョン名に、rc1
など純粋な番号以外の記号が付属している場合、上記のようにハイフンでつないで記述する。一応忘れてもエラーログで記法を教えてくれる。
ここまでの作業を終えてなおビルドが通らない場合は、なにか別の原因が存在する可能性があるため、エラーログをよく確認することを推奨する。
蛇足
Gradleのバージョンも古い では、
distributionUrl=https\://services.gradle.org/distributions/gradle-6.1.1-all.zip
としたが、書かれているURLにアクセスすれば、より新しいバージョンのGradleが配布されていることがわかる。今後の面倒を減らすためにも、6.1.1より新しいバージョンを入れておいてもいいかもしれない。
2021-03-04現在、6.8.3での動作を確認済み。