juliansteenbakker / mobile_scanner

A universal scanner for Flutter based on MLKit. Uses CameraX on Android and AVFoundation on iOS.
BSD 3-Clause "New" or "Revised" License
880 stars 510 forks source link

The Camera is still alive in background if the page pop while camera is starting #505

Open EArminjon opened 1 year ago

EArminjon commented 1 year ago

To reproduce :

Behavior : You will see the notification green badge which indicate that the camera is running in background despite the page is well poped (so high battery usage).

Expected behavior : Green toast should not appear or disappear automatically. Camera should not live if controller is well disposed.

Video :

untitled.webm

Code :

import 'package:flutter/material.dart';
import 'package:mobile_scanner/mobile_scanner.dart';

void main() => runApp(const MaterialApp(home: MyHome()));

class MyHome extends StatelessWidget {
  const MyHome({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Flutter Demo Home Page')),
      body: SizedBox(
        width: MediaQuery.of(context).size.width,
        height: MediaQuery.of(context).size.height,
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            ElevatedButton(
              onPressed: () {
                Navigator.of(context).push(
                  MaterialPageRoute<dynamic>(
                    builder: (BuildContext context) =>
                    const BarcodeScannerWithController(),
                  ),
                );
              },
              child: const Text('MobileScanner with Controller'),
            ),
          ],
        ),
      ),
    );
  }
}

class BarcodeScannerWithController extends StatefulWidget {
  const BarcodeScannerWithController({super.key});

  @override
  _BarcodeScannerWithControllerState createState() =>
      _BarcodeScannerWithControllerState();
}

class _BarcodeScannerWithControllerState
    extends State<BarcodeScannerWithController>
    with SingleTickerProviderStateMixin {
  BarcodeCapture? barcode;

  final MobileScannerController controller = MobileScannerController(
    torchEnabled: true,
    autoStart: true,
    // formats: [BarcodeFormat.qrCode]
    // facing: CameraFacing.front,
    // detectionSpeed: DetectionSpeed.normal
    // detectionTimeoutMs: 1000,
    // returnImage: false,
  );

  bool isStarted = true;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(controller.hashCode.toString()),
      ),
      backgroundColor: Colors.black,
      floatingActionButton: FloatingActionButton(
        child: const Icon(Icons.camera),
        onPressed: () async {
          await controller.stop();
          await Navigator.of(context).push(
            MaterialPageRoute<dynamic>(
              builder: (BuildContext context) =>
              const BarcodeScannerWithController(),
            ),
          );
          await controller.start();
        },
      ),
      body: Builder(
        builder: (BuildContext context) {
          return Stack(
            children: <Widget>[
              MobileScanner(
                startDelay: true,
                controller: controller,
                errorBuilder: (
                    BuildContext context,
                    MobileScannerException error,
                    Widget? child,
                    ) {
                  return ScannerErrorWidget(error: error);
                },
                fit: BoxFit.contain,
                onDetect: (BarcodeCapture barcode) {
                  setState(() {
                    this.barcode = barcode;
                  });
                },
              ),
            ],
          );
        },
      ),
    );
  }

  @override
  void dispose() {
    controller.dispose();
    super.dispose();
  }
}

class ScannerErrorWidget extends StatelessWidget {
  const ScannerErrorWidget({super.key, required this.error});

  final MobileScannerException error;

  @override
  Widget build(BuildContext context) {
    String errorMessage;

    switch (error.errorCode) {
      case MobileScannerErrorCode.controllerUninitialized:
        errorMessage = 'Controller not ready.';
        break;
      case MobileScannerErrorCode.permissionDenied:
        errorMessage = 'Permission denied';
        break;
      default:
        errorMessage = 'Generic Error';
        break;
    }

    return ColoredBox(
      color: Colors.black,
      child: Center(
        child: Column(
          mainAxisSize: MainAxisSize.min,
          children: [
            const Padding(
              padding: EdgeInsets.only(bottom: 16),
              child: Icon(Icons.error, color: Colors.white),
            ),
            Text(
              errorMessage,
              style: const TextStyle(color: Colors.white),
            ),
          ],
        ),
      ),
    );
  }
}

Flutter doctor -v

