Flutter Image Picker Crash

Viewed 13893

I want to ask if you ever encounter the app being crash right after selecting an image from the gallery/camera using image_picker plugin version 0.6.3+4 on Android? Already searching for an answer for 1 week and no answer can help me, because I think it's my project that has some compatibility problems.

Here is my case. On my original project, the app always crashes right after selecting an image from the gallery/camera, but if I use the plugin to a new clean project with just only one button with onPress function to select the image, it works, no crash happens.

So maybe I think there's something inside my original project that makes this crash happens. Here is the code about how I use the image_picker

  imageSelectorGallery() async {
    fileProfilePicture = await ImagePicker.pickImage(
      source: ImageSource.gallery,
    );

    if(fileProfilePicture != null) {
      setState(() {
        uploadPicture();
      });
    }
  }

And the function is called by this widget

new GestureDetector(
  onTap: () { 
    imageSelectorGallery();
  },
  child: new Container(
    child: new Column(
      children: <Widget>[
        new Container(
          width: 50,
          height: 50,
          decoration: BoxDecoration(
            color: Colors.blue,
            shape: BoxShape.circle,
          ),
          child: new Icon(
            FontAwesomeIcons.image,
            size: 22.0,
            color: Colors.white
          ),
        ),
        new Padding(padding: EdgeInsets.symmetric(vertical: 3.0)),
        new Text(
          "Gallery",
          style: new TextStyle(
            color: Colors.black,
            fontSize: 12.0,
          ),
        ),
      ],
    ),
  ),
)

of course, there's a camera button that called another similar function for taking an image from the camera, but I think it'll be too long for a question if I'm adding it, besides both of them are causing the same crash.

and here is the list of my plugins that I used inside the project, I don't know if there's some plugin that can't be used together or not, but I hope this can make my question clearer.

  http: ^0.12.0+2
  font_awesome_flutter: ^8.5.0
  flutter_calendar_carousel: 1.3.16
  bubble_tab_indicator: "^0.1.4"
  chewie: ^0.9.7
  video_player: ^0.10.1+3
  toast: ^0.1.3
  shimmer: ^1.0.0
  flutter_responsive_screen: ^1.0.0
  flutter_webview_plugin: ^0.3.7
  webview_flutter: ^0.3.19+8
  audioplayer: 0.5.2
  image_picker: ^0.6.3+4
  shared_preferences: ^0.5.3+4
  sticky_headers: "^0.1.8"
  flutter_speed_dial: ^1.2.1
  url_launcher: ^5.1.2
  image_picker_saver: ^0.3.0
  smooth_star_rating: ^1.0.3
  flutter_secure_storage: ^3.3.1+1
  flutter_datetime_picker: ^1.2.8
  flutter_launcher_icons: "^0.7.3"
  youtube_player: ^3.5.0
  youtube_player_flutter: ^6.0.3+2
  wakelock: ^0.1.3+4

and here is the log right before the gallery opened until after the app crash.

