Flutter downloads partial files from Google Drive and One drive - flutter

Flutter can not download files from Google Drive or OneDrive, zip or otherwise.
The files just get partially downloaded whereas files from most other links from websites etc are downloaded completely.
For example this Google Drive link will only get 10% file download but the other URL for a novel will get 100%
Packages used:
http: ^0.12.2
dio: ^3.0.10
path_provider: ^1.6.24
Google Drive URL = 'https://drive.google.com/file/d/1xnhT8mzMeU-wRemt1sNFR0DJt2MNmSC8/view?usp=sharing';
Gutenberg Novel URL = 'https://www.gutenberg.org/files/1342/1342-h.zip';
Example code shows both links and result.
Output:
Expected size: myColorsDIO.zip: 594,545 , myColorsHTTP.zip: 594,545 ,
1342DIO.zip: 778512, 1342HTTP.zip: 778512
Obtained size:
myColorsDIO.zip: 63411, myColorsHTTP.zip: 70677, 1342DIO.zip: 778512,
1342HTTP.zip: 778512
Please help.
import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'package:path_provider/path_provider.dart';
import 'dart:io';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(title: 'Flutter Demo', theme: ThemeData(primarySwatch: Colors.blue,visualDensity: VisualDensity.adaptivePlatformDensity,), home: MyHomePage(),);
}
}
class MyHomePage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Downloading Files'),),
body: Center(child: Text('Press the floating button to download files',),),
floatingActionButton: FloatingActionButton(
onPressed: () { _downloadFile();},
tooltip: 'Increment',
child: Icon(Icons.add),
), // This trailing comma makes auto-formatting nicer for build methods.
);
}
Future<File> _downloadFile() async {
String myUrl = 'https://drive.google.com/file/d/1xnhT8mzMeU-wRemt1sNFR0DJt2MNmSC8/view?usp=sharing';
String my7ZIPUrl = 'https://www.gutenberg.org/files/1342/1342-h.zip';
String myDownloadDirectory = ((await getApplicationDocumentsDirectory()).path);
String myDownloadedGoogleFile1 = 'myColorsDIO.zip';
String myDownloadedGoogleFile2 = 'myColorsHTTP.zip';
String myDownloadedfromgutenberg1 = '1342DIO.zip';
String myDownloadedfromgutenberg2 = '1342HTTP.zip';
print('Download Directory: $myDownloadDirectory');
//Downloading Google Drive zip file via DIO
Dio dio = Dio();
await dio.download(
myUrl,
'$myDownloadDirectory/$myDownloadedGoogleFile1',
onReceiveProgress: (rcv, total) {print('received: ${rcv.toStringAsFixed(0)} out of total: ${total.toStringAsFixed(0)}');}
);
await dio.download(
my7ZIPUrl,
'$myDownloadDirectory/$myDownloadedfromgutenberg1',
onReceiveProgress: (rcv, total) {print('received: ${rcv.toStringAsFixed(0)} out of total: ${total.toStringAsFixed(0)}');}
);
//Downloading Google Drive zip file via HTTP
var req = await http.Client().get(Uri.parse(myUrl));
var file = File('$myDownloadDirectory/$myDownloadedGoogleFile2',);
file.writeAsBytes(req.bodyBytes);
//Downloading Google Drive zip file via HTTP
var req1 = await http.Client().get(Uri.parse(my7ZIPUrl));
var file1 = File('$myDownloadDirectory/$myDownloadedfromgutenberg2',);
file1.writeAsBytes(req1.bodyBytes);
print('Expected size: myColorsDIO.zip: 594,545 , myColorsHTTP.zip: 594,545 , 1342DIO.zip: 778512, 1342HTTP.zip: 778512');
print('myColorsDIO.zip: ${await File('$myDownloadDirectory/$myDownloadedGoogleFile1',).length()}, myColorsHTTP.zip: ${await File('$myDownloadDirectory/$myDownloadedGoogleFile2',).length()}, 1342DIO.zip: ${await File('$myDownloadDirectory/$myDownloadedfromgutenberg1',).length()}, 1342HTTP.zip: ${await File('$myDownloadDirectory/$myDownloadedfromgutenberg2',).length()}');
return null;
}
}

Sharing link does not work directly, put it in the browser and when you are prompted for a download, that is the URL that works.

Related

How do I create a "fake" dart:io File from MemoryFileSystem bytes?

