Load pdf file from url - flutter

I have this url from server
https://xxxx.pdf20200529". How can I load it as pdf in my flutter app?
I use this plugin, but nothing happened.
Code
OpenFile.open(value); // value is https://xxxx.pdf20200529
Edit
generatePDF(dynamic value) async {
final filename = value.substring(value.lastIndexOf("/") + 1);
var request = await HttpClient().getUrl(Uri.parse(value));
var response = await request.close();
var bytes = await consolidateHttpClientResponseBytes(response);
String dir = (await getApplicationDocumentsDirectory()).path;
File file = new File('$dir/$filename');
await file.writeAsBytes(bytes);
OpenFile.open(file.path);
}

Opening PDF's in Flutter is pretty fiddly. So I suggest you use a package. flutter_full_pdf_viewer works pretty well and is easy to use, but there are others out there.
https://pub.dev/packages/flutter_full_pdf_viewer
This will be your PDF Screen:
class PDFScreen extends StatelessWidget {
String pathPDF = "";
PDFScreen(this.pathPDF);
#override
Widget build(BuildContext context) {
return PDFViewerScaffold(
appBar: AppBar(
title: Text("Document"),
actions: <Widget>[
IconButton(
icon: Icon(Icons.share),
onPressed: () {},
),
],
),
path: pathPDF);
}
}
Navigate to it like this. Make sure to pass the local path to the screen.:
Navigator.push(context, MaterialPageRoute(builder: (context) => PDFScreen(pathPDF)),

Have you tried url_launcher 5.4.10
As far as I know it opens pdfs as well.

I miss .pdf in this line
File file = new File('$dir/$filename.pdf');
After add .pdf, all PDF viewer able to open.

Related

How to save a file to Google Drive from Flutter web without a local file on disk?

The example Drive API v3 code shows that to save a file to Google drive from your app you have to create a local file on disk first, then upload it.
Since I'm using Flutter for web (as well as Windows and Android) I can't save files to disk. (Nor would I want to, as it's very slow compared to just sending bytes in memory over http.)
How can I send data in memory straight to Google and have it saved as a file please (and vice versa)? I can't find any Dart code for this, nor Drive examples, anywhere that I've Googled.
I know your question is about flutter. I am not a flutter dev. After discussing this with you in comments it sounds like you are looking to find out if its even possible.
I went a head and tested this with C# and i can tell you that it is possible. All you have to do is turn your text into a memory stream and then upload that instead of a file stream. As it sounds like you already have the text in a memory stream you should be able to just upload it.
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Google.Apis.Auth.OAuth2;
using Google.Apis.Drive.v3;
using Google.Apis.Drive.v3.Data;
using Google.Apis.Services;
using Google.Apis.Upload;
namespace ConsoleApp1
{
class Program
{
static readonly string CredentialsFile = "ServiceAccountCreds.json";
private static readonly string FileName = "UploadFileString.txt";
static async Task Main(string[] args)
{
Console.WriteLine("Hello World!");
var serviceAccountCredentials = GoogleCredential.FromFile(CredentialsFile)
.CreateScoped(DriveService.ScopeConstants.Drive);
var service = new DriveService(new BaseClientService.Initializer()
{
HttpClientInitializer = serviceAccountCredentials,
ApplicationName = "Discovery Authentication Sample",
});
var uploadString = "Test";
// Upload file Metadata
var fileMetadata = new Google.Apis.Drive.v3.Data.File()
{
Name = FileName,
Parents = new List<string>() {"1R_QjyKyvET838G6loFSRu27C-3ASMJJa"}
};
// Convert raw text to memory stream for upload.
var fsSource = new MemoryStream(Encoding.UTF8.GetBytes(uploadString ?? ""));
string uploadedFileId;
// // Create a new file on Google Drive
// await using (var fsSource = new FileStream(FileName, FileMode.Open, FileAccess.Read))
// await using (var fsSource = new FileStream(FileName, FileMode.Open, FileAccess.Read))
// {
// Create a new file, with metadata and stream.
var request = service.Files.Create(fileMetadata, fsSource, "text/plain");
request.Fields = "*";
var results = await request.UploadAsync(CancellationToken.None);
if (results.Status == UploadStatus.Failed)
{
Console.WriteLine($"Error uploading file: {results.Exception.Message}");
}
// the file id of the new file we created
uploadedFileId = request.ResponseBody?.Id;
//}
}
}
}
In theory any of the Flutter samples should work.
Use
dependencies:
google_drive_client: ^1.0.3
import 'dart:io';
import 'package:dio/dio.dart';
import 'package:example/config.dart';
import 'package:flutter/material.dart';
import 'package:google_drive_client/google_drive_client.dart';
import 'package:path_provider/path_provider.dart';
void main() {
runApp(App());
}
class App extends StatelessWidget {
final GoogleDriveClient client = GoogleDriveClient(Dio(), getAccessToken: () async => Config.ACCESS_TOKEN);
final String id = '';
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: ListView(
children: [
FlatButton(
child: Text('list'),
onPressed: () async {
print(await client.list());
},
),
FlatButton(
child: Text('create'),
onPressed: () async {
final File file = File((await getTemporaryDirectory()).path + '/testing2');
file.writeAsStringSync("contents");
var meta = GoogleDriveFileUploadMetaData(name: 'testing');
print(await client.create(meta, file));
},
),
FlatButton(
child: Text('delete'),
onPressed: () async {
await client.delete(id);
},
),
FlatButton(
child: Text('download'),
onPressed: () async {
await client.download(id, 'testing');
},
),
FlatButton(
child: Text('get'),
onPressed: () async {
print(await client.get(id));
},
),
],
),
),
);
}
}

