I'm trying to load image from server using networkimage() and I want to download the same once it is loaded.. can anyone suggest me some ideas.
CircleAvatar(
backgroundImage: NetworkImage(url),
maxRadius: 15.0,
);
Here I'm loading image from my server. I want to save to the image to particular path after the image is loaded.
I recently battled this, and decided to solve it without plugins. I hope it helps someone.
The below program downloads a picture from the web, stores it in the device's local path, and then displays it when run. (note, it does not work for flutter web because you don't have access to the local file storage on that platform. Instead you would have to save the image to a local database using a plugin like sqflite, or hive from pub.dev.) Here's the code:
import 'package:flutter/material.dart';
import 'package:http/http.dart' show get;
import 'dart:io';
import 'package:path_provider/path_provider.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: 'Test Image',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Test Image'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
initState() {
_asyncMethod();
super.initState();
}
_asyncMethod() async {
//comment out the next two lines to prevent the device from getting
// the image from the web in order to prove that the picture is
// coming from the device instead of the web.
var url = "https://www.tottus.cl/static/img/productos/20104355_2.jpg"; // <-- 1
var response = await get(url); // <--2
var documentDirectory = await getApplicationDocumentsDirectory();
var firstPath = documentDirectory.path + "/images";
var filePathAndName = documentDirectory.path + '/images/pic.jpg';
//comment out the next three lines to prevent the image from being saved
//to the device to show that it's coming from the internet
await Directory(firstPath).create(recursive: true); // <-- 1
File file2 = new File(filePathAndName); // <-- 2
file2.writeAsBytesSync(response.bodyBytes); // <-- 3
setState(() {
imageData = filePathAndName;
dataLoaded = true;
});
}
String imageData;
bool dataLoaded = false;
#override
Widget build(BuildContext context) {
if (dataLoaded) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Image.file(File(imageData), width: 600.0, height: 290.0)
],
),
),
);
} else {
return CircularProgressIndicator(
backgroundColor: Colors.cyan,
strokeWidth: 5,
);
}
}
}
pubspec.yaml file:
http: ^0.12.1
path_provider: ^1.6.5
flutter version: 1.20.0-3.0.pre.112
dart version 2.9.0-19.0.dev
I recommend image_downloader.
For ios, image is saved in Photo Library.
For Android, image is saved in Environment.DIRECTORY_DOWNLOADS or specified location. By calling inExternalFilesDir(), specification of permission becomes unnecessary.
By callback(), you can get progress status.
The following is the simplest example. It will be saved.
await ImageDownloader.downloadImage(url);
I used image_downloader.
Use await ImageDownloader.downloadImage("url") of image_downloader package's method to download image using it's url.
Note : above method will return value as follows :-
imageId of the saved image if saving succeeded.
null if not been granted permission.
for this you have to ask for storage permission, just add following line into android manifest file :
uses-permission
android:name="android.permission.WRITE_EXTERNAL_STORAGE"
Otherwise it is a PlatformException.
I tried many solution, but this is simplest solution for my... Just try it
STEP - 1
Add this package in your pubspec.yaml file
dependencies:
image_downloader: ^0.20.1
STEP - 2
Add this in your dart file
import 'package:image_downloader/image_downloader.dart';
STEP - 3
Write this code on press download button
ColButton(
title: 'Download',
icon: Icons.file_download,
onTap: () async {
try {
showLoadingDialog(context);
// Saved with this method.
var imageId =
await ImageDownloader.downloadImage("https://raw.githubusercontent.com/wiki/ko2ic/image_downloader/images/bigsize.jpg");
if (imageId == null) {
return;
}
// Below is a method of obtaining saved image information.
var fileName = await ImageDownloader.findName(imageId);
var path = await ImageDownloader.findPath(imageId);
var size = await ImageDownloader.findByteSize(imageId);
var mimeType = await ImageDownloader.findMimeType(imageId);
Navigator.pop(context);
showToast('Image downloaded.');
} on PlatformException catch (error) {
print(error);
}
},
),
I use this plugin to save image in the phone using an URL
https://pub.dartlang.org/packages/image_picker_saver
For more advanced handling of Image/File downloads, you can consider the flutter_downloader package.
Some of the features that I like are :
Shows OS level download progress
can track all downloads
Has notification
Related
TLDR: I understand how to create a new file via Dart and path provider, but I don't know how to get a pre-existing file into the Android/Apple file system.
I'm building this app which works a bit with string manipulation. Ideally, I want it reading strings from a pre-existing CSV file which I'm getting from a client, then manipulating the data to create more CSV files. I found packages for both CSV and Paths. What I don't know is how to get my CSV in there.
As of now I have this file called test.csv in my app's root directory. I tried to access it through my main.dart by using File f = File("$_localPath/test.csv"). The file was nowhere to be found. I then went into the phone's memory using Android Studio, and found the local storage path of the app. My test.csv file was nowhere to be seen. My guess right now is that at compilation, that CSV file becomes garbage machine code. So how can I get it intact into the device's local memory?
I don't want to get the file from the internet because I'm hoping the user can boot up the app for the first time in any setting and be able to have its full functionality.
I just tested this code example and it works on all platforms.
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:path_provider/path_provider.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatefulWidget {
const MyApp({super.key});
#override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
String _fileContent = '';
final TextEditingController _controller = TextEditingController();
#override
initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) {
readFile();
});
}
Future<String> getFilePath() async {
Directory appDocumentsDirectory =
await getApplicationDocumentsDirectory(); // 1
String appDocumentsPath = appDocumentsDirectory.path;
String filePath = '$appDocumentsPath/file.csv';
return filePath;
}
void saveFile() async {
File file = File(await getFilePath());
if (mounted) {
file.writeAsString(_controller.text);
setState(() {
_fileContent = _controller.text;
});
_controller.text = '';
}
}
void readFile() async {
File file = File(await getFilePath());
final fileContent = await file.readAsString();
if (mounted) {
setState(() {
_fileContent = fileContent;
});
}
}
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: const Text('Saving CSV file')),
body: Padding(
padding: const EdgeInsets.all(16),
child: Column(
children: [
Text('Current content = $_fileContent'),
TextField(
controller: _controller,
),
TextButton(
onPressed: saveFile,
child: const Text('Press to save file'),
),
],
),
),
),
);
}
}
This code creates the file and sets a content into it. Then, after restarting the app, it tries to find the file and receive its content. After that it shows the content inside a Text widget.
I used this article for making this example. Hope it will help:)
I am developing a flutter mobile application where I need to upload multiple images through an API. Now I completed the part where pick images from the gallery. Next step is to upload the images. To do that I need the image path. I know that image path can be get by using the below code line but it keep saying that Undefined name 'FlutterAbsolutePath' what is the reason how to fix this issue. I am using multi-image-picker package.
final filePath =
await FlutterAbsolutePath.getAbsolutePath(image.identifier);
It would be really nice if you could provide us with some more information or even a code sample. In case you are using this package, I would strongly advice you to change it to one that is not discontinued (take a look into this one: image_picker; you can select multiple images at once with this one too).
Until further information is provided you can take a look over the following code that uses the image_picker:
After following the installation steps from the documentation you can get images using the next method:
Future<void> getImages() async {
ImagePicker imagePicker = ImagePicker();
List<XFile>? images = await imagePicker.pickMultiImage();
if ((images ?? []).isNotEmpty) {
//get the path of the first image from the select images
String imagePath = images?.first.path ?? '';
//get the content of the first image from the select images as bytes
Uint8List? imageAsBytes = await images?.first.readAsBytes();
//get the content of the first image from the select images as a String based on a given encoding
String? imageAsString = await images?.first.readAsString();
}
}
I hope that I helped you a little bit. Happy coding! :)
Later edit:
Here is a very basic Flutter app that picks an image with multi-picker, creates a temp file for which we know the path and displays the temp file in order to show that the temp file was correctly displayed.
For you, what's of most interest is getFile() method which takes care of creating the temp file that is 1:1 with picked image(s).
For creating the temp file I used: path_provider also take a look into the following: Read and write files
For permission handling: permission_handler
I still strongly suggest that you use other package for image picking as this one is discontinued :).
import 'dart:io';
import 'dart:typed_data';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:multi_image_picker/multi_image_picker.dart';
import 'package:path_provider/path_provider.dart';
import 'package:permission_handler/permission_handler.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const HomePage(),
);
}
}
Future<File?> getFile() async {
List<Asset> images = await MultiImagePicker.pickImages(maxImages: 100);
if (images.isNotEmpty) {
ByteData bytesData = await images.first.getByteData();
List<int> bytes = bytesData.buffer
.asUint8List(bytesData.offsetInBytes, bytesData.lengthInBytes)
.cast<int>();
//get the extension jpeg, png, jpg
String extension = (images.first.name ?? '').split('.').last;
//get path to the temporaryDirector
final Directory directory = await getTemporaryDirectory();
//get the path to the chosen directory
String directoryPath = directory.path;
//create a temporary file to the specified path
//you can use the path to this file for the API
File file = File('$directoryPath/myImage.$extension');
//write the bytes to the image
file.writeAsBytesSync(bytes, mode: FileMode.write);
//just for path: file.path -> will return a String with the path
return file;
}
return null;
}
class HomePage extends StatefulWidget {
const HomePage({Key? key}) : super(key: key);
#override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
File? file;
#override
Widget build(BuildContext context) {
return Container(
color: Colors.amber,
child: Column(
children: [
const SizedBox(
height: 50,
),
Center(
child: TextButton(
child: const Text('Pick an image'),
onPressed: () async {
await Permission.accessMediaLocation.request();
file = await getFile();
setState(() {});
},
),
),
const SizedBox(
height: 50,
),
file != null
? Image.file(
file!,
height: 200,
width: 200,
)
: Container(),
],
),
);
}
}
I am using "mobile_number(version - 1.0.3)" plugin to get mobile number in flutter app, am running in original device but i couldn't get mobile number.instead of errors i can get mobile number as null along with other sim details as shown in screen shot.
help me to resolve this problem, i had just copy pasted the example given by plugin that is the code
plugin link
It says:
Note: If the mobile number is not pre-exist on sim card it will not return te phone number.
I think mobile number does not pre-exist on the SIM if the SIM is not original (i.e. replaced)
If the phone number isn't stored on the sim (aka null), then you can't get it from anywhere else, in that case you probably want to forward the user to a different page where they can type the phone number using TextField and then store it somewhere
Use Mobile_number package to get mobile number and other details. For example
import 'dart:async';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:mobile_number/mobile_number.dart';
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
String _mobileNumber = '';
List<SimCard> _simCard = <SimCard>[];
#override
void initState() {
super.initState();
MobileNumber.listenPhonePermission((isPermissionGranted) {
if (isPermissionGranted) {
initMobileNumberState();
} else {}
});
initMobileNumberState();
}
// Platform messages are asynchronous, so we initialize in an async method.
Future<void> initMobileNumberState() async {
if (!await MobileNumber.hasPhonePermission) {
await MobileNumber.requestPhonePermission;
return;
}
String mobileNumber = '';
// Platform messages may fail, so we use a try/catch PlatformException.
try {
mobileNumber = (await MobileNumber.mobileNumber)!;
_simCard = (await MobileNumber.getSimCards)!;
} on PlatformException catch (e) {
debugPrint("Failed to get mobile number because of '${e.message}'");
}
// If the widget was removed from the tree while the asynchronous platform
// message was in flight, we want to discard the reply rather than calling
// setState to update our non-existent appearance.
if (!mounted) return;
setState(() {
_mobileNumber = mobileNumber;
});
}
Widget fillCards() {
List<Widget> widgets = _simCard
.map((SimCard sim) => Text(
'Sim Card Number: (${sim.countryPhonePrefix}) - ${sim.number}\nCarrier Name: ${sim.carrierName}\nCountry Iso: ${sim.countryIso}\nDisplay Name: ${sim.displayName}\nSim Slot Index: ${sim.slotIndex}\n\n'))
.toList();
return Column(children: widgets);
}
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('Plugin example app'),
),
body: Center(
child: Column(
children: <Widget>[
Text('Running on: $_mobileNumber\n'),
fillCards()
],
),
),
),
);
}
}
I'm trying to download an image from the network and save it locally in the Downloads folder of a computer. I need to achieve that for flutter web, I'm not sure how to do it.
I found some questions related to how to achieve download and save a file or an image for android and IOS, such as Flutter save a network image to local directory. I also took a look at How do I read and write image file locally for Flutter Web?. However, I don't see how those answers can help me.
I think that for IOS and Flutter I can use the following function without getting any error, but I don't know where the files are being saved in my emulator:
void _downloadAndSavePhoto() async {
var response = await http.get(Uri.parse(imageUrl));
try {
Directory tempDir = await getTemporaryDirectory();
String tempPath = tempDir.path;
File file = File('$tempPath/$name.jpeg');
file.writeAsBytesSync(response.bodyBytes);
} catch (e) {
print(e.toString());
}
}
However, when I try the above function for flutter web (using a chrome simulator) I get the following error:
MissingPluginException(No implementation found for method getTemporaryDirectory on channel plugins.flutter.io/path_provider)
I will be more than happy if someone knows a way to do it or have some suggestions to implement that functionality.
Thanks in advance!
To achieve this I would suggest you first to add the universal_html package to your pubspec.yaml because in the newer versions of Flutter you will get warnings for importing dart:html.
In pubspec.yaml:
dependencies:
flutter:
sdk: flutter
http: ^0.13.1 // add http
universal_html: ^2.0.8 // add universal_html
I created a fully working example Flutter web app, you can try it, but the only thing that interests you is the downloadImage function.
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
// if you don't add universal_html to your dependencies you should
// write import 'dart:html' as html; instead
import 'package:universal_html/html.dart' as html;
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
debugShowCheckedModeBanner: false,
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
final imageUrls = <String>[
'https://images.pexels.com/photos/208745/pexels-photo-208745.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=650&w=940',
'https://images.pexels.com/photos/1470707/pexels-photo-1470707.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=650&w=940',
'https://images.pexels.com/photos/2671089/pexels-photo-2671089.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=650&w=940',
'https://images.pexels.com/photos/2670273/pexels-photo-2670273.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=650&w=940',
];
#override
Widget build(BuildContext context) {
return Scaffold(
body: GridView.count(
crossAxisCount: 3,
children: imageUrls
.map(
(imageUrl) => ImageCard(imageUrl: imageUrl),
)
.toList(),
),
);
}
}
class ImageCard extends StatefulWidget {
#override
_ImageCardState createState() => _ImageCardState();
final String imageUrl;
ImageCard({
#required this.imageUrl,
});
}
class _ImageCardState extends State<ImageCard> {
Future<void> downloadImage(String imageUrl) async {
try {
// first we make a request to the url like you did
// in the android and ios version
final http.Response r = await http.get(
Uri.parse(imageUrl),
);
// we get the bytes from the body
final data = r.bodyBytes;
// and encode them to base64
final base64data = base64Encode(data);
// then we create and AnchorElement with the html package
final a = html.AnchorElement(href: 'data:image/jpeg;base64,$base64data');
// set the name of the file we want the image to get
// downloaded to
a.download = 'download.jpg';
// and we click the AnchorElement which downloads the image
a.click();
// finally we remove the AnchorElement
a.remove();
} catch (e) {
print(e);
}
}
#override
Widget build(BuildContext context) {
return InkWell(
onTap: () => downloadImage(widget.imageUrl),
child: Card(
child: Image.network(
widget.imageUrl,
fit: BoxFit.cover,
),
),
);
}
}
I have a pdf reader in my app, with this function I get de pdf from URL and save the file in local path
Future<File> getFileFromUrl(String url) async {
try {
var data = await http.get(url);
var bytes = data.bodyBytes;
var dir = await getApplicationSupportDirectory();
File file = File("${dir.path}/some.pdf");
File urlFile = await file.writeAsBytes(bytes);
return urlFile;
} catch (e) {
throw Exception("Error opening url file");
}
}
After this process, I call a class to show this PDF in a new route
import 'package:flutter/material.dart';
import 'package:flutter_pdfview/flutter_pdfview.dart';
class CustomPdfView extends StatefulWidget {
final String title;
final String urlPdf;
CustomPdfView(
this.title,
this.urlPdf
);
#override
_CustomPdfViewState createState() => _CustomPdfViewState();
}
class _CustomPdfViewState extends State<CustomPdfView> {
//int _totalPages = 0;
//int _currentPage = 0;
bool pdfReady = false;
//PDFViewController _pdfViewController;
#override
Widget build(BuildContext context) {
print('Aqui entra antes: ${widget.urlPdf}');
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Stack(
children: <Widget>[
PDFView(
filePath: widget.urlPdf,
autoSpacing: true,
enableSwipe: true,
pageSnap: true,
swipeHorizontal: true,
nightMode: false,
onError: (e) {
print("error $e");
},
onRender: (_pages) {
setState(() {
//_totalPages = _pages;
pdfReady = true;
});
},
onViewCreated: (PDFViewController vc) {
//_pdfViewController = vc;
},
onPageChanged: (int page, int total) {
setState(() {});
},
onPageError: (page, e) {},
),
!pdfReady
? Center(
child: CircularProgressIndicator(),
)
: Offstage()
],
),
);
}
}
All works fine in debug mode, but when I run my app on release, the app crashes in CustomPdfView.
I don't know what is the error, I already added, STORAGE permissions in my /app/src/main/AndroidManifest.xml
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
And I don't know how can I get error line in the console, because the app is running on release.
same issue.....
i fixed that one
clean your project after build your apk
if still problem persist
than try these commands
flutter build apk --no-shrink
flutter build apk --release --split-per-abi --no-shrink
your way of reading pdf is very nice, here you try to launch pdf in your app,
i almost did the same way.
where i was getting Uint8List from url of pdf, and reading it in my app using printing 5.9.3
but when size of pdf or number of pages more then my app keep getting crash, and also before launching pdf in my app i need to save it locally as you did.
so, to solve this i just need to use flutter_cached_pdfview: ^0.4.1
using this flutter_cached_pdfview i don't need to save pdf locally, just pass the url of pdf and you can launch it in your app without worrying about size of pdf or number of pages in pdf.
i just launch using a button and i pass url of pdf
// navigate in another screen
onPressed: () => nextScreen(
PDFViewerPage(
url: widget.magazineModel.fileUrl,
title: widget.magazineModel.name,
),
),
and MyPdfViewerPage is below
class PDFViewerPage extends StatelessWidget {
final String url;
final String title;
const PDFViewerPage({
Key? key,
required this.title,
required this.url,
}) : super(key: key);
#override
Widget build(BuildContext context) {
debugPrint('url : $url');
return Scaffold(
appBar: AppBar(
leading: const LeadingIconComponent(), // for popScreen()
title: Text(title),
),
body: const PDF().cachedFromUrl(
Uri.parse(url).toString(),
placeholder: (progress) => const LoadingComponent(),
errorWidget: (error) {
debugPrint('errorInOprnPDF : $error');
return const ErrorPageComponent(
title: 'File Not Exist',
content: "This file is either removed or not valid",
image: "assets/images/empty_data_component/new data not found.svg",
);
},
),
);
}
}