How to download a pdf file using Flutter? - flutter

void getHttp() async
{
print("Got called");
var response = await Dio().download('https://www.google.com/', 'assets/xx.html');
print("DDDDD:");
print(response);
}
The directory assets is present with read and write permissions.
I am calling this on the press of a button. "Got called" DOES get printed.
There are no errors present, still "DDDDD" doesn't get printed.
The xx.html doesn't get saved.
Where am I going wrong?

Based on documentation the syntax for Dio to download a file is
var response = await Dio().download('https://www.google.com/', <<Destination directory from which your app is running. Like internal storage or external storage.>>);
I guess you are providing the file path which is associated with the projects assets directory where the file cannot be downloaded since it is bundled with the app.
Use the following package to access the device file system and provide that path to download your file.
var response = await Dio().download('https://www.google.com/', <<Path from internal storage.>>);

Related

Sharing a text file (csv) with share_plus: "unable to attach file"

I want to get data from Firestore, convert it into csv format, then share it using the user's method of choice (e.g. email). I'm using the csv package to convert the data to csv, the path_provider to get the directory to write the file to the phone, and the share_plus package to share the file.
However, when I tap a share method (e.g. Gmail, Outlook, Whatsapp), it opens the right app but then I get a message on the phone like "Unable to attach file" (but there is no error in my app). The file is definitely being written as I can read it and it comes back with the expected string. The ShareResultStatus that is returned by the share is 'successful' Can anyone figure it out what the problem is and how to fix it?
Here is my code:
Future exportData() async {
// Dummy data (in reality, this will come from Firestore)
List<List> dummyData = [
['Date', 'Piece', 'Rating'],
[DateTime.utc(2022, 05, 01), 'Sonata', 4],
[DateTime.utc(2022, 05, 02), 'Sonata', 2],
];
// Turn into CSV
String csvData = _convertToCsv(dummyData);
// Write to local disk
await _writeData(csvData);
// Share
String filePath = await _filePath;
final result =
await Share.shareFilesWithResult([filePath], mimeTypes: ['text/csv']);
print(result.status);
}
And here are the functions used in above code:
Future<String> get _filePath async {
final directory = await getApplicationDocumentsDirectory();
return '${directory.path}/my_practice_diary_data.csv';
}
Future<File> _writeData(String csvData) async {
String filePath = await _filePath;
final file = File(filePath);
return file.writeAsString(csvData);
}
String _convertToCsv(List<List> data) {
String result = const ListToCsvConverter().convert(data);
return result;
}
Note: I've tried doing it both as txt and csv files, got same result
*** EDIT (06/06/2022): After a lot of reading and watching youtube videos, I have come to realise that the problem is that the directory getApplicationDocumentsDirectory() is only accessible by my app (and hence the app that is is being shared to, like gmail, cannot read it).
For now I have worked around it by using the package mailer and using user's google credentials to send emails (I followed these helpful youtube tutorials: Flutter Tutorial - How To Send Email In Background [2021] Without Backend and Flutter Tutorial - Google SignIn [2021] With Firebase Auth - Android, iOS, Flutter Web.
However, it would still be nice to know a nice way to generate a file and share it using share_plus, as per my original question. I believe that this can be achieved via one of two ways:
Find a way to allow other apps to access this specific file in the app directory; or
Find a way to download the file into an external storage (like downloads folder), then share that. (I cannot find a way to do this on both Android and iOS).
Anyone who knows how to do these or any other solution to the problem, please share!

How to retrieve multiple different files form firebase to flutter

I don't want to upload my code but I am having problems with retrieving multiple files from firebase storage. So in my app, I want to make users upload different files and while uploading it will show up in a list form.
The thing is I am able to save files into the firebase storage but I am freaking out trying to retrieve them into my application. I really hope if I get some to help me with this.
I don't exactly know what you're trying to achieve but maybe this would help.
When you upload your file to firestore storage, get a download link of that file and store it in the collection. Then you can retrieve the list of files you have uploaded.
Get the download URL of the uploaded file
UploadTask imageUploadTask = storageReference.putFile(file);
await imageUploadTask.whenComplete(() async {
mediaURL = await imageUploadTask.snapshot.ref.getDownloadURL();
print("download url = $mediaURL");
return mediaURL;
}).catchError((err){
print(err.toString());
});
Save URL to the collection
final CollectionReference _filesCollectionReference = FirebaseFirestore.instance.collection("files");
Map<String, String> file = {
"downloadURL" : url,
};
var result = await _filesCollectionReference.add(file);
Retrieve files
await _filesCollectionReference.get();

Getting DetailedApiRequestError when uploading a file to google drive with pre-generated file id

