こんにちは。中山です。
前回の「 こんなときどうする?Flutter でモバイルアプリ開発 」に続きまして、今回は、Flutter と Firebase を連携して、Flutter アプリから、Google の機械学習ライブラリである「 Google ML Kit 」の機能を利用してみたいと思います。
目次:
準備
Flutter と Firebase を連携して利用するための手順については、公式の Codelab にある「 Firebase for Flutter 」を参考にしました。(この Codelab では、Firebase のデータベース機能を使うための手順を説明していますが、今回のような ML Kit を利用するパターンでも、同様に参考となるでしょう。)
Flutter の開発環境の構築と、Firebase のアカウント作成までは実施済み、という前提で、以下の 4つの操作を進めます。(以降の各準備操作についても、詳細は、上記 Codelab もご参考になさってください。)
準備1 Flutter アプリプロジェクトの作成
まずは Flutter アプリのプロジェクトを作成します。今回は Android Studio を使って、「 ml_kit_lesson 」という名前でプロジェクトを作成しました。
準備2 Firebase プロジェクトの作成
Firebase のコンソールページを開いて、Firebase に新しくプロジェクトを登録します。今回は「 ml kit lesson 」という名前で作成しました。
なお今回は、ML Kit のうちの「 Cloud Vision APIs 」を利用する、という想定で、Firebase の利用プランは、従量課金制の「 Blaze 」プランを選択しています。
ただし、この「 Blaze 」プランであっても、ある程度の利用までは無料枠として用意されているようですので、お試しで触る程度でしたら、無料の範囲内で利用できるでしょう。
準備3 Firebase を iOS アプリから利用するための設定
Firebase のコンソールページを開いて、まず iOS アプリの情報を設定します。
アプリの登録後、生成された「 GoogleService-info.plist 」をダウンロードし、Xcode のビュー上にドラッグ&ドロップします。( 「 Runner/Runner/ 」ディレクトリ内にドラッグ&ドロップします。)
Firebase コンソールに表示される、以降の手順( Firebase SDK のインストールなど)は、ここではすべてスキップします。
準備4 Firebase を Android アプリから利用するための設定
Firebase のコンソールページを開いて、同様に Android アプリの情報を設定します。
アプリの登録後、生成された「 google-service.json 」をダウンロードし、Android 用のプロジェクトディレクトリ内の「 app 」ディレクトリに配置します。
Firebase コンソールに表示される、以降の手順( Firebase SDK のインストールなど)は、ここではすべてスキップします。
また、Android プラットフォーム固有の設定として、Flutter アプリプロジェクトディレクトリ内の
「 android/build.gradle 」ファイルに
「 classpath 'com.google.gms:google-services:3.2.1' 」の設定を追加し、
buildscript { repositories { google() jcenter() } dependencies { classpath 'com.android.tools.build:gradle:3.1.2' classpath 'com.google.gms:google-services:3.2.1' } }
「 android/app/build.gradle 」ファイルの末尾に、
「 apply plugin: 'com.google.gms.google-services' 」を追記します。
apply plugin: 'com.google.gms.google-services'
以上で、Flutter アプリと Firebase を連携するための準備が整いました。
プラグインを使う
Flutter アプリから Firebase の ML Kit の機能を利用するために、専用のプラグイン「 firebase_ml_vision 」が用意されていました。これを用いて、ML Kit の機能を試すことにします。
pubspec.yaml の設定
まずは、Flutter アプリプロジェクトディレクトリ内の「 pubspec.yaml 」ファイルの「 dependencies 」ブロックの部分に、以下のように「 firebase_ml_vision 」の記述を追加します。
またあわせて「 image_picker 」の設定も追記します。
dependencies: flutter: sdk: flutter firebase_ml_vision: ^0.1.2 image_picker: ^0.4.5
Flutter アプリ側のコードは、今回は「 firebase_ml_vision 」プラグインの「 Example 」ページにあるコードをそのまま使うことにします。
こちらのコードで、Flutter アプリのプロジェクト内の、「 lib/main.dart 」ファイルのコードをそのまま置き換えます。
さらに、同じく example にある、「 detector_painters.dart 」ファイルを取得して、main.dart と同じ「 lib 」ディレクトリに配置します。
Anroid プラットフォーム固有の設定
Flutter アプリプロジェクトディレクトリ内の
「 android/app/src/main/AndroidManifest.xml 」ファイルに、
以下のように「 <meta-data> 」のブロックを追加します。
<manifest xmlns:android="http://schemas.android.com/apk/res/android" ・・・ <application ・・・ <meta-data android:name="com.google.firebase.ml.vision.DEPENDENCIES" android:value="ocr,label,barcode,face" /> </application> </manifest>
実行
ここまでできたところで、Android 実機でアプリを実行しようとしたのですが、今回試した環境では以下のようなビルドエラーが出ました。
FAILURE: Build failed with an exception. * What went wrong: Execution failed for task ':app:preDebugBuild'. > Android dependency 'com.android.support:support-v4' has different version for the compile (26.1.0) and runtime (27.1.1) classpath. You should manually set the same version via DependencyResolution
このため、以下を参考にして、
firebase - Android dependency 'com.android.support:support-v4' has different version - Stack Overflow
Flutter アプリプロジェクトディレクトリ内の「 android/build.gradle 」ファイルに以下のように追記しました。
subprojects { project.evaluationDependsOn(':app') project.configurations.all { resolutionStrategy.eachDependency { details -> if (details.requested.group == 'com.android.support' && !details.requested.name.contains('multidex')) { details.useVersion "27.1.1" } } } }
Android 実機で実行した結果がこちら:
右上のメニューから「Detect Label 」を選択して、右下のボタンから写真を選んで指定すると、
このように、「 Dog 」または「 Pet 」と認識されました。
実際に画像認識の処理を呼び出しているのは、「 lib/main.dart 」ファイルのこのあたり。
Future<void> _scanImage(File imageFile) async { setState(() { _scanResults = null; }); final FirebaseVisionImage visionImage = FirebaseVisionImage.fromFile(imageFile); FirebaseVisionDetector detector; switch (_currentDetector) { case Detector.barcode: detector = FirebaseVision.instance.barcodeDetector(); break; case Detector.face: detector = FirebaseVision.instance.faceDetector(); break; case Detector.label: detector = FirebaseVision.instance.labelDetector(); break; case Detector.text: detector = FirebaseVision.instance.textDetector(); break; default: return; } final List<dynamic> results = await detector.detectInImage(visionImage) ?? <dynamic>[]; setState(() { _scanResults = results; }); }
- 「 FirebaseVisionImage.fromFile 」で画像の情報を取得して、
- 「 FirebaseVision.instance.labelDetector 」で、画像認識処理用のオブジェクトを取得して、
- 「 detector.detectInImage 」で、実際に画像認識・解析処理を実行する、
という流れのようです。
しかしながら、この「 firebase_ml_vision 」プラグインの元のソースの、このあたりを見てみますと、
plugins/label_detector.dart at master · flutter/plugins · GitHub
実は上記の実装のように「 labelDetector 」を用いている場合は、画像認識の処理自体はローカル側で完結する、「 On Device 」ML Kit API を利用している、ということのようでした。
一方、Firebase のクラウド環境にアクセスして画像認識処理を行う「 Cloud 」ML Kit API は、より精度の高い解析が行える、とのことです。(参考)
すでに最新のプラグインのソースでは、「 CloudLabelDetector 」という、「 Cloud 」API を用いて画像認識する(であろう)クラスが用意されていたのですが、これはまだ正式なプラグインの機能としては提供されていないようでした。
近日中に、この「 firebase_ml_vision 」プラグイン自体もアップデートされると思われますので、その際にはあらためて、ML Kit の「 Cloud 」API を利用するパターンも試してみたいと思います。
まとめ
結局のところは、今回は Firebase の機能を間接的に利用した、という形ではありましたが、用意されているプラグインを用いることで、最小限のコードで、複雑な処理が実装できることがわかりました。
Flutter 自体が、まだまだ発展途上の部分もありそうですが、これによってもたらされる開発のスピード感は、非常に魅力的なものになっていくのだろう、と感じました。