はじめに
flutterでC言語を扱う方法です。(需要は無いかもしれない)
androidしか持ってないので、androidしか動作確認しません!iosの有識者に任せます。
dart:ffiを使ったやり方を紹介します。
flutterのプロジェクトを作る
ディレクトリを作って、flutter New Projectで作ります。
flutter環境
Flutter 3.24.3 • channel stable • https://github.com/flutter/flutter.git
Framework • revision 2663184aa7 (3 months ago) • 2024-09-11 16:27:48 -0500
Engine • revision 36335019a8
Tools • Dart 3.5.3 • DevTools 2.37.3
fvm 3.1.4
必要なpackageを入れる
ffi を入れましょう!ffiとはflutter(dart)からC言語のAPIを呼べるようにするためのpackageです。
fvmを入れていない人は以下のコマンドをfvmを取り除いて実行してください。
fvm flutter pub add ffi
cコードを入れる
android\app\src\main\cpp 以下にCが使えるようにfileを入れます.
今回はCのライブラリであるminiaudioを使うことを想定しています。公式サイトからminiaudio.hをダウンロードしてcpp以下のコードに入れましょう。
CmakeLists.txtもここの階層に入れてください。ffiで呼び出すCのAPI用のfileもここに記述します。
今回はaudio_processing.cとします。
cpp -
- CmakeLists.txt
- miniaudio.h
- audio_processing.c
cMakeLIsts.txtの中身は以下の通りです。cmakeのversionと、さっき追加したfile(audio_processing.c)をlibraryとして追加して、directoryを指定します。
cmake_minimum_required(VERSION 3.4.1)
add_library(audio_processing SHARED audio_processing.c)
target_include_directories(audio_processing PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
flutterの設定でcを使えるようにする
android\app\build.gradle に以下の設定を追加します。
なんとflutterにはbuild.gradlwが2つあってとってもややこしいので気を付けましょう!!!(android\app\build.gradle と android\build.gradle があります。githubのissueとかでもどちらのbuild.gradleかを確認しないと迷宮入りすることがまれによくあります。)
externalNativeBuild {
cmake {
path "src/main/cpp/CMakeLists.txt"
}
}
dart側でCを呼び出す
lib\src\native_audio.dart (lib 以下ならどこでもおいて大丈夫です)
最初にandroidのときに、lib_audio_processing.soを開くようにします。(CMakeLists.txtで
add_library(audio SHARED audio_processing.c)
などにするとaudio.soになります)
final DynamicLibrary nativeAudioLib = Platform.isAndroid
? DynamicLibrary.open("libaudio_processing.so")
: DynamicLibrary.process();
audio_processing.cで書いた関数を呼び出せるようにします。このとき、返り値の型をcとdartで同じようにしましょう!!エラーがでます。
final int Function() initAudio = nativeAudioLib
.lookup<NativeFunction<Int32 Function()>>("init_audio")
.asFunction();
以上のようにするとC言語で呼び出せるようになります!!
additional
miniaudioはaudio関係のものなので、flutterで利用するにはpermissionを与えないと上手く働きません。↓こんな感じでaudio関係のものが使えないというエラーがでます。
E/libOpenSLES( 6637): android_audioRecorder_realize(0xb400006f9a552800) error creating AudioRecord object; status -1
なのでaudio関係のpermissionをあたえましょう!flutterでpermission関連でおすすめのpackage https://pub.dev/packages/permission_handler を使います。
locationなどの位置情報系のpackageを入れたとしてもpermission系はこっちで管理すると楽です。parmanent(常に許可する)が出せるのがいいところです。
flutter pub add permission_handler
android\app\src\main\AndroidManifest.xml に以下のものを追加します。
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
mainで許可を求めるコードを追加します。
Future<void> _requestPermissions() async {
final status = await Permission.microphone.request();
if (status.isGranted) {
if (initAudio() != 0) {
debugPrint("Audio initialization failed");
}
} else {
debugPrint("Microphone permission denied");
}
}
これをinitState内で実行すれば以下のような画面が出てきます。
Cのbuildがどうしても上手くいかないとき
エラーの内容を直してfvm flutter runしなおしたのに反映されないことってたまにありますよね??そんなときにやるといいこと(android版)を書いておきます。体験談なので読んでくれている人に効くかはわかりません。
- まずcleanしてみよう!!残っているbuildファイルとかがよくない影響を残していたり、packageの依存関係が終わっているときに効きます
fvm flutter clean
fvm flutter run
- ./gradle以下をcleanしてみよう!!そもそもandroid側でのbuildが終わってるときに効きます。assemble debugの時点で試してみましょう。カレントディレクトリは/androidで実行しましょう。./gradlew buildしたときにエラーが出る場合はコードに原因があるので対応しましょう!!でもおそらくfvm flutter runしたときよりも詳しいエラーが得られるはずです!
cd android
./gradlew clean
./gradlew build
- .cxx/ 以下を削除しよう!!fvm flutter cleanしただけでは削除されないので一回削除するとうまくいきます
- もし一回buildしているとして、実機にアプリが残っている場合はアンインストールしてもう一度やると上手くいく場合が多いです
最後に
この記事を書いたきっかけはflutterでリアルタイムで音声を扱いたいな~と思ってやってみたのですが、https://pub.dev/packages/miniaudio がすでにあったので簡単に作るにはこっちを用いたほうが楽だと思います!!
よいコーディングライフを!