无法在 Flutter Web 上使用图像选择器 select 图像(MissingPluginException)

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

下面我分享了我的 flutter 代码,它只需选择一个图像并在获得所需权限后将其显示在屏幕上。然而,该代码在 Android 上运行良好,但当我尝试在网络上上传图像时出现 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"),
          )
        ],
      ),
    );
  }
}

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

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 版本。

问题出在 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 图片添加单独的实现:

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