I'm using Phonegap 3.3.0, earlier i used 2.5.0 where entry.fullPath will give the Device full path.
These paths would typically look like
/var/mobile/Applications/<application UUID>/Documents/path/to/file (iOS)
/storage/emulated/0/path/to/file (Android)
since that method is deprecated am using entry.toURL() method to get the path.This method will now return filesystem URLs of the form
cdvfile://localhost/persistent/path/to/file
In My application, am passing the URL to Native function and from native am opening a file. But If I pass the path to Native, iOS could not able to detect the file. The same If i hardcode the Absolute path, application detects the file.
How to use the fileSystem URL to access the file in native or any other method to get the device absolute path ?
Thanks in advance.
The toURL() method or the nativeURL attribute should return the result wanted:
window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, function(fileSystem){
console.log("fileSystem.root.toURL()="+fileSystem.root.toURL());
console.log("fileSystem.root.toInternalURL()="+fileSystem.root.toInternalURL());
console.log("fileSystem.root.nativeURL="+fileSystem.root.nativeURL);
}, function(){
alert("fails!");
});
Using cordova 3.5, the output in iPad simulator is:
fileSystem.root.toURL()=file:///Users/myuser/Library/Application%20Support/iPhone%20Simulator/7.1/Applications/1717CB5F-4032-45C7-8CA2-342502447F36/Documents/
fileSystem.root.toInternalURL()=cdvfile://localhost/persistent/
fileSystem.root.nativeURL=file:///Users/myuser/Library/Application%20Support/iPhone%20Simulator/7.1/Applications/1717CB5F-4032-45C7-8CA2-342502447F36/Documents/
...and in Android simulator (Genymotion) is:
fileSystem.root.toURL()=file:///storage/emulated/0/
fileSystem.root.toInternalURL()=cdvfile://localhost/persistent/
fileSystem.root.nativeURL=file:///storage/emulated/0/
document.addEventListener("deviceready", onDeviceReady, false);
function onDeviceReady() {
console.log("device is ready");
window.requestFileSystem = window.requestFileSystem || window.webkitRequestFileSystem;
window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, gotFS, fail);
}
function fail() {
console.log("failed to get filesystem");
}
function gotFS(fileSystem) {
console.log("got filesystem");
// save the file system for later access
console.log(fileSystem.root.fullPath);
window.rootFS = fileSystem.root;
}
function downloadImage(url, fileName){
var ft = new FileTransfer();
ft.download(
url,
window.rootFS.fullPath + "/" + fileName,
function(entry) {
console.log("download complete: " + entry.fullPath);
},
function(error) {
console.log("download error" + error.code);
}
);
}
window.requestFileSystem = window.requestFileSystem || window.webkitRequestFileSystem;
window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, gotFS, fail);
function gotFS(fileSystem) {
alert("entered gotFS: " + fileSystem.root.toURL);
}
Related
As I am having real troubles debugging an app in Android / iOs, can someone tell me some simple test to check if Cordova File API is loaded and works ?
Something like:
document.addEventListener("deviceready", onDeviceReady, false);
function onDeviceReady() {
if(fileAPI){ // what can I test there ?
alert('File API is OK');
}
}
Try to request the FileSystem
window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, function(fs) {
alert("it works");
}, function (e) {
alert("it doesn't work");
});
I have a app using cordova 3.4 and file 1.1.0.
If I copy a image using the camera-modul, I use
myFileObj.path = file.toNativeURL()
to get the file-path. If I put this path into a img-tag I get shown the picture on Android.
On iOS it doesn't work. The result of file.toNativeURL():
myFileObj.path -> file:///Users/.../Library/Application%20Support/..../myFolder/myImage.JPG
Using file 1.0 I had to build the url and it looked like this:
myFileObj.path = dirTarget.toURL() + '/' + targetFileName
myFileObj.path -> cdvfile://localhost/persisten/myFolder/myImage.JPG
Where videos and audios didn't work, but at least pictures.
Using file 1.1.0/1.1.1 the result of this method is different too:
myFileObj.path -> file:///Users/mak/Library/.../myFolder/myImage.JPG?id=.....&ext=JPG
This doesn't work on iOS either.
How can I get a working file-path by using cordova file-module version 1.1.0 and 1.1.1?
EDIT: What am I doing and what doesn't work:
I copy images from the media-library and put it into a folder I create myself.
What works in Android and doesn't work in iOS:
In Android the media-tags src attribute is able to display the resource, iOS can't find a resource at the src-path.
catching a file from the media-library:
navigator.camera.getPicture(onSuccess, onFail, {
destinationType: Camera.DestinationType.NATIVE_URI,
sourceType : Camera.PictureSourceType.PHOTOLIBRARY,
mediaType: Camera.MediaType.ALLMEDIA
});
success-callback:
function onSuccess(imageData) {
A.StoreFile(imageData, id);
}
create a folder and store file:
A.StoreFile = function(file, idBox) {
var targetDirectory = Config.getRootPath();
window.resolveLocalFileSystemURL(file, resolveFileSystemSuccess, resolveFileSystemError);
function resolveFileSystemSuccess(fileEntry) {
fileEntry.file(function(filee) {
mimeType = filee.type;
getFileSuccess(fileEntry, mimeType);
}, function() {
});
}
function getFileSuccess(fileEntry, mimeType) {
var targetFileName = name + '.' + fileNativeType;
var parentName = targetDirectory.substring(targetDirectory.lastIndexOf('/')+1),
parentEntry = new DirectoryEntry(parentName, targetDirectory);
window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, function(fileSystem) {
fileSystem.root.getDirectory(targetDirectory, {create: true, exclusive: false}, function(dirTarget) {
fileEntry.copyTo(dirTarget, targetFileName, function(entry) {
addFileToLocalStorage(entry);
}, function() {
})
})
}, resolveFileSystemError);
}
store file-information to a localStorageObject
function addFileToLocalStorage(file) {
fileList.addFile(
{
name:file.name,
internalURL: file.toNativeURL()
});
}
adding files dynamically to the dom:
myElement.find('.myMimeTypeTag').attr('src', fileList[f].internalURL);
This works with android, and not with iOS.
iOS-result of img-container:
Error-message:
DEPRECATED: Update your code to use 'toURL'
toURL doesn't work either
id="org.apache.cordova.file"
version="1.1.1-dev"
I've just tested this out, with a slightly simplified version of your code (you seem to have a lot of extra structure to your code that isn't shown, but if there's a significant difference between what I've done here and what your app does, then let me know. The problem will be in the difference.)
I've run this with Cordova 3.5.0, just released, using File 1.1.0 and Camera 0.2.9.
To create the app, I used the cordova command line tool, and just ran
cordova create so23801369 com.example.so23801369 so23801369
cd so23801369
cordova platform add ios
cordova plugin add org.apache.cordova.file
cordova plugin add org.apache.cordova.camera
This creates a default "Hello, Cordova" app, to which I've added some code that (I believe) replicates what your code does.
I added two lines to index.html:
<button id="doit">Do it</button>
<img class="myMimeTypeTag" src="file:///nothing" />
And I edited www/js/index.js to look like this:
var app = {
initialize: function() {
// Don't activate the button until Cordova is initialized
document.addEventListener('deviceready', this.onDeviceReady, false);
},
onDeviceReady: function() {
document.getElementById('doit').addEventListener('click', app.runTest, false);
},
runTest: function(ev) {
var StoreFile = function(file) {
var targetDirectory = "myFolder";
window.resolveLocalFileSystemURL(file, resolveFileSystemSuccess, resolveFileSystemError);
function resolveFileSystemSuccess(fileEntry) {
console.log("resolveLocalFileSystemURL returned: ", fileEntry.toURL());
fileEntry.file(function(filee) {
mimeType = filee.type;
getFileSuccess(fileEntry, mimeType);
}, function() {
});
}
function resolveFileSystemError() {
console.log("resolveFileSystemError: FAIL");
console.log(arguments);
alert("FAIL");
}
function getFileSuccess(fileEntry, mimeType) {
var targetFileName = "myImage.JPG";
window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, function(fileSystem) {
fileSystem.root.getDirectory(targetDirectory, {create: true, exclusive: false}, function(dirTarget) {
fileEntry.copyTo(dirTarget, targetFileName, function(entry) {
console.log("copyTo returned: ", entry.toURL());
// I have replaced the localstorage handling with this code
// addFileToLocalStorage(entry);
var img = document.querySelector('.myMimeTypeTag');
img.setAttribute('src', entry.toNativeURL());
}, function() {
});
});
}, resolveFileSystemError);
}
};
var onSuccess = function(imageData) {
console.log("getPicture returned: ", imageData);
StoreFile(imageData);
};
var onFail = function() {
console.log("getPicture FAIL");
console.log(arguments);
alert("FAIL");
};
ev.preventDefault();
ev.stopPropagation();
navigator.camera.getPicture(onSuccess, onFail, {
destinationType: Camera.DestinationType.NATIVE_URI,
sourceType : Camera.PictureSourceType.PHOTOLIBRARY,
mediaType: Camera.MediaType.ALLMEDIA
});
}
};
When I run this, I can pick an image from the media library, and it successfully displays it in the page, with the image src set to the URL of the copied image file. If I connect Safari dev tools to the iPad, I see this console output:
[Log] getPicture returned: assets-library://asset/asset.JPG?id=F9B8C942-367E-433A-9A71-40C5F2806A74&ext=JPG (index.js, line 49)
[Log] resolveLocalFileSystemURL returned: cdvfile://localhost/assets-library/asset/asset.JPG?id=F9B8C942-367E-433A-9A71-40C5F2806A74&ext=JPG (index.js, line 18)
[Log] copyTo returned: file:///var/mobile/Applications/9C838867-30BE-4703-945F-C9DD48AB4D64/Documents/myFolder/myImage.JPG (index.js, line 36)
[Log] DEPRECATED: Update your code to use 'toURL' (Entry.js, line 202)
This shows the camera and file plugins going through three different types of URL:
Camera returns an assets-library:// URL, with query parameters to identify the asset
calling resolveLocalFileSystemURL on that turns it into a cdvfile:// URL, also with query paramaters, as an internal Cordova representation.
After being copied, File returns a new file:/// URL showing the image's new place on the filesystem. This URL has no query parameters. (Calling toNativeURL() on this entry returns the same URL now, as of File 1.1.0)
This final URL is usable by iOS as an image source, and so that's what gets assigned to the <img> element.
The problem was, that the new file-plugin has to be case-sensitve.
I created a folder with capital letters and refered the copy-instruction to a folder with lowercase letters. The point is that android is case insensitive and ios is not.
This came out with the new file-plugin where the output was case sensitive.
I am downloading a file to the local file system. I can successfully create the empty file via fileSystem.root.getFile but fileTransfer.download fails with FILE_NOT_FOUND_ERR even though it's using the same path.
The problem is that my file is being created at //sdcard/MyDir/test.pdf (I confirmed using adb shell) but the fileEntry returned a path without sdcard: //MyDir/test.pdf. fileTransfer.download fails with this path. It also fails with the relative path MyDir/test.pdf.
If I hardcode the full path with 'sdcard' in it I can avoid the FILE_NOT_FOUND_ERR (specifically, in FileTransfer.java the resourceApi.mapUriToFile call succeeds) but then I get a CONNECTION_ERR and the console shows "File plugin cannot represent download path". (In FileTransfer.java, the filePlugin.getEntryForFile call returns null. I assume it doesn't like 'sdcard' in the path.)
Is there a better way to specify the target path in fileTransfer.download?
var downloadUrl = "http://mysite/test.pdf";
var relativeFilePath = "MyDir/test.pdf"; // using an absolute path also does not work
window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, function (fileSystem) {
fileSystem.root.getFile(relativeFilePath, { create: true }, function (fileEntry) {
console.log(fileEntry.fullPath); // outputs: "//MyDir/test.pdf"
var fileTransfer = new FileTransfer();
fileTransfer.download(
downloadUrl,
/********************************************************/
/* THE PROBLEM IS HERE */
/* These paths fail with FILE_NOT_FOUND_ERR */
//fileEntry.fullPath, // this path fails. it's "//MyDir/test.pdf"
//relativeFilePath, // this path fails. it's "MyDir/test.pdf"
/* This path gets past the FILE_NOT_FOUND_ERR but generates a CONNECTION_ERR */
"//sdcard/MyDir/test.pdf"
/********************************************************/
function (entry) {
console.log("Success");
},
function (error) {
console.log("Error during download. Code = " + error.code);
}
);
});
});
I'm using the Android SDK emulator if that makes a difference.
I was able to resolve this by using a URI for the file's path. (I also removed the unnecessary call to fileSystem.root.getFile per #Regent's comment.)
var downloadUrl = "http://mysite/test.pdf";
var relativeFilePath = "MyDir/test.pdf"; // using an absolute path also does not work
window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, function (fileSystem) {
var fileTransfer = new FileTransfer();
fileTransfer.download(
downloadUrl,
// The correct path!
fileSystem.root.toURL() + '/' + relativeFilePath,
function (entry) {
console.log("Success");
},
function (error) {
console.log("Error during download. Code = " + error.code);
}
);
});
I am having a problem storing a file locally on an iOS (or android) device using apache cordova's "file" plugin. The problem I believe is setting the path properly.
this is the error message I get from Xcode
Could not create path to save downloaded file: The operation couldn\U2019t be completed. (Cocoa error 512.)
Here is the code where I am attempting to save the file locally:
<script type="text/javascript" charset="utf-8" src="cordova.js"></script>
<script type="text/javascript" charset="utf-8">
document.addEventListener("deviceready", onDeviceReady, false);
var root;
function onDeviceReady(){
// Note: The file system has been prefixed as of Google Chrome 12:
window.requestFileSystem = window.requestFileSystem || window.webkitRequestFileSystem;
window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, onInitFs, errorHandler);
}
function onInitFs(fs) {
var fileURL = "cdvfile://localhost/persistant/file.png";
var fileTransfer = new FileTransfer();
var uri = encodeURI("http://upload.wikimedia.org/wikipedia/commons/6/64/Gnu_meditate_levitate.png");
fileTransfer.download(
uri,
fileURL,
function(entry) {
console.log("download complete: " + entry.fullPath);
},
function(error) {
console.log("download error source " + error.source);
console.log("download error target " + error.target);
console.log("upload error code" + error.code);
},
false,
{
headers: {
"Authorization": "Basic dGVzdHVzZXJuYW1lOnRlc3RwYXNzd29yZA=="
}
}
);
}
function errorHandler(e) {
var msg = '';
switch (e.code) {
case FileError.QUOTA_EXCEEDED_ERR:
msg = 'QUOTA_EXCEEDED_ERR';
break;
case FileError.NOT_FOUND_ERR:
msg = 'NOT_FOUND_ERR';
break;
case FileError.SECURITY_ERR:
msg = 'SECURITY_ERR';
break;
case FileError.INVALID_MODIFICATION_ERR:
msg = 'INVALID_MODIFICATION_ERR';
break;
case FileError.INVALID_STATE_ERR:
msg = 'INVALID_STATE_ERR';
break;
default:
msg = 'Unknown Error';
break;
};
alert('Error: ' + msg);
}
</script>
Your file path contains a typo (or a grammar error):
var fileURL = "cdvfile://localhost/persistant/file.png";
You should write it as persistent.
Correct code:
var fileURL = "cdvfile://localhost/persistent/file.png";
Check out these links :
http://cordova.apache.org/docs/en/3.4.0/cordova_plugins_pluginapis.md.html#Plugin%20APIs
https://github.com/apache/cordova-plugin-file/blob/dev/doc/index.md
http://cordova.apache.org/docs/en/3.0.0/cordova_file_file.md.html#File
First and second links provide you information about the plugin File and how to install it.
The third one show you how to use the File plugin.
Everytime you need to do something with Cordova, check if a plugin is available to do it :)
regards.
So far I have only tested this on Android, but I believe it should work as-is, or with little modification on IOS:
var url = 'example.com/foo'
window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, function(fileSystem){
fileSystem.root.getFile('foo_file', {create: true, exclusive: false},
function(file_entry){
var ft = new FileTransfer()
ft.download(url, file_entry.toURL(), function(fe){
fe.file(function(f){
reader = new FileReader()
reader.onloadend = function(ev){
console.log('READ!', ev.target.result)
}
reader.readAsText(f)
})
})
}
)
})
Note that I also needed the contents of the file, so the bit at the end may be omitted if you don't need the contents at the time of downloading.
Also note that there is a far simpler method using window.saveAs but it's only available in Android 4.4.
Just getting started with PhoneGap File API / Cordova 3.0 and I have a little issue looking up a file
using getFile(). Don't know if the chaining is wrong. Or just missing the obvious...
I get to gotFS, passing in the full path as file:///storage/emulated/0/DCIM/Camera/... and the result is an error 5. I am guessing the path is not correct, or I can't get to storage/emulated?
The whole point is to return the file as a base64-encoded data URL e.g.,readAsDataURL.
// I just finished taking a video
//
function captureSuccess(mediaFile) {
// Store the results
//
window.media = mediaFile;
// Get started with the file request
//
window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, gotFS, fail);
function gotFS(fileSystem) {
// Get the path of the file
// Will return something like //file:///storage/emulated/0/DCIM/Camera/....
//
var fullPath = window.media[0].fullPath;
// Let's try and resolve, make sure I'm not crazy. I might be.
//
window.resolveLocalFileSystemURI(fullPath, winConvert, failConvert);
function winConvert(uri){
// The resolve matches file location stored at window.media
//
console.log(uri);
}
function failConvert(error){
console.log('Something happend resolving uri: '+error.code);
}
fileSystem.root.getFile(fullPath, null, gotFileEntry, fail);
}
function gotFileEntry(fileEntry) {
console.log('gotFileEntry');
fileEntry.file(gotFile, fail);
}
function gotFile(file){
console.log('gotFile');
readDataUrl(file);
}
function readDataUrl(file) {
var reader = new FileReader();
reader.onloadend = function(evt) {
console.log(evt.target.result);
};
reader.readAsDataURL(file);
}
function fail(error) {
console.log(error.code);
}
}