PriyanshuG
PriyanshuG

Reputation: 145

Unable to select image using Image Picker on Flutter Web (MissingPluginException)

Below I'm sharing my flutter code that simply selects an Image and displays it on screen after taking the required permissions. The code, however, runs fine on Android but gives a MissingPluginException(No implementation found for method requestPermissions on channel flutter.baseflow.com/permissions/methods) exception when I try to upload image on web.

import 'dart:io';

import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:permission_handler/permission_handler.dart';

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

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Project2',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  @override
  createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  File _file = File("zz");

  uploadImage() async {
    final ImagePicker _picker = ImagePicker();
    final XFile? image;

    var permissionStatus = requestPermissions();
    if (await permissionStatus.isGranted) {
      image = await _picker.pickImage(source: ImageSource.gallery);
      var selected = File(image!.path);

      setState(() {
        _file = selected;
      });
    } else {
      showToast("Permission not granted");
    }
  }

  Future<PermissionStatus> requestPermissions() async {
    await Permission.photos.request();
    return Permission.photos.status;
  }

  void showToast(String message) {
    Fluttertoast.showToast(
      msg: message,
      toastLength: Toast.LENGTH_SHORT,
      gravity: ToastGravity.BOTTOM,
      timeInSecForIosWeb: 1,
      backgroundColor: Colors.red,
      textColor: Colors.white,
      fontSize: 16.0,
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Upload Image"),
      ),
      body: Column(
        children: [
          (_file.path != "zz")
              ? Image.file(_file)
              : Image.asset("assets/img/images.jpeg"),
          SizedBox(
            height: 20,
            width: double.infinity,
          ),
          ElevatedButton(
            onPressed: () => uploadImage(),
            child: Text("Upload"),
          )
        ],
      ),
    );
  }
}

Following is the generated stacktrace on pressing upload button:

Error: MissingPluginException(No implementation found for method requestPermissions on channel flutter.baseflow.com/permissions/methods)
    at Object.throw_ [as throw] (http://localhost:64931/dart_sdk.js:5041:11)
    at MethodChannel._invokeMethod (http://localhost:64931/packages/flutter/src/services/system_channels.dart.lib.js:943:21)
    at _invokeMethod.next (<anonymous>)
    at http://localhost:64931/dart_sdk.js:37403:33
    at _RootZone.runUnary (http://localhost:64931/dart_sdk.js:37274:59)
    at _FutureListener.thenAwait.handleValue (http://localhost:64931/dart_sdk.js:32530:29)
    at handleValueCallback (http://localhost:64931/dart_sdk.js:33057:49)
    at Function._propagateToListeners (http://localhost:64931/dart_sdk.js:33095:17)
    at _Future.new.[_completeWithValue] (http://localhost:64931/dart_sdk.js:32943:23)
    at async._AsyncCallbackEntry.new.callback (http://localhost:64931/dart_sdk.js:32964:35)
    at Object._microtaskLoop (http://localhost:64931/dart_sdk.js:37526:13)
    at _startMicrotaskLoop (http://localhost:64931/dart_sdk.js:37532:13)
    at http://localhost:64931/dart_sdk.js:33303:9

pubspec.yaml file:

environment:
  sdk: ">=2.12.0 <3.0.0"

dependencies:
  flutter:
    sdk: flutter
  image_picker: ^0.8.3+3
  permission_handler: ^8.1.4+2
  fluttertoast: ^8.0.8

  cupertino_icons: ^1.0.2

dev_dependencies:
  flutter_test:
    sdk: flutter


flutter:
  uses-material-design: true

  assets:
    - assets/img/images.jpeg

PS: flutter clean and flutter run isn't working for Web version.

Upvotes: 3

Views: 15124

Answers (2)

Manash
Manash

Reputation: 11

Here is the code that helps to upload for both web and mobile without using any conditional imports. This is from the image_picker package in flutter. This also returns the size of the image. 

    Future<void> pickImageForMobileAndWeb()async{
  final ImagePicker picker = ImagePicker();
  // This picks file for both mobile and web platforms
  final XFile? pickedFile = await picker.pickImage(
    source: ImageSource.gallery,
    imageQuality: 100,
  );

  // Defining the required size for image upload
  const int maxFileSizeInBytes = 5 * 1048; // This equals to 5MB of Size

  if (pickedFile != null) {
    final Uint8List imageByte = await pickedFile.readAsBytes(); //
    final int fileSize =
        imageByte.length; //Getting the file size of the file uploaded
    if (fileSize < maxFileSizeInBytes) {
      //show snackbar with message 'File size should be 5mb or less'
      return;
    } else {
      final String imageBase64String = base64Encode(
          imageByte); // Encoding the list of byte i.e imageBytes to base64 String
      

      // Sending the trimmed base64 string to server for validation
     // send the base64 string for validation to server. 

      final bool isValidImageFile = apiResponseForFileType[
          'valid_file']; //Response from the server after validation

      if (isValidImageFile) {
        //Do your actions
        // To pass to another screen 
// YourClassName(base64String : imageBase64String )

      } else {
        print('Not valid file or Image')
      }
    }
  } else {
   // Navigate safely to required screen
  }
}

Upvotes: 0

PriyanshuG
PriyanshuG

Reputation: 145

The problem is with the permissions handler package in Web. Permissions Handler package is built only for Android and IOS, and no permission is required to upload image on Web Platform, so using it on Web gives MissingPluginException.

The problem was resolved by adding conditional statements and separate implementations for Web And Mobile Platforms.

To check if the platform is web, you first need to add:

import 'package:flutter/foundation.dart' show kIsWeb;

Change the uploadImage() method as:

  uploadImage() async {
    var permissionStatus = requestPermissions();

    // MOBILE
    if (!kIsWeb && await permissionStatus.isGranted) {
      final ImagePicker _picker = ImagePicker();
      XFile? image = await _picker.pickImage(source: ImageSource.gallery);

      if (image != null) {
        var selected = File(image.path);

        setState(() {
          _file = selected;
        });
      } else {
        showToast("No file selected");
      }
    }
    // WEB
    else if (kIsWeb) {
      final ImagePicker _picker = ImagePicker();
      XFile? image = await _picker.pickImage(source: ImageSource.gallery);
      if (image != null) {
        var f = await image.readAsBytes();
        setState(() {
          _file = File("a");
          webImage = f;
        });
      } else {
        showToast("No file selected");
      }
    } else {
      showToast("Permission not granted");
    }
  }

And then finally add seperate implementations for Web and Android Image in build() method:

  File _file = File("zz");
  Uint8List webImage = Uint8List(10);
@override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Upload Image"),
      ),
      body: Column(
        children: [
          (_file.path == "zz")
              ? Image.asset("assets/img/images.jpeg")
              : (kIsWeb)
                  ? Image.memory(webImage)
                  : Image.file(_file),
          SizedBox(
            height: 20,
            width: double.infinity,
          ),
          ElevatedButton(
            onPressed: () => uploadImage(),
            child: Text("Upload"),
          )
        ],
      ),
    );
  }

Upvotes: 8

Related Questions