Flutter: APIレベル31以上のAndroidエミュレーターだと、Cameraの撮影がエラーになる
結論:(未解決)APIレベル31以上の端末については、実機でテストする
2022/11/6 Flutter エラー・バグ日記
「Camera」パッケージを使い、「takePicture」メソッドで撮影しようとすると、エラーになって撮影できない現象に直面した。
様々なケースで試したところ、
- APIレベル31(Android12)のAndroidエミュレーター
- APIレベル33(Android13)のAndroidエミュレーター
だとエラーになる。
一方、
- APIレベル30(Android11)以下のAndroidエミュレーター
- APIレベル31(Android12)のAndroid実機
- iOSシミュレーター(iOS16)
- iOS実機(iOS16)
ではエラーにならず、問題なく写真撮影できた。
実行環境は、以下のとおり。
- macOS: Monterey 12.6
- Flutter: stable 3.3.4
- Dart: 2.18.2
- Android Studio: version 2021.3
また、「Camera」パッケージのバージョンは、本日記時点で最新の「0.10.0+4」。
パッケージのReadmeに書かれているAndroid用の設定は実施済(minSdkVersion 21)。
以下2通りのコードで動作を試した。
- ReadmeのExampleの欄にあるコードに、「takePicture」メソッドの発動ボタン(撮影ボタン)を追加したもの
- Exampleページにあるコードそのまま
いずれのコードでも、同じエラーが発生する状況。そのため、コード自体の問題ではなさそう。。
エラーメッセージは複数パターンある
「CameraPreview」ウィジェットによるプレビュー画像は問題なく表示される(下図は、Android 12のエミュレーターで実行した場合)。
撮影ボタンを押し、「takePicture」メソッドを発動すると、アプリは落ちないが、何の反応も無く、コンソールにエラーログが表示される。
エラーログの内容は、状況によって若干異なり、主に下記3パターンあった。
■エラーパターン①
一番多く出るエラーが以下。
I/Camera (11669): runPrecaptureSequence I/Camera (11669): refreshPreviewCaptureSession D/CameraCaptureCallback(11669): CameraCaptureCallback | state: STATE_WAITING_PRECAPTURE_START | afState: 0 | aeState: 2 D/CameraCaptureCallback(11669): CameraCaptureCallback | state: STATE_WAITING_PRECAPTURE_DONE | afState: 0 | aeState: 2 I/Camera (11669): captureStillPicture D/Camera (11669): Updating builder with feature: ExposureLockFeature D/Camera (11669): Updating builder with feature: ExposurePointFeature D/Camera (11669): Updating builder with feature: ZoomLevelFeature D/Camera (11669): Updating builder with feature: AutoFocusFeature D/Camera (11669): Updating builder with feature: NoiseReductionFeature I/Camera (11669): updateNoiseReduction | currentSetting: fast D/Camera (11669): Updating builder with feature: FocusPointFeature D/Camera (11669): Updating builder with feature: ResolutionFeature D/Camera (11669): Updating builder with feature: SensorOrientationFeature D/Camera (11669): Updating builder with feature: FlashFeature D/Camera (11669): Updating builder with feature: ExposureOffsetFeature D/Camera (11669): Updating builder with feature: FpsRangeFeature I/Camera (11669): sending capture request D/CameraCaptureCallback(11669): CameraCaptureCallback | state: STATE_CAPTURING | afState: 0 | aeState: 2 D/CameraCaptureCallback(11669): CameraCaptureCallback | state: STATE_CAPTURING | afState: 0 | aeState: 2 D/CameraCaptureCallback(11669): CameraCaptureCallback | state: STATE_CAPTURING | afState: 0 | aeState: 5 D/CameraCaptureCallback(11669): CameraCaptureCallback | state: STATE_CAPTURING | afState: 0 | aeState: 5 D/EGL_emulation(11669): app_time_stats: avg=135.85ms min=30.15ms max=597.02ms count=11 I/Camera (11669): unlockAutoFocus I/Camera (11669): refreshPreviewCaptureSession D/CameraCaptureCallback(11669): CameraCaptureCallback | state: STATE_CAPTURING | afState: 0 | aeState: 5 D/CameraCaptureCallback(11669): CameraCaptureCallback | state: STATE_CAPTURING | afState: 0 | aeState: 5 D/CameraCaptureCallback(11669): CameraCaptureCallback | state: STATE_CAPTURING | afState: 0 | aeState: 5 D/CameraCaptureCallback(11669): CameraCaptureCallback | state: STATE_CAPTURING | afState: 0 | aeState: 5 D/CameraCaptureCallback(11669): CameraCaptureCallback | state: STATE_CAPTURING | afState: 0 | aeState: 5 D/CameraCaptureCallback(11669): CameraCaptureCallback | state: STATE_CAPTURING | afState: 0 | aeState: 5 D/CameraCaptureCallback(11669): CameraCaptureCallback | state: STATE_CAPTURING | afState: 0 | aeState: 2 D/CameraCaptureCallback(11669): CameraCaptureCallback | state: STATE_CAPTURING | afState: 0 | aeState: 5 I/Camera (11669): open | onError I/Camera (11669): close I/Camera (11669): open | onClosed
「E/」から始まるログはないものの、最後から3行目に「onError」と出ている。
APIレベル30以下のエミュレーターでは問題なく撮影され、このようなログは出ない。
■エラーパターン②
「compileSdkVersion」と「targetSdkVersion」を31から33に上げたら、以下のエラーになった。
I/Camera (11977): runPrecaptureSequence I/Camera (11977): refreshPreviewCaptureSession D/CameraCaptureCallback(11977): CameraCaptureCallback | state: STATE_WAITING_PRECAPTURE_START | afState: 0 | aeState: 2 D/CameraCaptureCallback(11977): CameraCaptureCallback | state: STATE_WAITING_PRECAPTURE_DONE | afState: 0 | aeState: 2 I/Camera (11977): captureStillPicture D/Camera (11977): Updating builder with feature: ExposureLockFeature D/Camera (11977): Updating builder with feature: ExposurePointFeature D/Camera (11977): Updating builder with feature: ZoomLevelFeature D/Camera (11977): Updating builder with feature: AutoFocusFeature D/Camera (11977): Updating builder with feature: NoiseReductionFeature I/Camera (11977): updateNoiseReduction | currentSetting: fast D/Camera (11977): Updating builder with feature: FocusPointFeature D/Camera (11977): Updating builder with feature: ResolutionFeature D/Camera (11977): Updating builder with feature: SensorOrientationFeature D/Camera (11977): Updating builder with feature: FlashFeature D/Camera (11977): Updating builder with feature: ExposureOffsetFeature D/Camera (11977): Updating builder with feature: FpsRangeFeature D/EGL_emulation(11977): app_time_stats: avg=92.99ms min=17.37ms max=464.67ms count=14 I/Camera (11977): sending capture request D/CameraCaptureCallback(11977): CameraCaptureCallback | state: STATE_CAPTURING | afState: 0 | aeState: 2 D/CameraCaptureCallback(11977): CameraCaptureCallback | state: STATE_CAPTURING | afState: 0 | aeState: 2 D/CameraCaptureCallback(11977): CameraCaptureCallback | state: STATE_CAPTURING | afState: 0 | aeState: 5 D/CameraCaptureCallback(11977): CameraCaptureCallback | state: STATE_CAPTURING | afState: 0 | aeState: 5 I/Camera (11977): unlockAutoFocus I/Camera (11977): refreshPreviewCaptureSession D/CameraCaptureCallback(11977): CameraCaptureCallback | state: STATE_CAPTURING | afState: 0 | aeState: 5 D/CameraCaptureCallback(11977): CameraCaptureCallback | state: STATE_CAPTURING | afState: 0 | aeState: 5 D/CameraCaptureCallback(11977): CameraCaptureCallback | state: STATE_CAPTURING | afState: 0 | aeState: 5 D/CameraCaptureCallback(11977): CameraCaptureCallback | state: STATE_CAPTURING | afState: 0 | aeState: 5 D/CameraCaptureCallback(11977): CameraCaptureCallback | state: STATE_CAPTURING | afState: 0 | aeState: 5 D/CameraCaptureCallback(11977): CameraCaptureCallback | state: STATE_CAPTURING | afState: 0 | aeState: 5 D/CameraCaptureCallback(11977): CameraCaptureCallback | state: STATE_CAPTURING | afState: 0 | aeState: 2 D/CameraCaptureCallback(11977): CameraCaptureCallback | state: STATE_CAPTURING | afState: 0 | aeState: 5 D/CameraCaptureCallback(11977): CameraCaptureCallback | state: STATE_CAPTURING | afState: 0 | aeState: 5 E/CameraCaptureSession(11977): Session 0: Exception while stopping repeating: E/CameraCaptureSession(11977): android.hardware.camera2.CameraAccessException: CAMERA_ERROR (3): cancelRequest:507: Camera 0: Error clearing streaming request: Function not implemented (-38) E/CameraCaptureSession(11977): at android.hardware.camera2.CameraManager.throwAsPublicException(CameraManager.java:1179) E/CameraCaptureSession(11977): at android.hardware.camera2.impl.ICameraDeviceUserWrapper.cancelRequest(ICameraDeviceUserWrapper.java:99) E/CameraCaptureSession(11977): at android.hardware.camera2.impl.CameraDeviceImpl.stopRepeating(CameraDeviceImpl.java:1287) E/CameraCaptureSession(11977): at android.hardware.camera2.impl.CameraCaptureSessionImpl.close(CameraCaptureSessionImpl.java:579) E/CameraCaptureSession(11977): at android.hardware.camera2.impl.CameraCaptureSessionImpl$2.onDisconnected(CameraCaptureSessionImpl.java:790) E/CameraCaptureSession(11977): at android.hardware.camera2.impl.CameraDeviceImpl$7.run(CameraDeviceImpl.java:259) E/CameraCaptureSession(11977): at android.os.Handler.handleCallback(Handler.java:938) E/CameraCaptureSession(11977): at android.os.Handler.dispatchMessage(Handler.java:99) E/CameraCaptureSession(11977): at android.os.Looper.loopOnce(Looper.java:201) E/CameraCaptureSession(11977): at android.os.Looper.loop(Looper.java:288) E/CameraCaptureSession(11977): at android.os.HandlerThread.run(HandlerThread.java:67) E/CameraCaptureSession(11977): Caused by: android.os.ServiceSpecificException: cancelRequest:507: Camera 0: Error clearing streaming request: Function not implemented (-38) (code 10) E/CameraCaptureSession(11977): at android.os.Parcel.createExceptionOrNull(Parcel.java:2439) E/CameraCaptureSession(11977): at android.os.Parcel.createException(Parcel.java:2409) E/CameraCaptureSession(11977): at android.os.Parcel.readException(Parcel.java:2392) E/CameraCaptureSession(11977): at android.os.Parcel.readException(Parcel.java:2334) E/CameraCaptureSession(11977): at android.hardware.camera2.ICameraDeviceUser$Stub$Proxy.cancelRequest(ICameraDeviceUser.java:749) E/CameraCaptureSession(11977): at android.hardware.camera2.impl.ICameraDeviceUserWrapper.cancelRequest(ICameraDeviceUserWrapper.java:97) E/CameraCaptureSession(11977): ... 9 more I/Camera (11977): open | onDisconnected I/Camera (11977): close I/Camera (11977): open | onClosed
今度は「E/」のログが表示され、「CAMERA_ERROR (3)」という表示も出ている。
また、最後から3行目は「onDisconnected」に変わった。
■エラーパターン③
「Camera」パッケージのバージョンを思い切って下げたら(0.9.0より下)、以下のようなエラーになった。
D/EGL_emulation(12214): app_time_stats: avg=372.55ms min=79.65ms max=683.29ms count=3 E/CameraCaptureSession(12214): Session 0: Exception while stopping repeating: E/CameraCaptureSession(12214): android.hardware.camera2.CameraAccessException: CAMERA_ERROR (3): The camera device has encountered a serious error E/CameraCaptureSession(12214): at android.hardware.camera2.impl.CameraDeviceImpl.checkIfCameraClosedOrInError(CameraDeviceImpl.java:2350) E/CameraCaptureSession(12214): at android.hardware.camera2.impl.CameraDeviceImpl.stopRepeating(CameraDeviceImpl.java:1277) E/CameraCaptureSession(12214): at android.hardware.camera2.impl.CameraCaptureSessionImpl.close(CameraCaptureSessionImpl.java:579) E/CameraCaptureSession(12214): at io.flutter.plugins.camera.Camera.closeCaptureSession(Camera.java:1171) E/CameraCaptureSession(12214): at io.flutter.plugins.camera.Camera.close(Camera.java:1177) E/CameraCaptureSession(12214): at io.flutter.plugins.camera.Camera$1.onError(Camera.java:252) E/CameraCaptureSession(12214): at android.hardware.camera2.impl.CameraDeviceImpl.notifyError(CameraDeviceImpl.java:1748) E/CameraCaptureSession(12214): at android.hardware.camera2.impl.CameraDeviceImpl.$r8$lambda$KBQCqQRdhVVn7uHI9Xdha6OqnsU(Unknown Source:0) E/CameraCaptureSession(12214): at android.hardware.camera2.impl.CameraDeviceImpl$$ExternalSyntheticLambda0.accept(Unknown Source:8) E/CameraCaptureSession(12214): at com.android.internal.util.function.pooled.PooledLambdaImpl.doInvoke(PooledLambdaImpl.java:281) E/CameraCaptureSession(12214): at com.android.internal.util.function.pooled.PooledLambdaImpl.invoke(PooledLambdaImpl.java:204) E/CameraCaptureSession(12214): at com.android.internal.util.function.pooled.OmniFunction.run(OmniFunction.java:97) E/CameraCaptureSession(12214): at android.os.Handler.handleCallback(Handler.java:938) E/CameraCaptureSession(12214): at android.os.Handler.dispatchMessage(Handler.java:99) E/CameraCaptureSession(12214): at android.os.Looper.loopOnce(Looper.java:201) E/CameraCaptureSession(12214): at android.os.Looper.loop(Looper.java:288) E/CameraCaptureSession(12214): at android.app.ActivityThread.main(ActivityThread.java:7839) E/CameraCaptureSession(12214): at java.lang.reflect.Method.invoke(Native Method) E/CameraCaptureSession(12214): at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548) E/CameraCaptureSession(12214): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1003)
「E/」のログや「CAMERA_ERROR (3)」の他に、「The camera device has encountered a serious error」というメッセージも表示されている。
GitHubに複数のオープン中のイシューあり
「Androidで動かない」(適当に英単語化して検索)、「CAMERA_ERROR (3)」などのキーワードで検索すると、以下2つのイシューが見つかった。
いずれもまだオープン中。
1つ目のイシューは、iOSだと機能するが、Androidのエミュレーターだと機能しないとのことで、自分と似た状況。
2つのイシューを見ると、色々な報告があるようだが、やはりAPIレベル31以上のPixelのエミュレーターで発生する模様。
しかし、解決策は提示されていない。
2つ目のイシューでは、イシュー報告に多くの賛成票(グッドボタン)が投じられている。
「Camera」パッケージは、Flutter公式が開発していることも踏まえると、そのうち改善される可能性がありそう。
試しに、「targetSdkVersion」を上げたり、パッケージのバージョンを下げたりしてみたが、状況は変わらず(前述のとおり、若干エラーメッセージの表示が変わる程度)。。
APIレベル31(Android12)の実機では問題なく動いているので、エミュレーターで動かないうちは、仕方なく実機でテストすることにして、いったん本件は様子見。
(補足)「Camera.java」の内容
「onDisconnected」や「onError」の出力箇所を確認したいと思い、プロジェクト内を検索したところ、Javaで書かれた「Camera.java」というファイル内に書かれていた。
読んでみたが、エラーの発生条件は理解できず。。
ただし、ファイル内に、以下のようにAPIレベル31を境にした判定箇所がいくつかあった。
if (Build.VERSION.SDK_INT >= 31) { mediaRecorderBuilder = new MediaRecorderBuilder(getRecordingProfile(), outputFilePath); } else { mediaRecorderBuilder = new MediaRecorderBuilder(getRecordingProfileLegacy(), outputFilePath); }
どうやら録画関連の機能を使用する場合に、影響がある模様。
もしかすると、録画機能をOFFにすれば、エラーが解消されるかもしれない、と思い、「CameraController」の「enableAudio」プロパティをfalseにしてみた(デフォルトはtrue)が、残念ながら、結果は変わらず。。
いったん諦めて、引き続き、イシューをウォッチしていこう。
\一般的なエラー対処法をまとめた記事はこちら/
リリースしたアプリ(全てFlutterで開発)
個人アプリ開発で役立ったもの
おすすめの学習教材
\超初心者向けでオススメな元Udemyの講座/
\キャンペーン時を狙えば安価で網羅的な内容が学べる(日本語訳あり)/
\Gitの基礎について無料で学べる/
おすすめの学習書籍
\実用的。image_pickerに関してかなり助けられた/
\Dartの基礎文法を素早くインプットできる/