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 visual studio to create cordova mobile application and I'm using Cordova-plugin-file for file manipulation on device.
How to write to a text file in a specific path in android device,
to be able to get it from a fixed location.
You can try below code. Also you can find good explanation for the code in Cordova Example: Writing to a file & Exploring the FileSystem APIs.
As a very short explanation: you should install cordova file plugin, after device ready, you first will ask for a FileSystem then will create the file in a particular path (in my example:cordova.file.dataDirectory) and finally will write to it.
document.addEventListener('deviceready', function () {
window.resolveLocalFileSystemURL(cordova.file.dataDirectory, function (dirEntry) {
dirEntry.getFile("log.txt", { create: true }, function (fileEntry) {
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(['Lorem Ipsum'], { type: 'text/plain' });
fileWriter.write(blob);
}, errorHandler);
});
});
}, false);
I want to create a folder in the internal storage of my device, but not in the root directory, which will store the audios I've recorded using my app. I've tried using the following code to implement the same:
fileSys.root.getDirectory('file:///storage/sdcard/records', {create: true, exclusive: false},function(d) {
window.resolveLocalFileSystemURL($scope.sound.file, function(fe) {
fe.copyTo(d, filename, function(e) {
console.log('success in copy');
console.dir(e);
$scope.sound.file = e.nativeURL;
$scope.sound.path = e.fullPath;
}, function(e) {
console.log('error in copy');console.dir(e);
});
}, function(e) {
console.log("error in directory");
console.dir(e);
});
}, function(e) {
console.log("error in file");
console.dir(e);
});
But an error(code = 5) is generated when I implement the above code. Can someone point out the error in the above code so the directory is created and file is copied to the specified location?
I had the same issue and I preferred to use https://github.com/torrmal/cordova-simplefilemanagement which wraps native storage api.
Then you can do something like this:
var a = new DirManager(); // Initialize a Folder manager IF does not exists
a.create_r("NewFolder", function () {/* Notify dir creation*/ });
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.
Hi im currently trying to create an gallery app with phonegap build, but i cant read files from the local storage. I`m using this function:
function listDir(directoryEntry){
var directoryReader = directoryEntry.createReader();
directoryReader.readEntries(function(entries){ // success get files and folders
for(var i=0; i<entries.length; ++i){
alert(entries[i].name) // this is just for checking purposes, no matter what i put here it wont fire
}
}, function(error){ // error get files and folders
alert(error.code);
});
}
function getFileSystem(){
window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, function(fileSystem){ // success get file system
var sdcard = fileSystem.root;
sdcard.getDirectory('dcim',{create:false}, function(dirEntry){
listDir(dirEntry);
}, function(error){
alert(error.code);
})
}, function(evt){ // error get file system
console.log(evt.target.error.code);
});
}
getFileSystem();
The listDir function wont even fire (the error function wont too). I have tried to add an "OnDeviceReady" listener to call the getFileSystem() function but it wont work too, plus i have tried toons of ways, even using the official phonegap docs, but it cant read my directory. Anyone know how to do this (im currently using android)? Thanks in advance.
You need remember that the cordova api is async.
This code read the list of files in my app external storage directory:
function getFilesList(callback) {
console.log('getFilesList');
var fileList = [];
function onDirResolved(dir) {
var reader =dir.createReader();
reader.readEntries(function(entries) {
console.log('readEntries');
for (var i=0; i<entries.length; i++) {
if (entries[i].name.indexOf(".fototoon") != -1) {
fileList.push(entries[i].fullPath);
};
};
console.log('fileList ' + fileList);
callback(fileList);
}, errorHandler);
};
function onFsResolved(fs) {
window.resolveLocalFileSystemURL(
cordova.file.externalApplicationStorageDirectory,
onDirResolved, errorHandler);
};
window.requestFileSystem(LocalFileSystem.PERSISTENT, 0,
onFsResolved, errorHandler);
};
The callback function will receive the list of files read.