Flutter: ImagePicker: await picker.pickImage(source: ImageSource.gallery) doesn't return

Viewed 835

When I triggers the pickimage function, it pops up the gallery view to select an image. And when I choose an image, the app returns to app view. But the pickimage function doesn't return, and hangs forever. Here's my code:


import 'package:flutter/material.dart';
import 'dart:async';
import 'dart:io';

import 'package:flutter/foundation.dart';
import 'package:google_ml_kit/google_ml_kit.dart';
import 'package:image_picker/image_picker.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const MyHomePage(title: 'Text Scanning Demo'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({Key? key, required this.title}) : super(key: key);
  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {

  late String result;
  File? _image;
  InputImage? inputImage;
  final ImagePicker picker = ImagePicker();

  Future pickImageFromGallery() async {
    print("starting get image");
    final XFile? pickedFile = await picker.pickImage(source: ImageSource.gallery);
    //final pickedFile = await picker.pickImage(source: ImageSource.gallery);
    print("getting image.....");
    setState(() {
      if (pickedFile != null) {
        print("file not null");
        _image = File(pickedFile.path);
        inputImage = InputImage.fromFilePath(pickedFile.path);

        imageToText(inputImage);
      } else {
        print('No image selected.');
      }
    });
  }

  Future captureImageFromCamera() async {
    final pickedFile = await picker.pickImage(source: ImageSource.camera);
    setState(() {
      if (pickedFile != null) {
        _image = File(pickedFile.path);
        inputImage = InputImage.fromFilePath(pickedFile.path);
        imageToText(inputImage);
      } else {
        print('No image selected.');
      }
    });
  }

  Future imageToText(inputImage) async {
    print("starting");
    result = '';

    final textDetector = GoogleMlKit.vision.textDetector();
    print("loaded textDetector");
    final RecognisedText recognisedText = await textDetector.processImage(inputImage);
    print("loaded recognisedText");

    setState(() {
      String text = recognisedText.text;
      for (TextBlock block in recognisedText.blocks) {
        //each block of text/section of text
        final String text = block.text;
        print("block of text: ");
        print(text);
        for (TextLine line in block.lines) {
          //each line within a text block
          for (TextElement element in line.elements) {
            //each word within a line
            result += element.text + " ";
          }
        }
      }
      result += "\n\n";
    });
  }


  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Row(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Container(
              width: 100,
              child: TextField(
                textAlign: TextAlign.center,
                style: TextStyle(color: Colors.black),
              ),
            ),
            Container(
                height: 70,
                width: 150,
                child: TextButton(
                  style: TextButton.styleFrom(
                    primary: Colors.blue,
                  ),
                  onPressed: () {
                    pickImageFromGallery();
                  },
                  child: Text('Pick Image'),
                ))
          ],
        ),
      ),
      // This trailing comma makes auto-formatting nicer for build methods.
    );
  }
}

Here's my pubspec.yaml

name: text_scanning
description: A new Flutter project.


publish_to: 'none' # Remove this line if you wish to publish to pub.dev

version: 1.0.0+1

environment:
  sdk: ">=2.14.0-0 <3.0.0"


dependencies:
  flutter:
    sdk: flutter
  font_awesome_flutter: ^9.0.0
  splash_screen_view: ^3.0.0
  cupertino_icons: ^1.0.2
  google_ml_kit: ^0.7.3
  image_picker: ^0.8.1+1

dev_dependencies:
  flutter_test:
    sdk: flutter

  flutter_lints: ^1.0.0


flutter:

  uses-material-design: true

Here's podfile

# Uncomment this line to define a global platform for your project
platform :ios, '10.0'

# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
ENV['COCOAPODS_DISABLE_STATS'] = 'true'

project 'Runner', {
  'Debug' => :debug,
  'Profile' => :release,
  'Release' => :release,
}

def flutter_root
  generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__)
  unless File.exist?(generated_xcode_build_settings_path)
    raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first"
  end

  File.foreach(generated_xcode_build_settings_path) do |line|
    matches = line.match(/FLUTTER_ROOT\=(.*)/)
    return matches[1].strip if matches
  end
  raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get"
end

require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root)

flutter_ios_podfile_setup

target 'Runner' do
  use_frameworks!
  use_modular_headers!

  flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
  pod 'GoogleMLKit/TextRecognition'
  pod 'Firebase'
end

post_install do |installer|
  # add these lines:
  installer.pods_project.build_configurations.each do |config|
    config.build_settings["EXCLUDED_ARCHS[sdk=*]"] = "armv7"
    config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = $iOSVersion
  end

  installer.pods_project.targets.each do |target|
    flutter_additional_ios_build_settings(target)

    # add these lines:
    target.build_configurations.each do |config|
      if Gem::Version.new($iOSVersion) > Gem::Version.new(config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'])
        config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = $iOSVersion
      end
    end
  end
end

Here's screenshot of my Info from xcode: [note the privacy for gallery and camera][1]

I am at my wits end here, I followed every documentation, and it just doesn't even produce any error, and just hangs there. [1]: https://i.stack.imgur.com/XC6aP.png

1 Answers

Are you running this code on an iOS Simulator on an ARM based Mac (M1 / M1 Pro)? If so, then the problem probably stems from a current bug in the iOS Simulator which only seems to reproduce when running with Rosetta translation (read more here, and here).

In your case, the pubspec.yaml file states google_ml_kit as a dependency, which forces the app to run using Rosetta, which in turn breaks the image_picker plugin.

Apple will probably fix this some time in the future, but in the meanwhile, you can workaround this issue by either running your app on a physical iOS device, or using an iOS Simulator with iOS version < 14.

To do so:

  1. Open up Xcode
  2. Go to Preferences.
  3. Select the "Components" tab.
  4. Mark the simulators you want.
  5. Press "Check and Install Now".

Then:

  1. Open up the Simulator app.
  2. Select File > New Simulator
  3. Select your device of choice, and make sure to select an iOS version < 14.
Related