I have the following piece of code to download and save a file on local phone device. I have a https url for a pdf file from AWS and I am trying to download it onto android.
await FileSystem.downloadAsync(uri, fileLocation)
.then(async(u) => {
if(ext === 'pdf') {
var status = await StorageAccessFramework.requestDirectoryPermissionsAsync();
if(!status.granted) {
return;
}
await StorageAccessFramework.createFileAsync(status.directoryUri, 'receipt' , 'application/pdf')
.then (async(r) => {
const form64data = await FileSystem.readAsStringAsync(u, {encoding: FileSystem.EncodingType.Base64})
await FileSystem.writeAsStringAsync(r, form64data, {encoding: FileSystem.EncodingType.Base64});
})
.catch((e) => {
if(e === undefined) {
return Toast.error(e)
else {return Toast.error(e.data.message)}
})
}
This code downloads the file onto 2 out of 3 actual devices. On 1 out of the 3 devices I see it always goes in the catch block and throws a undefined error in the Toast. on further debugging, I found that the createFileAsync function is not working as the file is not created at all on the device. Upon opening document picker , It always asks for permissions and folder to use but then throws a undefined error which I am unable to debug.
Need suggestions to debug and therefore, fix the issue . I do not have the actual device on which it fails to be able to see logs.
Related
I am now using the below cloud code to only update "downloads" column on my parse server running on AWS EC2 instance. But I am getting the error code 141(invalid function)
Parse.Cloud.define("updateDownloads", async (request) => {
const query = new Parse.Query(request.params.className);
query.get(request.params.objectId)
.then((watchFace) => {
downloads = watchFace.get("downloads")
watchFace.set("downloads", downloads + 1);
await watchFace.save(null, { useMasterKey: true });
return "download updated";
}, (error) => {
return "something went wrong";
});
});
I have place my code in /opt/bitnami/cloud/main.js.
I even tried adding “cloud”: “/opt/bitnami/cloud/main.js” in config.json file but then the parse server gives 503 Service Unavailable error. So I removed it.
If you don't add the cloud code main.js file to your parse server configuration, parse server will never find your function, and that's why you get the invalid function error.
If you get error when adding the file, you are either adding it in a wrong way (you need to check your parse server initialization code) or the config.json is in wrong format or the cloud code has a problem.
The best way to figure it out is by checking your logs.
At a first glance, a problem that I see (may have others) is the usage of await in a function that is not async. You are also using a combination of async and then, which is little strange.
I'd recommend you to change the code to something like:
Parse.Cloud.define("updateDownloads", async (request) => {
const query = new Parse.Query(request.params.className);
const watchFace = await query.get(request.params.objectId);
const downloads = watchFace.get("downloads");
watchFace.set("downloads", downloads + 1); // You can use inc function to avoid concurrency problem
await watchFace.save(null, { useMasterKey: true });
return "download updated";
});
I'm trying to save a video record from the camera to cordova.file.dataDirectory but I get a NOT_FOUND_ERR when I try to copy the newly created file from the gallery.
I'm using cordova-plugin-media-capture to record the video, which then is saved to the user's gallery. But when I get the FileEntry using window.resolveLocalFileSystemURL and try to use entry.copyTo() the NOT_FOUND_ERR error is thrown.
A cut down / messy version of my code is below:
// Capture Video
navigator.device.capture.captureVideo(onCaptureSuccess, onError, { limit: 1 });
onCaptureSuccess(mediaFiles: any[]) {
// Get video Path
let videoPath = mediaFiles[0].fullPath;
// Get the actual video file
window.resolveLocalFileSystemURL(videoPath, entry => {
// Get the cordova.file.dataDirectory directory entry
window.resolveLocalFileSystemURL(cordova.file.dataDirectory, directoryEntry => {
// Get / Create the 'videos' directory
directoryEntry.getDirectory('videos', { create: true }, videoDirectoryEntry => {
// Copy video file (entry) to 'videos' directory
entry.copyTo(videoDirectoryEntry, 'copiedVideo', copiedEntry => {
// I should now have a file entry of the copied video, but I don't. I get an error.
console.log(copiedEntry);
}, err => {
console.error(err); // This is where I capture the NOT_FOUND_ERR error
});
}, onError);
}, onError);
});
}
onError(error: Error) {
console.error(error.message)
}
Any idea why the file isn't being copied? Do I need to request specific permissions to write to cordova.file.dataDirectory?
After a lot of trial and error, it turns out I needed to request the READ_EXTERNAL_STORAGE and WRITE_EXTERNAL_STORAGE permissions for Android.
At a future date I'll check if any permissions are needed for iOS, but for now I'm happy that it's working for Android.
I am using this plugin for getting files
https://ionicframework.com/docs/native/file-chooser/
When I select a PDF file from Downloads folder it is giving me a URI like content://com.android.providers.downloads.documents/document/1015
But if i select another file like ZIP or PNG it resolves to a suitable path
content://com.android.providers.downloads.documents/document/raw%3A%2Fstorage%2Femulated%2F0%2FDownload%2Fwws.zip
content://com.android.providers.downloads.documents/document/raw%3A%2Fstorage%2Femulated%2F0%2FDownload%2Fopacity.png
How do I get the path from a file in the form of file://….
I have tried the following approaches with no success yet:
FilePath.resolveNativePath
and
normalizeURL
UPDATE:
Imports
import { File } from '#ionic-native/file';
import { FileChooser } from '#ionic-native/file-chooser'
import { FilePath } from '#ionic-native/file-path';
Code for file chooser:
getAndroidFile() {
this.fileChooser.open()
.then(uri => {
console.log("uri", uri);
this.file.resolveLocalFilesystemUrl(uri).then((files) => {
console.log("files", files);
}).catch((error) => { console.log("error", error) });
(<any>window).FilePath.resolveNativePath(uri, (result) => {
this.nativepath = result;
console.log("nativepath", this.nativepath);
}, (err) => {
console.log("err", err);
})
})
}
I have used it as Aaron suggested:
this.file.resolveLocalFilesystemUrl(uri).then((files)=>{
console.log("files",files);
}).catch((error) => { console.log("error", error) });
It still returns as:
filesystem: FileSystem {name: "content", root: DirectoryEntry}
fullPath: "/com.android.providers.downloads.documents/document/1015"
isDirectory: false
isFile: true
name: "1015"
nativeURL: "content://com.android.providers.downloads.documents/document/1015"
Which is the original url.
UPDATE 2:
getBase64Content(nativepath) {
let path = nativepath.substring(0, nativepath.lastIndexOf('/'));
let filename = nativepath.substring(nativepath.lastIndexOf('/'), nativepath.length);
filename = filename.replace("/", "");
console.log("path", path);
console.log("filename", filename);
this.file.readAsDataURL(path, filename)
.then(content => {
console.log('content1', content);
//this will be passed to web API
this.base64content = content;
})
.catch(err => {
console.log("err", err);
})
}
This base64 content is sent overthe to server via api and they convert it back to file.
UPDATE 3:
Sorry for late reply, really busy with another project.
Answers for Koken:
How are you testing this thing?
What command are you using for the execution?
ionic cordova run android
(I check the values by remote debugging using chrome.)
Android emulator? Android device?
Android Device. Redmi note 5 pro(MIUI 10, Android 8.1).
Also... what are the next steps after selecting the file?
This base64 content is sent over to server via api and they convert it back to file.
Hope you guys can help me. With code given. Thanks
you need resolveLocalFilesystemUrl from the FileManager Plugin
https://ionicframework.com/docs/native/file/#resolveLocalFilesystemUrl
I am using ionic 3.13.1 framework. My application should allow user to work with files from device and from google drive. I am using IonicNativeFile and IonicNativeFileChooser. So, when I select file from device memory - all works good, but I cannot use that method for google drive files. My function looks like:
public OpenFile(event: Event) {
this.fileChooser.open() //Open File Chooser
.then(uri => { //get uri
console.log(`URI: ${uri}`);
( < any > window).FilePath.resolveNativePath(uri, (result) => { //Get file path in storage from uri
this.nativepath = result;
console.log(`Native Path: ${this.nativepath}`);
this.readFile(); //read data from file
this.loader = this.loadingCtrl.create({ //Create and show loader message
content: "Loading..."
});
this.loader.present();
}, (error) => {
console.log(`Looks like file from GDrive: code ${error.code} message ${error.message}`);
});
}).catch(e => console.log(e));}
The uri is: content://com.google.android.apps.docs.storage.legacy/enc%3Di2Alapnkehx4uFSbuS2U3VO_rC-nrHu3Emq8u8eF4Z9w8QvL%0A
ResolveNativePath shoud return 1 if file is in cloud, but my function returns 0 with message: Unable to resolve filesystem path. I dont't know how to fix it.
Help me, please. What should I do to get path of file?
I am attempting to open a PDF file with FileOpener2 (through ng-cordova) with the following code:
$cordovaFile.checkFile(cordova.file.dataDirectory, attachmentPath)
.then((fileEntry) => {
// success
fileEntry.getMetadata((metadata) => {
// metadata.size is in bytes
var megabyteSize = metadata.size / 1048576;
if (megabyteSize > 5) {
var path = cordova.file.dataDirectory + attachmentPath;
console.log(path); // prints: file:///data/data/com.ionicframework.enhatch146189/files/attachments/CS-353ES_CS-420ES_Eng.pdf which is correct
$cordovaFileOpener2.open(path, 'application/pdf').then(() => {
console.log("Opened!") // prints
}, (error) => {
console.log(error);
usePDFJs(); // tries to render PDF in app with PDFJs
});
} else {
usePDFJs();
}
})
}, function (error) {
// error
console.error(error);
});
What happens confuses me: it prompts me with an "open this file in Adobe Reader?" and lists the other PDF viewers, and the console prints "Opened!"
However, no matter what I open ANY pdf in, I get some sort of error such as "cannot open this PDF file".
Can anyone see something wrong with this code?
Apparently, if you use cordova.file.dataDirectory on android you can't open those files in other applications or attach them to emails. Silly mistake -- coded too fast and read too little on the documentation. Using cordova.file.externalApplicationStorageDirectory solved the issue.