I have the in-memory bytes of a decrypt epub file, but the package that I want to open this epub file with only accepts dart:io File objects.
I don't want to create real local file => just for security
Is there a way to create a "fake" dart:io File, simply wrapping my in-memory bytes, so that I can pass this "fake" File to the package?
I'm using vocsy_epub_viewer package to open epub files
filePath should be a local file
import 'package:archive/archive.dart';
import 'package:flutter/material.dart';
import 'package:vocsy_epub_viewer/epub_viewer.dart';
import 'package:file_picker/file_picker.dart';
import 'package:path_provider/path_provider.dart';
import 'package:encrypt/encrypt.dart' as en;
import 'dart:io';
import 'package:cross_file/cross_file.dart';
import 'package:file/memory.dart';
import 'package:file/file.dart' as F;
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Ebook(),
);
}
}
class Ebook extends StatefulWidget {
#override
State<Ebook> createState() => _EbookState();
}
class _EbookState extends State<Ebook> {
Directory? _temp;
String? path;
#override
void initState() {
address();
super.initState();
}
Future decodeEpub(String path) async {
final bytes = await File(path).readAsBytes();
Archive archive =
await ZipDecoder().decodeBytes(bytes, password: '7web', verify: true);
final data = await archive.first.content;
final key = en.Key.fromUtf8('qwertyuiopasdfghjklmnbvcxzasdfgh');
final iv = en.IV.fromLength(16);
final decrypted = await en.AES(key).decrypt(en.Encrypted(data), iv: iv);
// XFile file = await XFile.fromData(decrypted,name:'2.epub',path:"${_appDocumentsDirectory!.path}/2.epub" );
// File file1= await File(file.path).create(recursive: true);
// File file = MemoryFileSystem().file('${temp!.path}/2.epub')..create(recursive: true)
// ..writeAsBytesSync(decrypted);
File file = await File('${_temp!.path}/2.epub').writeAsBytes(decrypted); // it must be change ******
print(file.path);
return file.path;
}
void address() async {
final temp = await getTemporaryDirectory();
setState(() {
_temp = temp;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ElevatedButton(
onPressed: () async {
FilePickerResult? result =
await FilePicker.platform.pickFiles();
if (result != null) {
File file = File(result.files.single.path!);
path = await decodeEpub(file.path);
print('?= $path , ${file.path}');
} else {
print('cancel');
}
},
child: Text('add File')),
ElevatedButton(
onPressed: () {
EpubViewer.setConfig(
themeColor: Theme.of(context).primaryColor,
identifier: "iosBook",
scrollDirection: EpubScrollDirection.ALLDIRECTIONS,
allowSharing: true,
enableTts: true,
nightMode: false);
EpubViewer.open(path!, lastLocation: EpubLocator());
},
child: Text("open"),
),
],
),
),
);
}
}
I don't want to create real local file => just for security
This is not actually true because EPUBs are structured as a zip file and folioreader, the framework used behind the vocsy_epub_viewer, will "unzip" the file to a temp folder (or one predefined). So, in the end, it's not going to be secure anyway.
Just extract the EPUB to the temp folder from path_provider and remove it afterwards. Otherwise, you're going to need a new framework to read EPUBs that don't have this behaviour or even customize the vocsy_epub_viewer/folioreader sources yourself to make it secure.

Undefined name 'FlutterAbsolutePath'

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

How can I download an image from the network and save it in a locally directory?

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

PDF File generation with Flutter web

I'm in the process of Web'ifing a Flutter mobile application and attempting to get around the lack for support for Path Provider in Web.
I'm using the PDF (pdf: ^1.9.0) package to generate a PDF document and upload it to Google Drive and I'm trying to find out if I can generate and store the PDF In memory to make it web compatible.
Example current code using Path Provider.
createFile() async {
final downloads = await getApplicationSupportDirectory();
final file = File("${downloads.path}/$filename.pdf");
await file.writeAsBytes(pdf.save());
await GoogleDriveController.uploadFileToGoogleDrive(file.path);
}
Question: Is there a way to generate and store Fies in memory for web using Flutter web?
I managed to find a work around to generate the PDF and trigger a download via the browser instead and thought I should post incase anyone stumbles across this.
//Create PDF in Bytes
Uint8List pdfInBytes = pdf.save();
//Create blob and link from bytes
final blob = html.Blob([pdfInBytes], 'application/pdf');
final url = html.Url.createObjectUrlFromBlob(blob);
final anchor = html.document.createElement('a') as html.AnchorElement
..href = url
..style.display = 'none'
..download = 'pdf.pdf';
html.document.body.children.add(anchor);
//Trigger the download of this PDF in the browser.
RaisedButton(
child: Text('Press'),
onPressed: () {
anchor.click();
Navigator.pop(context);
},
)
My answer is a variant on Yonkee above specifically for flutter web. In this answer, I have added the imports required (dart:html and dart:typed_data) and added formatting of text as I needed that feature.
import 'package:flutter/material.dart';
import 'package:pdf/widgets.dart' as pw;
import 'dart:typed_data';
import 'dart:html' as html;
class PDFSave extends StatefulWidget {
#override
_PDFSaveState createState() => _PDFSaveState();
}
class _PDFSaveState extends State<PDFSave> {
final pdf = pw.Document();
var anchor;
savePDF() async {
Uint8List pdfInBytes = await pdf.save();
final blob = html.Blob([pdfInBytes], 'application/pdf');
final url = html.Url.createObjectUrlFromBlob(blob);
anchor = html.document.createElement('a') as html.AnchorElement
..href = url
..style.display = 'none'
..download = 'pdf.pdf';
html.document.body.children.add(anchor);
}
createPDF() async {
pdf.addPage(
pw.Page(
build: (pw.Context context) => pw.Column(
children: [
pw.Text('Hello World', style: pw.TextStyle(fontSize: 40)),
],
),
),
);
savePDF();
}
#override
void initState() {
super.initState();
createPDF();
}
#override
Widget build(BuildContext context) {
return Scaffold(backgroundColor: Colors.transparent,
appBar: AppBar(
title: Text('PDF Creator'),
),
body: Center(
child:RaisedButton(
child: Text('Press'),
onPressed: () {
anchor.click();
Navigator.pop(context);
},
)
));
}
}

flutter download an Image from url

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