How to solve Unhandled Exception: FormatException: Could not find End of Central Directory Record while downloading file in Flutter?

In my Flutter project, I want to download some files as zip and then unzip it programmatically and save it in device locally. So, for that reason I followed some examples, here's the code for that-
import 'package:flutter/material.dart';
import 'dart:io';
import 'package:archive/archive.dart';
import 'package:http/http.dart' as http;
import 'package:path_provider/path_provider.dart';
class DownloadAssetsDemo extends StatefulWidget {
DownloadAssetsDemo() : super();
final String title = "Download & Extract ZIP Demo";
#override
DownloadAssetsDemoState createState() => DownloadAssetsDemoState();
}
class DownloadAssetsDemoState extends State<DownloadAssetsDemo> {
//
bool _downloading;
String _dir;
List<String> _images, _tempImages;
String _zipPath = 'https://coderzheaven.com/youtube_flutter/images.zip';
String _localZipFileName = 'images.zip';
#override
void initState() {
super.initState();
_images = List();
_tempImages = List();
_downloading = false;
_initDir();
}
_initDir() async {
if (null == _dir) {
_dir = (await getApplicationDocumentsDirectory()).path;
}
}
Future<File> _downloadFile(String url, String fileName) async {
var req = await http.Client().get(Uri.parse(url));
var file = File('$_dir/$fileName');
return file.writeAsBytes(req.bodyBytes);
}
Future<void> _downloadZip() async {
setState(() {
_downloading = true;
});
_images.clear();
_tempImages.clear();
var zippedFile = await _downloadFile(_zipPath, _localZipFileName);
await unarchiveAndSave(zippedFile);
setState(() {
_images.addAll(_tempImages);
_downloading = false;
});
}
unarchiveAndSave(var zippedFile) async {
var bytes = zippedFile.readAsBytesSync();
var archive = ZipDecoder().decodeBytes(bytes);
for (var file in archive) {
var fileName = '$_dir/${file.name}';
if (file.isFile) {
var outFile = File(fileName);
//print('File:: ' + outFile.path);
_tempImages.add(outFile.path);
outFile = await outFile.create(recursive: true);
await outFile.writeAsBytes(file.content);
}
}
}
buildList() {
return Expanded(
child: ListView.builder(
itemCount: _images.length,
itemBuilder: (BuildContext context, int index) {
return Image.file(
File(_images[index]),
fit: BoxFit.fitWidth,
);
},
),
);
}
progress() {
return Container(
width: 25,
height: 25,
padding: EdgeInsets.fromLTRB(0.0, 20.0, 10.0, 20.0),
child: CircularProgressIndicator(
strokeWidth: 3.0,
valueColor: AlwaysStoppedAnimation<Color>(Colors.white),
),
);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
actions: <Widget>[
_downloading ? progress() : Container(),
IconButton(
icon: Icon(Icons.file_download),
onPressed: () {
_downloadZip();
},
),
],
),
body: Container(
child: Column(
children: <Widget>[
buildList(),
],
),
),
);
}
}
This example, works fine with all the functionalities- zip file download, extract the file and load the images.
But the problem is
When I want to download the file from my desired location where I have saved a sqlite database(Size:19 mb) as a zip file, it doesn't work like the way it happened for the given code.
It shows the following error exception-
[ERROR:flutter/lib/ui/ui_dart_state.cc(186)] Unhandled Exception: FormatException: Could not find End of Central Directory Record
And I am not exactly getting whether the problem is in my download path or I need to make some changes in my coding example?
So, I need some suggestion to fix this exception and download and unzip my desired file from desired url.
This was likely caused by the fact that the file was not yet flushed to the filesystem after downloading before attempting to extract same.
To fix this update the _downloadFile method to the following
Future<File> _downloadFile(String url, String fileName) async {
var req = await http.Client().get(Uri.parse(url));
var file = File('$_dir/$fileName');
return file.writeAsBytes(req.bodyBytes, flush: true); // Added flush: true
}
From dart:io docs
Future<File> writeAsBytes(List<int> bytes, {FileMode mode = FileMode.write, bool flush = false})
Writes a list of bytes to a file.
Opens the file, writes the list of bytes to it, and closes the file. Returns a Future<File> that completes with this [File] object once the entire operation has completed.
By default [writeAsBytes] creates the file for writing and truncates the file if it already exists. In order to append the bytes to an existing file, pass [FileMode.append] as the optional mode parameter.
Note: --> If the argument [flush] is set to true, the data written will be flushed to the file system before the returned future completes.

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: How to display a short text file from assets on screen of phone?