D/ViewRootImpl@e8d5055[MainActivity](19819): ViewPostIme pointer 0
D/ViewRootImpl@e8d5055[MainActivity](19819): ViewPostIme pointer 1
D/ViewRootImpl@e8d5055[MainActivity](19819): MSG_WINDOW_FOCUS_CHANGED 0 1
D/InputMethodManager(19819): prepareNavigationBarInfo() DecorView@7634a6a[MainActivity]
D/InputMethodManager(19819): getNavigationBarColor() -855310
D/SurfaceView(19819): onWindowVisibilityChanged(8) false io.flutter.embedding.android.FlutterSurfaceView{9f9cd1 V.E...... ........ 0,0-1080,1920} of ViewRootImpl@e8d5055[MainActivity]
D/SurfaceView(19819): show() Surface(name=SurfaceView - com.example.test_new_image_picker/com.example.test_new_image_picker.MainActivity@9f9cd1@1[19819])/@0x7cc5bde io.flutter.embedding.android.FlutterSurfaceView{9f9cd1 V.E...... ........ 0,0-1080,1920}
D/SurfaceView(19819): surfaceDestroyed callback.size 1 #2 io.flutter.embedding.android.FlutterSurfaceView{9f9cd1 V.E...... ........ 0,0-1080,1920}
W/libEGL  (19819): EGLNativeWindowType 0xd622b808 disconnect failed
D/SurfaceView(19819): destroy() Surface(name=SurfaceView - com.example.test_new_image_picker/com.example.test_new_image_picker.MainActivity@9f9cd1@1[19819])/@0x7cc5bde io.flutter.embedding.android.FlutterSurfaceView{9f9cd1 V.E...... ........ 0,0-1080,1920}
W/libEGL  (19819): EGLNativeWindowType 0xd622b008 disconnect failed
D/OpenGLRenderer(19819): eglDestroySurface = 0xf0c74920, 0xd622b000
D/ViewRootImpl@e8d5055[MainActivity](19819): Relayout returned: old=[0,0][1080,1920] new=[0,0][1080,1920] result=0x5 surface={false 0} changed=true
D/InputTransport(19819): Input channel destroyed: fd=95
D/ViewRootImpl@e8d5055[MainActivity](19819): stopped(true) old=false
D/SurfaceView(19819): windowStopped(true) false io.flutter.embedding.android.FlutterSurfaceView{9f9cd1 V.E...... ........ 0,0-1080,1920} of ViewRootImpl@e8d5055[MainActivity]
D/FlutterView(19819): Detaching from a FlutterEngine: io.flutter.embedding.engine.FlutterEngine@53149bd
D/SurfaceView(19819): onWindowVisibilityChanged(4) false io.flutter.embedding.android.FlutterSurfaceView{9f9cd1 V.E...... .......D 0,0-1080,1920} of ViewRootImpl@e8d5055[MainActivity]
D/ViewRootImpl@e8d5055[MainActivity](19819): Relayout returned: old=[0,0][1080,1920] new=[0,0][1080,1920] result=0x1 surface={false 0} changed=false
D/AndroidRuntime(19819): Shutting down VM
E/AndroidRuntime(19819): FATAL EXCEPTION: main
E/AndroidRuntime(19819): Process: com.example.test_new_image_picker, PID: 19819
E/AndroidRuntime(19819): java.lang.RuntimeException: Failure delivering result ResultInfo{who=null, request=2342, result=-1, data=Intent { dat=content://com.android.providers.media.documents/document/image:8411 flg=0x1 }} to activity {com.example.test_new_image_picker/com.example.test_new_image_picker.MainActivity}: java.lang.IllegalStateException: Received image from picker that was not requested
E/AndroidRuntime(19819):        at android.app.ActivityThread.deliverResults(ActivityThread.java:4643)
E/AndroidRuntime(19819):        at android.app.ActivityThread.handleSendResult(ActivityThread.java:4685)
E/AndroidRuntime(19819):        at android.app.servertransaction.ActivityResultItem.execute(ActivityResultItem.java:49)
E/AndroidRuntime(19819):        at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108)
E/AndroidRuntime(19819):        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68)
E/AndroidRuntime(19819):        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1970)
E/AndroidRuntime(19819):        at android.os.Handler.dispatchMessage(Handler.java:106)
E/AndroidRuntime(19819):        at android.os.Looper.loop(Looper.java:214)
E/AndroidRuntime(19819):        at android.app.ActivityThread.main(ActivityThread.java:7156)
E/AndroidRuntime(19819):        at java.lang.reflect.Method.invoke(Native Method)
E/AndroidRuntime(19819):        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:494)
E/AndroidRuntime(19819):        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:975)
E/AndroidRuntime(19819): Caused by: java.lang.IllegalStateException: Received image from picker that was not requested
E/AndroidRuntime(19819):        at io.flutter.plugins.imagepickersaver.ImagePickerDelegate.handleImageResult(ImagePickerDelegate.java:495)
E/AndroidRuntime(19819):        at io.flutter.plugins.imagepickersaver.ImagePickerDelegate.handleChooseImageResult(ImagePickerDelegate.java:434)
E/AndroidRuntime(19819):        at io.flutter.plugins.imagepickersaver.ImagePickerDelegate.onActivityResult(ImagePickerDelegate.java:413)
E/AndroidRuntime(19819):        at io.flutter.embedding.engine.FlutterEnginePluginRegistry$FlutterEngineActivityPluginBinding.onActivityResult(FlutterEnginePluginRegistry.java:634)
E/AndroidRuntime(19819):        at io.flutter.embedding.engine.FlutterEnginePluginRegistry.onActivityResult(FlutterEnginePluginRegistry.java:367)
E/AndroidRuntime(19819):        at io.flutter.embedding.android.FlutterActivityAndFragmentDelegate.onActivityResult(FlutterActivityAndFragmentDelegate.java:546)
E/AndroidRuntime(19819):        at io.flutter.embedding.android.FlutterActivity.onActivityResult(FlutterActivity.java:594)
E/AndroidRuntime(19819):        at android.app.Activity.dispatchActivityResult(Activity.java:7791)
E/AndroidRuntime(19819):        at android.app.ActivityThread.deliverResults(ActivityThread.java:4636)
E/AndroidRuntime(19819):        ... 11 more
I/Process (19819): Sending signal. PID: 19819 SIG: 9
Lost connection to device.

