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.
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"),
)
],
),
);
}
Related
This flutter web page reading-writing-files
provides an example of saving a file, in this case containing a counter. I have pasted this into an example app. How can I unit test the file saving part of it?
My failed test attempt is below the app code.
There are 2 issues:
How to write the test itself - what is the testable return from the
t = storage.writeCounter(counter);
how can I shut the app down and prove that the file persists and is later readable
main.dart
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:path_provider/path_provider.dart';
void main() {
runApp(
MaterialApp(
title: 'Reading and Writing Files',
home: FlutterDemo(storage: CounterStorage()),
),
);
}
class CounterStorage {
Future<String> get _localPath async {
final directory = await getApplicationDocumentsDirectory();
return directory.path;
}
Future<File> get _localFile async {
final path = await _localPath;
return File('$path/counter.txt');
}
Future<int> readCounter() async {
try {
final file = await _localFile;
// Read the file
final contents = await file.readAsString();
return int.parse(contents);
} catch (e) {
// If encountering an error, return 0
return 0;
}
}
Future<File> writeCounter(int counter) async {
final file = await _localFile;
// Write the file
return file.writeAsString('$counter');
}
}
class FlutterDemo extends StatefulWidget {
const FlutterDemo({Key? key, required this.storage}) : super(key: key);
final CounterStorage storage;
#override
_FlutterDemoState createState() => _FlutterDemoState();
}
class _FlutterDemoState extends State<FlutterDemo> {
int _counter = 0;
#override
void initState() {
super.initState();
widget.storage.readCounter().then((int value) {
setState(() {
_counter = value;
});
});
}
Future<File> _incrementCounter() {
setState(() {
_counter++;
});
// Write the variable as a string to the file.
return widget.storage.writeCounter(_counter);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Reading and Writing Files'),
),
body: Center(
child: Text(
'Button tapped $_counter time${_counter == 1 ? '' : 's'}.',
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: const Icon(Icons.add),
),
);
}
}
counter_test.dart
import 'package:write_file_test/main.dart';
void main() {
test('Check file save works', () async {
final CounterStorage storage;
var counter = 6;
var t = storage.writeCounter(counter);
expect(find.text('1'), findsOneWidget);
});
}
pubspec.yaml
name: write_file_test
description: Flutter test file saving
publish_to: 'none' # Remove this line if you wish to publish to pub.dev
version: 1.0.0+1
environment:
sdk: ">=2.12.0 <3.0.0"
dependencies:
flutter:
sdk: flutter
path_provider: ^2.0.5
cupertino_icons: ^1.0.2
dev_dependencies:
flutter_test:
sdk: flutter
flutter_lints: ^1.0.0
flutter:
uses-material-design: true
Please I need assistance.
I have written below code to saved file selected from filepicker_windows to C: drive.
filepicker_windows worked well and it get my C: drive successfully But not saving the file.
It gives me ERROR "Exception has occurred.
NoSuchMethodError (NoSuchMethodError: Class 'String' has no instance getter 'bodyBytes'.
Receiver: "C:\Users\norak\OneDrive\Pictures\afdb\Capture.PNG"
Tried calling: bodyBytes)"
Below is my code, please help correct it.
pubspec.yaml File
name: file_manager
description: A new Flutter project.
publish_to: 'none' # Remove this line if you wish to publish to pub.dev
version: 1.0.0+1
environment:
sdk: ">=2.12.0 <3.0.0"
dependencies:
flutter:
sdk: flutter
cupertino_icons: ^1.0.2
filepicker_windows: ^2.0.0
path_provider: ^2.0.1
provider: ^5.0.0
dev_dependencies:
flutter_test:
sdk: flutter
flutter:
uses-material-design: true
MAIN PAGE
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:filepicker_windows/filepicker_windows.dart';
import 'package:path_provider/path_provider.dart';
import 'package:path/path.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
Future<String> getPicturesPath() async {
Directory docDir = await getApplicationDocumentsDirectory();
var pathList = docDir.path.split('\\');
pathList[pathList.length - 1] = 'Pictures';
var picturePath = pathList.join('\\');
print(picturePath);
return picturePath;
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("File Management"),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'You have pushed the button this many times:',
),
Text(
'Testing',
style: Theme.of(context).textTheme.headline4,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: () async {
final file = OpenFilePicker()
..filterSpecification = {'All Files': '*.*'}
..defaultFilterIndex = 0
..defaultExtension = 'doc'
..title = 'Select a document';
final result = file.getFile();
if (result != null) {
print(result.path);
saveImage(result.path, 'ik.jpg');
print("Saved");
}
},
tooltip: 'Increment',
child: Icon(Icons.add),
), // This trailing comma makes auto-formatting nicer for build methods.
);
}
void saveImage(imageData, String imageName) async {
var picturesPath = await getPicturesPath();
var thetaImage = await File(join(picturesPath, 'theta_images', imageName))
.create(recursive: true);
await thetaImage.writeAsBytes(imageData.bodyBytes);
}
}
await thetaImage.writeAsBytes(imageData.bodyBytes); //This is the line that is given error
Please advice
Why don't you debug your code? It's a string. That's why you got the error.
Change the code to:
await thetaImage.writeAsBytes(File(imageData).readAsBytesSync());
> final directory = await getApplicationDocumentsDirectory();
final path = directory.path;
final file = File(path);
I have searched for similar questions and answers to this question but haven't found any specific answer till now.
I am trying to save downloaded files to my internal phone storage. Preferably the download folder... Am using d i o and path provider.
Have tried using "get External Storage Directory". But even after the download I can't locate the file anywhere in my device.
Please how do I specify the download path to something like /storage/emulated/0/Download
You can copy paste run full code below
This example code download a pdf file with Dio and save to Downloads directory
Step 1: downloads_path_provider has archived by the owner, you can use package https://pub.dev/packages/ext_storage
code snippet
String path = await ExtStorage.getExternalStoragePublicDirectory(
ExtStorage.DIRECTORY_DOWNLOADS);
print(path);
Step 2: Add permission in AndroidManifest.xml
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
Step 3: pubspec.yaml , notice permission_handler is 4.4.0
dependencies:
flutter:
sdk: flutter
dio: any
permission_handler: 4.4.0
ext_storage: any
Step 4: Dio for download file
Future download2(Dio dio, String url, String savePath) async {
try {
Response response = await dio.get(
url,
onReceiveProgress: showDownloadProgress,
//Received data with List<int>
options: Options(
responseType: ResponseType.bytes,
followRedirects: false,
validateStatus: (status) {
return status < 500;
}),
);
print(response.headers);
File file = File(savePath);
var raf = file.openSync(mode: FileMode.write);
// response.data is List<int> type
raf.writeFromSync(response.data);
await raf.close();
} catch (e) {
print(e);
}
}
output
I/flutter (13605): full path /storage/emulated/0/Download/test.pdf
I/flutter (13605): 62%
I/flutter (13605): 100%
full code
import 'package:flutter/material.dart';
import 'package:dio/dio.dart';
import 'package:ext_storage/ext_storage.dart';
import 'dart:io';
import 'package:permission_handler/permission_handler.dart';
final imgUrl =
"https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf";
var dio = Dio();
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
void getPermission() async {
print("getPermission");
Map<PermissionGroup, PermissionStatus> permissions =
await PermissionHandler().requestPermissions([PermissionGroup.storage]);
}
#override
void initState() {
getPermission();
super.initState();
}
Future download2(Dio dio, String url, String savePath) async {
try {
Response response = await dio.get(
url,
onReceiveProgress: showDownloadProgress,
//Received data with List<int>
options: Options(
responseType: ResponseType.bytes,
followRedirects: false,
validateStatus: (status) {
return status < 500;
}),
);
print(response.headers);
File file = File(savePath);
var raf = file.openSync(mode: FileMode.write);
// response.data is List<int> type
raf.writeFromSync(response.data);
await raf.close();
} catch (e) {
print(e);
}
}
void showDownloadProgress(received, total) {
if (total != -1) {
print((received / total * 100).toStringAsFixed(0) + "%");
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
RaisedButton.icon(
onPressed: () async {
String path =
await ExtStorage.getExternalStoragePublicDirectory(
ExtStorage.DIRECTORY_DOWNLOADS);
//String fullPath = tempDir.path + "/boo2.pdf'";
String fullPath = "$path/test.pdf";
print('full path ${fullPath}');
download2(dio, imgUrl, fullPath);
},
icon: Icon(
Icons.file_download,
color: Colors.white,
),
color: Colors.green,
textColor: Colors.white,
label: Text('Dowload')),
Text(
'You have pushed the button this many times:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.display1,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
}
I haven't tested it, but if you want to save your downloaded files to the download directory, there is a package for that : downloads_path_provider
If you encounter issues, you can use the path_provider package instead.
It gives you access to several directories of devices.
You can use "flutter_file_dialog" to handle the issue. After succesfully saving file into app you can provide the path of file to this package and save it in another folder of phone. You can use the function below; ** fromDest ** is the path of the saved file.
_saveFileToDest(String fromDest) async {
final params =
SaveFileDialogParams(sourceFilePath: fromDest);
final filePath = await FlutterFileDialog.saveFile(params: params);
if (kDebugMode) {
print(filePath);
}
}
I'm trying to use firebase_ml_vision with image_picker.
Here's the code:
import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';
import 'package:firebase_ml_vision/firebase_ml_vision.dart';
void main() => runApp(MyHomePage());
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
FirebaseVisionImage visionImage;
final BarcodeDetector barcodeDetector = FirebaseVision.instance.barcodeDetector();
final TextRecognizer textRecognizer = FirebaseVision.instance.textRecognizer();
final ImageLabeler labeler = FirebaseVision.instance.imageLabeler(
ImageLabelerOptions(confidenceThreshold: 0.75),
);
final FaceDetector faceDetector = FirebaseVision.instance.faceDetector();
void detections() async {
final VisionText visionText = await textRecognizer.processImage(visionImage);
}
File _image;
Future getImage() async {
var image = await ImagePicker.pickImage(source: ImageSource.camera);
var something = await ImagePicker.pickImage(source: ImageSource.camera);
setState(() {
this.visionImage = FirebaseVisionImage.fromFile(something);
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Image Picker Example'),
),
body: Center(
child: _image == null
? Text('No image selected.')
: Image.file(_image),
),
floatingActionButton: FloatingActionButton(
onPressed: getImage,
tooltip: 'Pick Image',
child: Icon(Icons.add_a_photo),
),
);
}
}
But I am unable to use the File datatype and this is the error I get:
Error
Here's what I get when I run flutter doctor:
Doctor
And here's what I get when I run flutter --version:
Version
I'm very new to Flutter so please let me know if you need anything else.
Thank you!
File type is in dart:io, which you are missing. Add import 'dart:io'; to the top of the file.
I'm using Google mlkit: ^0.9.0 for scanning bar-code in my Flutter project and when I run it this error occrues:
Note: C:\flutter\.pub-cache\hosted\pub.dartlang.org\mlkit-0.9.0\android\src\main\java\com\azihsoyn\flutter\mlkit\MlkitPlugin.java uses unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.
FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':app:transformResourcesWithMergeJavaResForDebug'.
> More than one file was found with OS independent path 'META-INF/androidx.exifinterface_exifinterface.version'
I don't know what the reason.
This is my pubsec.yaml file:
name: flutter_test_barcode
description: A new Flutter application for test ocr
version: 1.0.0+1
environment:
sdk: ">=2.0.0-dev.68.0 <3.0.0"
dependencies:
flutter:
sdk: flutter
cupertino_icons: ^0.1.2
path_provider: 0.4.1
mlkit: ^0.9.0
image_picker: 0.4.12+1
dev_dependencies:
flutter_test:
sdk: flutter
flutter:
uses-material-design: true
And this is my Main.dart file:
import 'dart:async';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';
import 'package:mlkit/mlkit.dart';
void main() => runApp(new MyApp());
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => new _MyAppState();
}
class _MyAppState extends State<MyApp> {
File _file;
List<VisionText> _currentLabels = <VisionText>[];
FirebaseVisionTextDetector detector = FirebaseVisionTextDetector.instance;
#override
initState() {
super.initState();
}
#override
Widget build(BuildContext context) {
return new MaterialApp(
home: new Scaffold(
appBar: new AppBar(
title: new Text('Plugin example app'),
),
body: _buildBody(),
floatingActionButton: new FloatingActionButton(
onPressed: () async {
try {
//var file = await ImagePicker.pickImage(source: ImageSource.camera);
var file =
await ImagePicker.pickImage(source: ImageSource.gallery);
setState(() {
_file = file;
});
try {
var currentLabels = await detector.detectFromPath(_file?.path);
setState(() {
_currentLabels = currentLabels;
});
} catch (e) {
print(e.toString());
}
} catch (e) {
print(e.toString());
}
},
child: new Icon(Icons.camera),
),
),
);
}
Widget _buildImage() {
return SizedBox(
height: 500.0,
child: new Center(
child: _file == null
? Text('No Image')
: new FutureBuilder<Size>(
future: _getImageSize(Image.file(_file, fit: BoxFit.fitWidth)),
builder: (BuildContext context, AsyncSnapshot<Size> snapshot) {
if (snapshot.hasData) {
return Container(
foregroundDecoration:
TextDetectDecoration(_currentLabels, snapshot.data),
child: Image.file(_file, fit: BoxFit.fitWidth));
} else {
return new Text('Detecting...');
}
},
),
),
);
}
Future<Size> _getImageSize(Image image) {
Completer<Size> completer = new Completer<Size>();
image.image.resolve(new ImageConfiguration()).addListener(
(ImageInfo info, bool _) => completer.complete(
Size(info.image.width.toDouble(), info.image.height.toDouble())));
return completer.future;
}
Widget _buildBody() {
return Container(
child: Column(
children: <Widget>[
_buildImage(),
_buildList(_currentLabels),
],
),
);
}
Widget _buildList(List<VisionText> texts) {
if (texts.length == 0) {
return Text('Empty');
}
return Expanded(
child: Container(
child: ListView.builder(
padding: const EdgeInsets.all(1.0),
itemCount: texts.length,
itemBuilder: (context, i) {
return _buildRow(texts[i].text);
}),
),
);
}
Widget _buildRow(String text) {
return ListTile(
title: Text(
"Text: ${text}",
),
dense: true,
);
}
}
class TextDetectDecoration extends Decoration {
final Size _originalImageSize;
final List<VisionText> _texts;
TextDetectDecoration(List<VisionText> texts, Size originalImageSize)
: _texts = texts,
_originalImageSize = originalImageSize;
#override
BoxPainter createBoxPainter([VoidCallback onChanged]) {
return new _TextDetectPainter(_texts, _originalImageSize);
}
}
class _TextDetectPainter extends BoxPainter {
final List<VisionText> _texts;
final Size _originalImageSize;
_TextDetectPainter(texts, originalImageSize)
: _texts = texts,
_originalImageSize = originalImageSize;
#override
void paint(Canvas canvas, Offset offset, ImageConfiguration configuration) {
final paint = new Paint()
..strokeWidth = 2.0
..color = Colors.red
..style = PaintingStyle.stroke;
print("original Image Size : ${_originalImageSize}");
final _heightRatio = _originalImageSize.height / configuration.size.height;
final _widthRatio = _originalImageSize.width / configuration.size.width;
for (var text in _texts) {
print("text : ${text.text}, rect : ${text.rect}");
final _rect = Rect.fromLTRB(
offset.dx + text.rect.left / _widthRatio,
offset.dy + text.rect.top / _heightRatio,
offset.dx + text.rect.right / _widthRatio,
offset.dy + text.rect.bottom / _heightRatio);
//final _rect = Rect.fromLTRB(24.0, 115.0, 75.0, 131.2);
print("_rect : ${_rect}");
canvas.drawRect(_rect, paint);
}
print("offset : ${offset}");
print("configuration : ${configuration}");
final rect = offset & configuration.size;
print("rect container : ${rect}");
//canvas.drawRect(rect, paint);
canvas.restore();
}
}
I changed libraries version according to Google Android X Compatibility documentation but the error still exists! Please help me
The problem was solved finally by changing version library of mlkit and some other libraries in pubspec.yaml file that I guessed they may have conflict with this. The key note is that '^' sign before version number should be removed to make sure which version number is exactly used, not the latest available version.