下面我分享了我的 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 clean
和flutter run
不适用于网页版。
问题出在 Web 中的权限处理程序包上。 Permissions Handler 包仅针对 Android 和 IOS 构建,在 Web 平台上上传图像不需要权限,因此在 Web 上使用它会带来
MissingPluginException
。
通过添加条件语句以及针对 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"),
)
],
),
);
}
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
}
}