In the past week I've gotten a few emails from folks working with the file system in PhoneGap/Cordova apps. Recently, the plugin had a major update and if you weren't paying attention to the docs/blogs, it would be easy to miss.
First, see the blog post from the Cordova site: Plugins Release: Feb 10, 2014. Second - you can get even deeper docs at the plugin Github repo docs: Docs. Finally, as the changes here were intended to bring the plugin closer to the core HTML5 FileSystem API, you should refresh your memory with the excellent HTML5Rocks article and the official spec as well.
I started up a fresh project for iOS and had no problem accessing the file system, but I didn't do anything too complex. If folks want to talk specifics, I can try to create a specific demo, but again, I strongly recommend reading the plugin doc.
Archived Comments
wow you helped me solve one of my biggest problems....thank you raymonnd ..brilliant article...it would be so helpful if you could make a demo for andriod...amazing blog though:)
Do you have a specific example you would like to see?
Hello Raymond,
Thanks for the heads-up regarding this, I would have been very confused otherwise, I'm sure!
However, I'm running into an issue that I wonder if you might be able to shed some light on.
I'm recording audio files using the Media plugin. After a recording has successfully completed, I want to move the file to another directory using the File plugin. Prior to the update to the File plugin, I did something like <a href="https://gist.github.com/ros...">this</a>, which worked as the filesystem root and the location that the Media plugin initially saved the recording were the same.
Now the filesystem root is relative to my app's "private" directory (which is cool), I'm not sure how to go about reliably resolving the location of the saved recording so I can move it.
I've tried window.resolveLocalFileSystemURL, without success thus far.
I've also tried recording directly to the target directory (therefore removing the requirement to move the file at all), but passing targetDir.toURL() as the src param to Media doesn't seem to work.
I'm only targeting Android, currently.
Am I going about this the wrong way, or missing something obvious?
Thanks!
Oops, sorry about the mangled gist link.
https://gist.github.com/ros...
yes raymond ...i wish you could make a sample demo project for android about accessing to filesystems and searching for a particular file with a specific name for example...
@omid: Well the first question is - do you know what folder you want to look in?
With being able to write to the internal file system now, does this improve security at all? We were looking into storing javascript files via the phonegap file api, but then realized there's the possibility of people editing those files we stored using the file api which could then inject code into our apps. Thanks for posting this tidbit!
yes presume that we know the folder..actually we make and choose this folder
@Tom: I honestly do not know. You would need to check the Android/iOS docs (not PhoneGap) for info on how it treats the file system and apps. My guts say to NOT trust it. Period. Much like a "normal" client side app (and remember you can store data on the desktop websites too with LocalStorage, IndexedDB,etc) you should always assume that the user can modify the values. That to me isn't a deal breaker. Being able to store stuff locally is incredibly important, but you just have to remember that it can't be trusted in terms of secured operations.
So omid - it should just work. I mean the docs that show how to list a directory, that still works fine. These changes are more involved about *where* you start off with when opening the file system.
I am using the filetransfer plugin to download images from the server to the local file system. I get a path like 'cdvfile://localhost/persistent/...' at the end which i store for future reference. I use these cached paths to refer these images in my html using the image tag
<img src="cdvfile://localhost/persistent/...'"/>
This works fine when the first time but when i restart the app or navigate to some other page which iss using the same image the image doesn't load. I am seeing this behavior on simulator and on a physical device. Could you please try this out and let me know if there is some thing wrong with the way i am using the path.
Also i use a nexus 5 for debugging and i am not able to locate the files on my device.
yeah, it works ,thanks raymond:)
For all who are having trouble with reading files from another direcotry (not root). This example lists all pictures within your DCIM/Camera folder:
document.addEventListener("deviceready", onDeviceReady, false);
function onDeviceReady() {
window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, onFSSuccess, FileError);
}
//Be careful! The onFSSuccess needs the parameter fileSystem!
//The directory path is without the prefix of the root directory!
function onFSSuccess(fileSystem) { fileSystem.root.getDirectory("DCIM/Camera/", {create: false, exclusive: false}, doDirectoryListing, FileError);
}
//dirEntry needs to be a parameter of the function!
function doDirectoryListing(dirEntry) {
var directoryReader = dirEntry.createReader();
directoryReader.readEntries(gotFiles, FileError);
}
function gotFiles(entries)
{
for(var i=0,len=entries.length; i<len; i++)
{
//Name of the picture within "DCIM/Camera"
alert(entries[i].name);
}
}
//This function won´t get executed if you forgot the parameter(s) of the functions
function FileError(e)
{
alert("Fehler");
}
Thanks to RaymondCamden and SimonMacDonald!
I store gpx files locally for openlayers to display. The file paths starting with '/' and cdvfile://localhost/, that are returned by fullPath and toURL, will not work. Only a path starting with file:/// will work. Is this possible in cordova 3?
Have you tried setting the img src to a cdvfile url?
I'm not trying to display an image, I'm tring to draw a gpx track which is an xml file, for example: http://wiki.openstreetmap.o... (see line 'url: "around_lake.gpx",'. The cdvfile url URL does not work.
Hmm. If we ignore GPX for a bit - if you do a regular XHR to the cdv url, do you get a response?
No I get an error doing a XHR to the cdv url.
Hmm, I don't know. I apologize - these new changes are confusing to me as well. What I would recommend is - post to the Google group for PhoneGap and ask about this, specifically - why you can't access the file via XHR. It seems like you should be able to. When you get a response, can you let us know?
Hi Raymond,
Your blogs are very much helpful in getting a better understanding of the concepts. Thanks to you, many of my project issues were resolved even without posting in any group.
Reg filesystem, am facing the same issue as Vinay:
I am using the filetransfer plugin to download images from the server to the local file system. I get a path like 'cdvfile://localhost/persistent/...' at the end which i store for future reference. I use these cached paths to refer these images in my html using the image tag
<img src="cdvfile://localhost/persistent/...'"/>
This works fine when the first time but when i restart the app or navigate to some other page which iss using the same image the image doesn't load. I am seeing this behavior on simulator and on a physical device.
Could you please help us resolve the same?
Thank you.
I've recently upgraded and I'm having issues witht he file plugin. previously I could get a fullpath to an image that was in the gallery (android) using the code below. But now I can't. always returns undefined.
any suggestions?
window.resolveLocalFileSystemURL(imageURI, function(fileEntry) {
fileEntry.file(function(fileObj) {
newimageURI = fileObj.fullPath;
alert(newimageURI);
});
});
@mathew
fileObj.toURL() to be used instead of fileObj.fullPath
Please refer:
https://github.com/apache/c...
Tried that fileObj.toURL() but only get this error...
03-07 10:08:08.123: I/Web Console(2170): processMessage failed: Stack: TypeError: Object [object Object] has no method 'toURL'
The image in question is located in the content://media/external .... but earlier in the week when I ran the above code it returned a full image address. now nothing. I'm trying to get the address so I can use fileupload to send to a server. works fine for images captured using the camera but not from stored images.
Thanks.
Matthew
@mathew please try fileObj.localURL
@Priya I tried fileObj.localURL and it does return a slightly different url but still not the true file path. content://media/external/images/media/86 is the imageURI then the localURL returns the same. if I select a resized version it only gives me a link to the resize.jpg with a time stamp. where the fullPath used to return a true path to the original file (if I selected a none resized image). Is there an easy way to save the resized timestamp version locally which I rename and then get access to that?
Thank you for pointing out the update. Please do you have a blog post or a demo app set up to demonstrate filesysytem access in a phonegap app? What I'm particular about is how would one go about calling up the device file system and have a user select a file and probably upload to a remote server.
The selection process is my major concern as the docs for accessing the filesystem are centered around getting a 'known' file and not leaving the user to browse and select 'any' file residing somewhere on their device. Any ideas?
I do have an earlier blog entry on the file system where I demonstrate getting a listing, which is what you would need to do. It doesn't let them browse/select, but thats the only other piece you need. Ie, add links and if they click a directory, do a listing on that then. I'll see if I can blog something more formal, but it may be a while.
Thank you Raymond, while I wait for that new post, please give me the url to the old post you referred to.
Hmpth, now I can't find it. I'd suggest just browsing my phonegap blog entries via my search.
Hello Raymond,
thanks for this article. I have an issue by accesing the filesystem.
I download cordova-3.4 and copied the cordova.js for android system.
Before 3.4 I was using 2.9.1.
The problem is LocalFileSystem is undefined. In 2.9.1 it was defined. I looked
into the source of cordova.js and could not find LocalFileSystem. In cordova.js
of version 2.9.1 I could find it.
Are there other files I have to include in my index.html?
Did you add the FIleSystem plugin? Remember everything in Cordova 3.X runs via plugins you *must* install first.
Yes, due the releasenotes I have version 1.0.1 (Feb 28, 2014)
I'd double check then. The error you report is pretty much exactly the one you get when trying to use a feature w/o the plugin installed.
Hmm, I use Zend Studio 10.6 to install my phonegap plugins. The ide creates a config.xml where you can add and remove Plugins you want.
Can I check somehow which version of plugin I have installed?
I checked in plugin.xml.. This is the repository where the file plugin will be fetched:
https://git-wip-us.apache.o...
The console in Eclipse/Zend Studio says:
Fetching plugin from location "org.apache.cordova.file"...
And I see the plugins in the plugins/ directory of the project.
Is it possible I just have to add other *.js files then cordova.js...
I get it in this directory of the download file...
...\Downloads\cordova-3.4.0\cordova-android\framework\assets\www
I would recommend *not* using Zend Studio to install plugins. It may not be working right. I don't know that for a fact of course, but I'd suggest using the *documented* way for now.
Hmm okay, I will try it with the documented way. I let you know if it worked. Thank you very much :-)
Hello Raymond. Is it correct that value of fileSystem.root.fullPath can be just: "/"??
Or should I get something like "file///..."
I am using android 4.3 and phonegap 2.9...
Maybe zend studio really did not install the plugin correctly.
Thank you for answer :-)
Please see the upgrade notes about the FileSystem API. This in particular may be applying to you:
"With v1.0.0, the fullPath attribute is the path to the file, relative to the root of the HTML filesystem"
https://github.com/apache/c...
Hello again Raymond,
sorry to ask you again. I would be happy if you can answer this:
I need the directory entry of the "download" folder of android.
Therefore i wrote:
window.resolveLocalFileSystemURL('cdvfile://external/persistent/storage/emulated/0/Download', function(a) {
console.log(a);
}, InfopoolFileDownloadRepository.errorOccured);
Permissions of app are WRITE_EXTERNAL_STORAGE, READ_EXTERNAL_STORAGE
Thank you
And? You didn't say what went wrong - if anything.
Hehe you are right..
Well, first I tried with: 'file:///...' but I always got error code 5.
So,
window.resolveLocalFileSystemURL('file:///storage/emulated/0/Download', function(a) {
console.log(a);
}, MyObj.errorOccured);
AND
window.resolveLocalFileSystemURL('cdvfile:///storage/emulated/0/Download', function(a) {
console.log(a);
}, MyObj.errorOccured);
wont work.
Using cordova 3.4 and Android 4.3.
Any idea why?
Thank you.
From what I can see, 5 implies an encoding error, but I'm not sure how that applies here. I also did some Googling, and from what I can see, Android devs are *not* supposed to assume a particular folder, but rather call an API to get the folder. I think if you wanted to do this with Cordova, you would need to build a plugin that just exposed this API so you could call it from JS. In theory not too difficult to do - but you would need to write some Java.
Hello all.
Was happy to stumble upon this thread, as I'm having some difficulty with the filesystem on a cordova project I'm working on. Having difficulty trying to access the actual file produced by the media capture plugin, despite having the full path of the file.
Details are in a Stack Overflow post that has gone unanswered for the past few days:
http://stackoverflow.com/qu...
Any ideas? Any help would be greatly appreciated.
Thanks.
Posted a comment.
Hello Sir
In the new file system, we are facing one major issue.
The css styles are not applied to any html files that are residing in the library\caches folder
though it is not a linked style sheet. Even the inline styles are not getting applied.
please let me know any workaround.
Hmm. I'd suggest checking w/ Remote Debugging to see if you can get a detailed error report. Best I can suggest then is to post it to the Google Group.
Hi
Ihave the same issue as matthew.
did anybody find a solution?
thank you
Hello Raymond,
I am new to Phonegap and is searching for information on the file API I found your blog and thought maybe you can help me with the File API. The app captures the path a user is following using geolocation's watch mode. The path points are stored into a variable with a predefined file format known as GPX (an XML type of file for GPS data).
I need to create the actual GPX file and allow the user to send it by email. To do so I am using the File and the Email Composer with attachments APIs and I cannot yet figure out how to connect both.
The path points data is stored in a javascript variable named "gpxcontents". Using the file API, I am creating and storing the file to be emailed (track.gpx) as follows:
function createGPX(fs) {
fs.root.getFile('track.gpx', {create: true}, function(fileEntry) {
// Create a FileWriter object for our FileEntry (track.gpx).
fileEntry.createWriter(function(fileWriter) {
fileWriter.onwriteend = function(e) {
console.log('Write completed.');
};
fileWriter.onerror = function(e) {
console.log('Write failed: ' + e.toString());
};
// Create a new Blob and write it to log.txt.
var blob = new Blob([gpxcontents], {type: 'text/plain'});
fileWriter.write(blob);
}, errorHandler);
}, errorHandler);
}
window.requestFileSystem(window.LocalFileSystem.PERSISTENT, 5*1024*1024, createGPX, errorHandler);
Now, using Email Composer, I am building this function:
function emailTrack(){
window.plugins.emailComposer.showEmailComposerWithCallback(callbackEmail,'Track File','Track File sent from
Mobile App',[] //toRecipients
,[] //ccRecipients
,[] //bccRecipients
,false //isHtml
,[] //attachments
,[] //attachmentsData
);
}
and have the following questions:
1. What shall be used as a "callbackEmail" function? is it mandatory or optional?
2. How can I capture the path to the "track.gpx" file and add it to the attachment section of the email composer?
3. What is the difference among "attachments" and "attachmentsData"? Shall both be used and if so how?
I am using Phonegap Build with version 3.3 to compile the app.
Thanks forany help you may provide.
'1. What shall be used as a "callbackEmail" function? is it mandatory or optional?'
I don't know this plugin. If their docs do not make this clear, you should file a bug report with them so they can make it clear.
'2. How can I capture the path to the "track.gpx" file and add it to the attachment section of the email composer? '
The fileEntry object you used earlier should be copied to a global scope, like window.myFile = fileEntry. The full path is part of the FileEntry object - I believe just something.fullPath.
'3. What is the difference among "attachments" and "attachmentsData"? Shall both be used and if so how?'
See #1. ;)
http://www.html5rocks.com/e...
Based on the above article, Chrome is going to stop working on the FileSystem APIs. How is this going to affect the Cordova FileSystem plugin?
Thanks in advance.
I don't know to be honest - but I do know you can subscribe to the Cordova dev list where they discuss stuff exactly like this.
Hi,
I'm also having trouble reading file. I used navigator.camera.getPicture api to take or get photo from library and i manage to save it to file system using destinationType: Camera.DestinationType.1 The location of photo something like this;
file:///Users/xxx/Library/Application%20Support/iPhone%20Simulator/7.1-64/Applications/87329C6B-9D22-4639-AA68-5A25607234DA/tmp/cdv_photo_041.jpg
I've also managed to send photo using;
var ft = new FileTransfer();
ft.upload(file_uri, encodeURI(url), photo_upload_success, photo_upload_fail, options);
But somehow couldn't manage to read image to show in html.
I used different thinks like;
- remove first part of uri;
imageURI = imageURI.substr(8);
- don't remove
- etc.
Lastly i tried this function but still same;
function get_image(imageURI){
console.log(imageURI);
var reader = new FileReader();
reader.onloadend = function(evt) {
console.log('-------------onloadend');
};
console.log('111');
window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, gotFS, fail);
console.log('222');
function gotFS(fileSystem) {
console.log('gotFS');
//fileSystem.root.getFile('tmp.tmp', {create: false, exclusive: false}, gotFileEntry, fail);
fileSystem.root.getFile(imageURI, null, gotFileEntry, fail);
}
function gotFileEntry(fileEntry) {
console.log('fileEntry');
console.log(imageURI);
reader.readAsBinaryString(imageURI);
console.log('333');
}
function fail(error) {
console.log('fail');
console.log(error.code);
console.log(error);
}
}
Does anyone has a working example to read image from file system on IOS?
Thanks
In the future, please do not post large code blocks here.
So - to be clear, you just want to show an image that you selected w/ getPicture?
Sorry about it, you are right, if you want you can delete it i'll sent pastebin link.
Correct, i just would like to show an image from fileurl. I don't use DATA_URL as destinationType to avoid memory problem.
I did a quick test and for me it worked ok. I created a virgin Cordova project and removed some of the DOM. I added an image tag with id of IMG. Here is the JS I used - it was written quickly so it isn't pretty. But it does work. I can select from the gallery and when I get the URI, I can set it to the DOM.
https://gist.github.com/cfj...
Thanks Raymond for all your great articles.
@Alberto - I saw an email composer that said to put 'null' as the callback. The callback feature was added in order to be compatible with something.
window.plugins.emailComposer.showEmailComposerWithCallback(null,'Track File','Track File sent from ...
Can someone help me with attaching a file to an email? I have a web sql form that is exported to a text file through javascript. Logcat in Android Eclipse says the file is saved to cdvfile://localhost/temporary/profile.txt: 6124. The file is in the cache folder of my app.
I am using the katzer email compoer. He says to attach a file like this -
window.plugin.email.open({
attachments: [
'file://storage/sdcard/icon.jpg', //=> Android
He says it can be used for text files to, but I can't get it to work. I even changed the file name to jpg.
Thanks Raymond, i was trying to read file, but i saw that it more easy to use uri directly.
Thank you so much for help and also for article.
Hi Raymond, thanks for your post. I cannot write a file on the private memory of an android application. Please could you try and help me? This is my stackoverflow post:
http://stackoverflow.com/qu...
I am new to phonegap but I think it would be used much more if there was more support of stackoverflow ...
Thank you
I was at a conference - it looks like you got the support you needed.
yes I managed it, Thanks for your job and help anyway.
@Glen,
Sorry for my late reply, I just saw your post. Thanks for your comment. I had figured out the role of that function and it seems to be needed by iOS somehow.
Anyway, we have figured out how to work with the new File API and native file paths. There is a new method "toNativeURL() " that allows to convert a fileEntry path to a native file path. Please check this thread in the Phonegap Build Community Forum for more details:
http://community.phonegap.c...
I hope it helps.
Greetings
Hello Sir,
Is there any way, where we could use the cordova api functions inside a local page that opens up in inappbrowser.
say sample.html which is opened in inappbrowser. This html uses jquery and cordova.js files.
'document ready' is triggered but device ready is not triggered and iam unable to use any of the cordova functionalities. Is there any work around for this. as i need access to cordova.js functionality and also the local database files to fetch and display the details.
Thanks
In theory, yes, but it will not be easy. Only the parent doc can do "Cordova stuff", and you can't "talk" to the parent from the child. The closest you can do is poll for messages from the parent. See this: http://blogs.telerik.com/ap...
I used the barcode scanner plugin that i found in repository and now i am working on that after i scan like said 10 items i want to save it text file and send that text file through email in iphone/ipad.
Any help would be greatly appreciated.
Thank you
@bharat: Your question is a bit broad. Can you ask one specific question to narrow it down?
I have a page hosted online accessed that page in my phonegap application but now i want to come back to my local files in
file:///android_asset/www/profile.html
but it gives me error:
08-21 14:08:00.324: E/Web Console(8304): Not allowed to load local resource: file:///android_asset/www/profile.html at null:0
How do I fix this issue.
I don't quite understand your question. How are you trying to load that file?
Trying to access local page in href
<a href="file:///android_asset/www/hyperextend.html';">Ext</a>
super.loadUrl("http://www.web.com/app/andr...");
one page is added on my local folder and want to open that page using <a href="file:///android_asset/www/hyperextend.html';">Ext</a>
If it is local, why are you using file:///? Just link to hyerextend.html.
But my index file in online web.com/index.html and i need only one file due to some reasons online and after that file need to come back to my local files
Then I wouldn't do that I guess. I'd fetch the remote content from a local index.html.
There is a method that can be used to return to the 1st page... it's not ideal but it might be of use.
window.history.go( -( history.length - 1 ) );
I have this question on http://stackoverflow.com/qu... , i want to download file from my app? whats wrong there am not getting....Help me!