首页 > 解决方案 > 无法使用 Flutter Web 上的图像选择器选择图像(MissingPluginException)

问题描述

下面我将分享我的颤振代码,它只需选择一个图像并在获得所需权限后将其显示在屏幕上。但是,该代码在 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 clean并且flutter run 不适用于Web版本。

标签: flutterdartfile-permissionsflutter-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 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"),
          )
        ],
      ),
    );
  }

推荐阅读