Description
When running the sample code with basic feature, the functionality works fine on Android. However, on iOS, after navigating back and forth to the same page multiple times, the camera sometimes works as expected. Other times, it fails and throws the following error:
======== Exception caught by services library ======================================================
The following MissingPluginException was thrown while activating platform stream on channel plugins.flutter.io/camera_avfoundation/imageStream:
MissingPluginException(No implementation found for method listen on channel plugins.flutter.io/camera_avfoundation/imageStream)
When the exception was thrown, this was the stack:
#0 MethodChannel._invokeMethod (package:flutter/src/services/platform_channel.dart:368:7)
<asynchronous suspension>
#1 EventChannel.receiveBroadcastStream.<anonymous closure> (package:flutter/src/services/platform_channel.dart:715:11)
<asynchronous suspension>
my full code is below
import 'package:camera/camera.dart';
import 'package:flutter/material.dart';
import 'package:google_mlkit_object_detection/google_mlkit_object_detection.dart';
import 'detector_view.dart';
import 'painters/object_detector_painter.dart';
import 'utils.dart';
class ObjectDetectorView extends StatefulWidget {
@override
State<ObjectDetectorView> createState() => _ObjectDetectorView();
}
class _ObjectDetectorView extends State<ObjectDetectorView> {
ObjectDetector? _objectDetector;
DetectionMode _mode = DetectionMode.stream;
bool _canProcess = false;
bool _isBusy = false;
CustomPaint? _customPaint;
String? _text;
var _cameraLensDirection = CameraLensDirection.back;
@override
void dispose() {
_canProcess = false;
_objectDetector?.close();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Stack(children: [
DetectorView(
title: 'Object Detector',
customPaint: _customPaint,
text: _text,
onImage: _processImage,
initialCameraLensDirection: _cameraLensDirection,
onCameraLensDirectionChanged: (value) => _cameraLensDirection = value,
onCameraFeedReady: _initializeDetector,
initialDetectionMode: DetectorViewMode.values[_mode.index],
onDetectorViewModeChanged: _onScreenModeChanged,
),
]),
);
}
void _onScreenModeChanged(DetectorViewMode mode) {
switch (mode) {
case DetectorViewMode.gallery:
_mode = DetectionMode.single;
_initializeDetector();
return;
case DetectorViewMode.liveFeed:
_mode = DetectionMode.stream;
_initializeDetector();
return;
}
}
void _initializeDetector() async {
_objectDetector?.close();
_objectDetector = null;
print('Set detector in mode: $_mode');
// Use object_labeler.tflite model
final modelPath = await getAssetPath('assets/ml/object_labeler.tflite');
print('use custom model path: $modelPath');
final options = LocalObjectDetectorOptions(
mode: _mode,
modelPath: modelPath,
classifyObjects: true,
multipleObjects: true,
);
_objectDetector = ObjectDetector(options: options);
_canProcess = true;
}
Future<void> _processImage(InputImage inputImage) async {
if (_objectDetector == null) return;
if (!_canProcess) return;
if (_isBusy) return;
_isBusy = true;
setState(() {
_text = '';
});
final objects = await _objectDetector!.processImage(inputImage);
// print('Objects found: ${objects.length}\n\n');
if (inputImage.metadata?.size != null &&
inputImage.metadata?.rotation != null) {
final painter = ObjectDetectorPainter(
objects,
inputImage.metadata!.size,
inputImage.metadata!.rotation,
_cameraLensDirection,
);
_customPaint = CustomPaint(painter: painter);
} else {
String text = 'Objects found: ${objects.length}\n\n';
for (final object in objects) {
text +=
'Object: trackingId: ${object.trackingId} - ${object.labels.map((e) => e.text)}\n\n';
}
_text = text;
// TODO: set _customPaint to draw boundingRect on top of image
_customPaint = null;
}
_isBusy = false;
if (mounted) {
setState(() {});
}
}
}
Steps to reproduce.
Run the sample app on an iOS device.
Navigate to the page that initializes the camera.
Navigate away from the page and return multiple times.
Observe that sometimes the camera works, and other times it throws the MissingPluginException.
What is the expected result?
The camera should initialize correctly every time the page is visited without throwing an exception.
Did you try our example app?
Yes
Is it reproducible in the example app?
Yes
Reproducible in which OS?
iOS
Flutter/Dart Version?
[✓] Flutter (Channel stable, 3.29.0, on macOS 15.3.2 24D81 darwin-x64, locale en-US)
[✓] Android toolchain - develop for Android devices (Android SDK version 34.0.0)
[✓] Xcode - develop for iOS and macOS (Xcode 16.2)
[✓] Chrome - develop for the web
[✓] Android Studio (version 2024.2)
[✓] VS Code (version 1.98.0)
Plugin Version?
83.0.3