I have ckecked all the answers about reading and writing file in Flutter. None of them answers the question of how to display a text file on the screen of the phone.
All I want to do is to have a function/method to call with the filename as input, which will display a short text file from my assets directory on a new screen on the phone that I have navigated to. The file is correctly placed in assets and mentioned in the yaml file. I have seen the suggestion to use:
Future loadAsset() async {
return await rootBundle.loadString('assets/my_text.txt');
}
but I don't know how to use it and what code to use to display a file on the screen.
You do not need to add Esen Mehmet's code to a new file. Suppose you are pressing a button which opens up the text file on a new page, you just need to add the below code in the same class :
Future _future;
Future<String> loadString() async =>
await rootBundle.loadString('assets/text.txt');
#override
void initState() {
_future = loadString();
super.initState();
And the below code in the body of the scaffold:
FutureBuilder(
future: _future,
builder: (context, snapshot) =>
Text(snapshot.hasData ? '${snapshot.data}' : ' Reading...')),
I suppose that you know how to display a Text on the Screen, so I will just try to explain how I normally read files.
First you have to import:
import 'package:path_provider/path_provider.dart';
import 'dart:io';
and then, in your class, you can use this:
Future<void> readMyFile() async {
Directory directory = await getApplicationDocumentsDirectory();
var _localFilePath = (directory.path + "yourfile.txt");
if (FileSystemEntity.typeSync(_localFilePath) == FileSystemEntityType.file) {
final myFile = await _localFile(_localFilePath);
List<String> linesAsList = await myFile.readAsLinesSync();
for (var i = 0; i < linesAsList.length; i++) {
//print("Line No: " + i.toString() + "\n");
print(linesAsList[i]);
}
}
}
Future<File> _localFile(String myPath) async {
return File(myPath);
}
At the end, the content of your file is in linesAsList as a list of lines.
First this code to have a new screen and call your code:
child:
FlatButton(
onPressed: () {
Navigator.pushNamed(context, '/indled');
setState(() {
ReadFile(fileName: 'myfile.txt');
print('Button 1 got pressed');
});
},
......
It prints Button 1 got pressed on console and goes fine to new screen indled, which has the code:
class Indled extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Indledning'),
),
body: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Expanded(
child: Container(
padding: EdgeInsets.all(8.0),
child: Text('Indledning 2'),
It prints 'Indledning 2' on the screen as a test, but nothing more happens. I have your code as the following in a separate file:
class ReadFile {
ReadFile({this.fileName});
final String fileName;
Future<void> readMyFile() async {
Directory directory = await getApplicationDocumentsDirectory();
var _localFilePath = (directory.path + "myfile.txt");
if (FileSystemEntity.typeSync(_localFilePath) ==
FileSystemEntityType.file) {
final myFile = await _localFile(_localFilePath);
List<String> linesAsList = myFile.readAsLinesSync();
for (var i = 0; i < linesAsList.length; i++) {
//print("Line No: " + i.toString() + "\n");
print(linesAsList[i]);
}
}
}
Future<File> _localFile(String myPath) async {
return File(myPath);
}
}
On the line: List linesAsList = await myFile.readAsLinesSync();
I get a warning on await: Await only futures
so I took out await. But same result if await is included.
I have tried to put fileName instead of "my file.txt" in your code, but same result.

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