dart 无法使用Flutter Web上的Image Picker选择图像(MissingPluginException)

iecba09b  于 2023-10-13  发布在  Flutter
关注(0)|答案(2)|浏览(183)

下面我分享我的Flutter代码,只需选择一个图像,并在获得所需的权限后将其显示在屏幕上。然而,代码在Android上运行良好,但当我尝试在Web上上传图像时,会出现MissingPluginException(No implementation found for method requestPermissions on channel flutter.baseflow.com/permissions/methods)异常。

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"),
          )
        ],
      ),
    );
  }
}

以下是按下upload按钮时生成的堆栈跟踪:

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文件:

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 cleanflutter run不适用于Web版本。

n53p2ov0

n53p2ov01#

问题出在Web中的权限处理程序包。Permissions Handler包只为Android和IOS构建,在Web平台上上传图片不需要权限,所以在Web上使用它会得到MissingPluginException
通过为Web和移动的平台添加条件语句和单独的实现,该问题得到了解决。
要检查平台是否为Web,首先需要添加:

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

uploadImage()方法更改为:

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");
    }
  }

然后最后在build()方法中添加Web和Android Image的单独实现:

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"),
          )
        ],
      ),
    );
  }
p5cysglq

p5cysglq2#

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
  }
}

相关问题