[✓] Flutter (Channel stable, 3.3.9, on macOS 13.1 22C65 darwin-arm, locale fr-FR)
    • Flutter version 3.3.9 on channel stable at /Users/earminjon/fvm/versions/3.3.9
    • Upstream repository https://github.com/flutter/flutter.git
    • Framework revision b8f7f1f986 (3 months ago), 2022-11-23 06:43:51 +0900
    • Engine revision 8f2221fbef
    • Dart version 2.18.5
    • DevTools version 2.15.0

[✓] Android toolchain - develop for Android devices (Android SDK version 33.0.2)
    • Android SDK at /Users/earminjon/Library/Android/Sdk
    • Platform android-33, build-tools 33.0.2
    • ANDROID_HOME = /Users/earminjon/Library/Android/Sdk
    • Java binary at: /Users/earminjon/Library/Java/JavaVirtualMachines/corretto-11.0.17/Contents/Home/bin/java
    • Java version OpenJDK Runtime Environment Corretto-11.0.17.8.1 (build 11.0.17+8-LTS)
    • All Android licenses accepted.

[✓] Xcode - develop for iOS and macOS (Xcode 14.2)
    • Xcode at /Applications/Xcode.app/Contents/Developer
    • Build 14C18
    • CocoaPods version 1.11.3

[✓] Chrome - develop for the web
    • Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome

[!] Android Studio (version 2022.1)
    • Android Studio at /Users/earminjon/Library/Application Support/JetBrains/Toolbox/apps/AndroidStudio/ch-0/221.6008.13.2211.9514443/Android Studio.app/Contents
    • Flutter plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/9212-flutter
    • Dart plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/6351-dart
    ✗ Unable to find bundled Java version.
    • Try updating or re-installing Android Studio.

[✓] IntelliJ IDEA Ultimate Edition (version 2022.3.2)
    • IntelliJ at /Users/earminjon/Applications/JetBrains Toolbox/IntelliJ IDEA Ultimate.app
    • Flutter plugin version 72.1.4
    • Dart plugin version 223.8617.8

[✓] IntelliJ IDEA Ultimate Edition (version 2022.3.2)
    • IntelliJ at /Users/earminjon/Library/Application Support/JetBrains/Toolbox/apps/IDEA-U/ch-0/223.8617.56/IntelliJ IDEA.app
    • Flutter plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/9212-flutter
    • Dart plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/6351-dart

[✓] Connected device (3 available)
    • sdk gphone64 arm64 (mobile) • emulator-5554 • android-arm64  • Android 13 (API 33) (emulator)
    • macOS (desktop)             • macos         • darwin-arm64   • macOS 13.1 22C65 darwin-arm
    • Chrome (web)                • chrome        • web-javascript • Google Chrome 109.0.5414.119

[✓] HTTP Host Availability
    • All required HTTP hosts are available

! Doctor found issues in 1 category.
EArminjon commented 1 year ago

Maybe once fixed it will help following issue :

EArminjon commented 1 year ago

I am having the same issue. Has anyone found a fix?

@BBQRIBS72 , @junko2013 Issue created 2 days ago :') You can upvote original post to avoid spamming. If someone know how to resolve this, he will post don't worry !

junko2013 commented 1 year ago

the same issue

c-seeger commented 1 year ago

me too

manishvill commented 9 months ago

Please check fix here https://github.com/juliansteenbakker/mobile_scanner/issues/619#issuecomment-1918405545

navaronbracke commented 8 months ago

@EArminjon With the new beta release, version 5.0.0-beta.1 , we removed the manual lifecycle management in mobile_scanner itself, as it caused issues with widget tree reparenting.

Now that you have full control over the lifecycle, this issue should no longer occur?

EArminjon commented 4 months ago

With latest version i can well manage with some tricks multiples scanners lifecycle (https://github.com/juliansteenbakker/mobile_scanner/issues/1002#issuecomment-2156693406) and so this issue.

As it's 'tricky' and required an other package 'visibility_detector' i didn't know if i can close this issue :/

navaronbracke commented 4 months ago

When you leave the page, does that page call its dispose method?

You also do not await the disposal?

  @override
  Future<void> dispose() async {
    super.dispose(); // If dispose is async, the super call has to happen before any awaits. Otherwise the framework asserts
    await controller.dispose();
  }