and I'm using minSdk 21 and targetSdk 28 on the build.gradle, and I use all this permission on my AndroidManifest

    <uses-permission android:name="android.permission.INTERNET"/>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.CAMERA"/>
    <uses-permission android:name="android.hardware.camera.autofocus"/>
    <uses-permission android:name="android.permission.WAKE_LOCK"/>

So anyone who knows about this problem and how to fix it please tell me, thank you. Really appreciate it. :)

11 Answers

found out the problem, with the latest version of Flutter on stable channel 1.12.13+hotfix.9, you can't use plugin image_picker and image_picker_saver together, still don't know why, but you can add a comment to this answer if you know about it, thanks.

The problem with using the plugin permission_handler is iOS will complain about .plist info. Until you are certain about multiple permission like camera, calendar, contacts etc... I would not prefer to use this.

This is how i did -

checkAndRequestCameraPermissions() async {
    final picker = ImagePicker();
    try {
      final image = await picker.getImage(
        source: ImageSource.camera,
        imageQuality: 75,
        maxHeight: 300,
        maxWidth: 400,
      );
    } catch (e) {
      print(e.code);
    }
  }

you can check for exception code in your catch bloc like e.code == 'camera_access_denied' then you can prompt user about enabling it from device Settings, on Android it ask anyway all time if it is not granted/disabled.

by adding preferredCameraDevice: CameraDevice.rear in pickImage worked for me. also add the android:requestLegacyExternalStorage="true" in AndroidManifest.xml

image_picker plugin does not support permissions condition anymore. For instance, when we try to access camera from an app, the app asks us for permission. Now, since image_picker plugin has removed that condition, we need to ask the permission manually using permission_handler plugin. Read more details about this change here

Use this plugin to add the request manually i.e on runtime and you should be able to get rid of this crash.

Sample Code:

  // get permissions
  Future<PermissionStatus> _getPermission(perm) async {
    PermissionStatus permission = await PermissionHandler()
        .checkPermissionStatus(perm);
    if (permission != PermissionStatus.granted &&
        permission != PermissionStatus.disabled) {
      Map<PermissionGroup, PermissionStatus> permisionStatus =
      await PermissionHandler()
          .requestPermissions([perm]);
      return permisionStatus[perm] ??
          PermissionStatus.unknown;
    } else {
      print(permission);
      return permission;
    }
  }

  Future selectGallery() async {
    // check permission
    PermissionStatus permissionStatus = await _getPermission(PermissionGroup.photos);
    if (permissionStatus == PermissionStatus.granted) {
      var image = await ImagePicker.pickImage(source: ImageSource.gallery);
      setState(() {
        accessDenied = false;
        // do your work
      });
    } else {
      accessDenied = true;
      setState(() {});
      throw PlatformException(
        code: 'PERMISSION_DENIED',
        message: 'Access to location data denied',
        details: null,
      );
    }    
  }

  Future selectCamera() async {
    // check permission
    PermissionStatus permissionStatus = await _getPermission(PermissionGroup.camera);
    print(permissionStatus);
    if (permissionStatus == PermissionStatus.granted) {
      var image = await ImagePicker.pickImage(source: ImageSource.camera);
      setState(() {
        accessDenied = false;
        // do your work
      });
    } else {
      accessDenied = true;
      setState(() {});
      throw PlatformException(
        code: 'PERMISSION_DENIED',
        message: 'Access to location data denied',
        details: null,
      );
    }
  }

I solved it, you just need to add camera permission in Info.plist file

<key>NSPhotoLibraryUsageDescription</key>
<string>App needs access to photo lib for profile images</string>
<key>NSCameraUsageDescription</key>
<string>To capture profile photo please grant camera access</string>

Don´t forget to add permissions in Info.plist for iOS (NSPhotoLibraryUsageDescription, NSCameraUsageDescription and NSMicrophoneUsageDescription), and android:requestLegacyExternalStorage="true" for AndroidManifest.xml

in case of iOS 14 or later using image picker with InkWell causes the app to crash on the second image selection , [image_picker: 0.6.7+22, flutter:1.22.6], this can be avoided by using GestureDector rather than Inkwell to open the picker

Add this in info.plist

<key>NSPhotoLibraryUsageDescription</key> <string>This app requires access to the photo library.</string>

<key>NSMicrophoneUsageDescription</key> <string>This app does not require access to the microphone.</string>

<key>NSCameraUsageDescription</key> <string>This app requires access to the camera.</string>

use get Imagepicker.getImage instead of ImagePicker.pickImage

Related