I want my users to be able to back-up their data on google drive. I used the "Try it now" tool of google drive to generate a file id, because if I don't set file id before uploading the file, the drive.files.create() method creates a new file id after every upload to google drive.
First I import google drive API.
import 'package:googleapis/drive/v3.dart' as ga;
This is how I create the file I want to upload:
// Create the file we want to upload.
ga.File fileToUpload = ga.File();
var file = await _localFile;
fileToUpload.parents = ["appDataFolder"];
fileToUpload.name = path.basename(file.absolute.path);
// Setting a generated id from the "Try it now" tool.
fileToUpload.id = "1azltlNpZEt6RyUBNwdYUAWPZv2o6w7bP";
And this is how I upload it to google drive:
var response = await drive.files.create(
fileToUpload,
uploadMedia: ga.Media(file.openRead(), file.lengthSync()),
);
The response I get is: "Unhandled Exception: DetailedApiRequestError(status: 403, message: Method not supported for files within the Application Data folder.)"
If I remove the next line when I create the file:
fileToUpload.parents = ["appDataFolder"];
And then I try to upload the file, I get: "DetailedApiRequestError(status: 403, message: The user does not have sufficient permissions for this file.)"
If I don't set the file id, which means I remove the next line:
fileToUpload.id = "1azltlNpZEt6RyUBNwdYUAWPZv2o6w7bP";
Then I can upload the file to google drive. But it's not helping me because it creates a new file id.
Is there anything I can do?
Edit: The problem with google drive generating a new file Id every time the user syncing the app data on google drive, is that it means that after every sync, I need to save the new file id on a server (so I can retrieve the file when needed). And when there are many active users that backing their data multiple times a day, all those update calls to the service would cost me too much money. So I prefer that the file Id will always stay the same.

I can't upload data from my app to dropbox

I can't upload data from my app to dropbox. I always gets this error:
'Error in call to API function "files/upload": HTTP header "Dropbox-API-Arg": path: \'\\Songs\\539f67c172ec78e3f7608a64537616a5.mp3\' did not match pattern \'(/(.|[\\r\\n])*)|(ns:[0-9]+(/.*)?)|(id:.*)\'',
I created dropbox app, generated app access token and added token in my env file.
const uploadSong = async (file, song) => {
const destination = path.join(process.env.DROPBOX_UPLOAD_PATH, song.asset_sound.fileNameFull);
console.log('Uploading to DROPBOX ...', destination);
return await dbx.filesUpload({ path: destination, contents: file.buffer, mode: 'overwrite'});
};
The path you're supplying to the path parameter of filesUpload should be the remote Dropbox path where you want to upload the file. It should be formatted like '/path/to/file.ext'.
You're supplying something like '\Songs\539f67c172ec78e3f7608a64537616a5.mp3'. I imagine you mean to supply something like '/Songs/539f67c172ec78e3f7608a64537616a5.mp3' instead.

Flutter integration test - how to load a JSON file?

I am writing a Flutter integration test with a mock client that returns a JSON response for each of the REST endpoints my app calls.
These JSON responses are stored in separate JSON files, but I am unable to access the files when the test is running.
I've tried loading the files by creating and reading a new file object. Flutter: how to load file for testing but it could never find the file.
I also tried putting my JSON files into assets. This worked, but also resulted in the test JSON files being bundled when I built the APK.
Simplified Mock Client:
MockClient integrationMockClient = MockClient((request) async {
switch (request.url.toString()) {
case 'https://staging.company.com/api/123':
return Response(readJsonfile('myJsonFile.json'), 200);
Simplified integration test main function - passes mock client in. test_driver/app.dart
void main() async {
enableFlutterDriverExtension();
final app = await initializeApp(
integrationMockClient
);
runApp(app);
}
When I try and read a file it can never find it. Possible because flutterDriver runs the 'real app' with no access to files stored in test directories.
How can I access a JSON file from an integration test without it being bundled in production code/APK?
I encountered similar issues accessing file resources using flutter driver for integration tests. What I did as a workaround was to parse the JSON response directly, instead of storing the JSON response as a file.
Here's a sample that you can try out. This uses https://jsonplaceholder.typicode.com as its endpoint sample.
test('Test http', () async {
final file = await http.get(Uri.parse('https://jsonplaceholder.typicode.com/albums/1'));
final json = jsonDecode(file.body.toString());
print('json contents: $json');
print('userId: ${json['userId']}');
final userId = json['userId'];
expect(userId, 1);
});
Put JSON into String variable, like this. const String objectJson = """{JSON}""";
Wrap your JSON with a triple quotation mark """
and use it on integration tests, instead of reading it from a file