I am busy upgrading a Phonegap app from 3.3 to 3.5 everything works so far but the file download, opening isn't working
function downloadFile(url, filename, fail, downloadDone) {
window.fail = fail;
window.downloadDone = downloadDone;
window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, function onFileSystemSuccess(
fileSystem) {
var fileTransfer = new FileTransfer();
fileTransfer.download(url, window.filePath + filename, function(theFile) {
window.downloadDone();
}, function(error) {
window.fail(error);
});
}, window.fail);
}
function setupFilePath(callBack) {
window.callback = callBack;
window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, function onFileSystemSuccess(
fileSystem) {
fileSystem.root.getFile("dummy.html", {
create: true,
exclusive: false
}, function gotFileEntry(fileEntry) {
var sPath = fileEntry.root.replace("dummy.html", "");
window.filePath = sPath;
var fileTransfer = new FileTransfer();
fileEntry.remove();
dataDir = fileSystem.root.getDirectory(sPath + 'cordapp', {
create: true
});
window.filePath = sPath + 'cordapp/';
console.log("FILE PATH IS: " + window.filePath)
callBack()
}, null);
}, null);
}
Getting the error that the app can't create the directory what am I doing wrong? Is there also a way to not letting it backup to iCloud?
Related
I have been trying to store Audio file in persistent storage for two days without success.
So far I am able to create an audio file which records audio from Microphone (The app has the permission) using the code attached below.
The audio file is getting generated & stored successfully, I can play it.
But the real problem is when I close the app and come back and try to play the file it shows error.
"{"message": "Cannot use audio file from resource '/myrecording.wav'",
"code":1}"
The file is not persistent across app sessions even though I used LocalFileSystem.PERSISTENT.
I am not sure whether the problem is with my Media/Audio code or File storage code.
Please find the code attached below:
Below function records the audio from the microphone.
function _recordAudio() {
var deferred = $q.defer();
var src = "myrecording.wav";
alert("SRC:" + src);
window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, function (fileSystem) {
fileSystem.root.getFile(src, {
create: true,
exclusive: false
}, function (fileEntry) {
alert("File " + src + " created at " + fileEntry.fullPath);
var mediaRec = new Media(fileEntry.fullPath,
function () {
alert("Success");
}, function (error) {
alert("error:" + JSON.stringify(error));
});
// Record audio
mediaRec.startRecord();
// Stop recording after 10 sec
var recTime = 0;
var recInterval = setInterval(function () {
recTime = recTime + 1;
if (recTime >= 5) {
clearInterval(recInterval);
mediaRec.stopRecord();
deferred.resolve(fileEntry.fullPath);
}
}, 1000);
}, function (error) {
alert("getFile error:" + JSON.stringify(error));
deferred.reject();
}); //of getFile
}, function (error) {
alert("requestFileSystem error:" + JSON.stringify(error));
deferred.reject();
}); //of requestFileSystem
return deferred.promise;
}
Below function plays the audio.
function _play2() {
var src = "myrecording.wav";
window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, function (fileSystem) {
fileSystem.root.getFile(src, null, function (fileEntry) {
alert("File " + src + " created at " + fileEntry.fullPath);
var mediaRec = new Media(fileEntry.fullPath,
function () {
alert("Success play2");
}, function (error) {
//Getting error after closing and opening the app
//Error message = {"message": "Cannot use audio file from resource '/myrecording.wav'","code":1}
alert("error play2:" + JSON.stringify(error));
});
mediaRec.play();
});
});
}
I solved this problem by passing cdvfile: path to the Media plugin in PlayAudio function code and copying the file from Temp storage to persistent storage.
I had to use localURL of the file.
This part solved my problem:
fileEntry.file(function (file) {
_playNow(file.localURL);
}
For full functions refer code snippets below:
recordAudio: function (projectNo, ItemNo) {
try {
var deferred = $q.defer();
var recordingTime = 0;
_audioLoader = $("#audioLoader");
_audioLoader.show();
UtilityService.showPopup('audio');
_isRecording = true;
_recordFileName = "Audio_" + projectNo + "_" + ItemNo + ".wav";
_mediaRecord = new Media(_recordFileName);
//Record audio
_mediaRecord.startRecord();
var recordingInterval = setInterval(function () {
recordingTime = recordingTime + 1;
$('#audioPosition').text(_secondsToHms(recordingTime));
if (!_isRecording) {
clearInterval(recordingInterval);
_mediaRecord.stopRecord();
_mediaRecord.release();
deferred.resolve();
}
}, 1000);
//document.getElementById('audioPosition').innerHTML = '0 sec';
$('#audioPosition').text('0 sec');
return deferred.promise;
}
catch (ex) {
alert('WMMCPA|recordAudio:- ' + ex.message);
}
},
Get file path from the persistent storage and send it to the play method.
//To play recorded audio for specific project item
playAudio: function (projectNo, ItemNo) {
try {
_recordFileName = "Audio_" + projectNo + "_" + ItemNo + ".wav";
var newFileUri = cordova.file.dataDirectory + _recordFileName;
window.resolveLocalFileSystemURL(newFileUri, function (fileEntry) {
fileEntry.file(function (file) {
_playNow(file.localURL);
}, function (error) {
alert("WMMCPA|playAudio.file:-" + JSON.stringify(error));
});
}, function (error) {
alert("WMMCPA|playAudio.resolveLocalFileSystemURL:-" + JSON.stringify(error));
});
}
catch (ex) {
alert("WMMCPA|playAudio:-" + ex.message);
}
}
function _playNow(src) {
try {
var mediaTimer = null;
_audioLoader = $("#audioLoader");
_audioLoader.show();
UtilityService.showPopup('audio');
//Create Media object from src
_mediaRecord = new Media(src);
//Play audio
_mediaRecord.play();
} catch (ex) {
alert('WMMCPA|_playNow.mediaTimer:- ' + ex.message);
}
}, 1000);
} catch (ex) {
alert('WMMCPA|_playNow:- ' + ex.message);
I am running into a problem with my cordova app where after an app update, localStorage is cleared. I am now attempting to save some basic user data to a text file instead, using cordova's FileWriter and FileReader.
At some point cordova updated and these methods and now requires a plugin to read and write files: https://cordova.apache.org/docs/en/latest/reference/cordova-plugin-file/index.html
Because my live iOS application uses the old version of cordova, it must write with FileWriter. My app update (not live) uses a newer version of cordova and therefore must use the plugin.
------ Possible workaround found, see update below ------
When trying to read the file, I am seeing the following error in xcode:
017-01-26 17:58:52.990 MyApp[40355:2892997] ERROR: Method 'hello there' not defined in Plugin 'File'
2017-01-26 17:58:52.991 MyApp[40355:2892997] -[CDVCommandQueue executePending] [Line 142] FAILED pluginJSON = ["File1875336264","File","hello there",["cdvfile://localhost/persistent/player_data.txt",null,null]]
Note: I'm running the following code in Safari console while the iOS simulator is running, just for convenience
My code for writing the file
(function() {
var onFail = function(err) {
alert('write action failed!');
alert(err.code);
};
var onGotFS = function(fileSystem) {
alert( 'gotFS' );
fileSystem.root.getFile("player_data.txt", {create: true}, onGotFileEntry, onFail);
};
var onGotFileEntry = function(fileEntry) {
alert( 'gotFileEntry, path: ' + fileEntry.fullPath );
fileEntry.createWriter(onGotFileWriter, onFail);
};
var onGotFileWriter = function(writer) {
alert( 'gotFileWriter' );
writer.onwrite = onFileWritten;
writer.onerror = onFail;
var data = "hello there";
alert( 'writing data: ' + data );
writer.write( data );
};
var onFileWritten = function(evt) {
alert( "saveTokenToFile SUCCESS!" );
};
// start process of looking up file system and writing
alert( 'requesting file system ...' );
window.requestFileSystem(LocalFileSystem.PERSISTENT, 1024, onGotFS, onFail);
})();
My code for reading the file:
(function() {
window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, function (fs) {
fs.root.getFile("player_data.txt", { create: true }, function (fileEntry) {
fileEntry.file(function (file) {
var reader = new FileReader();
reader.onloadend = function() {
alert("Success");
console.log(evt.target.result);
};
reader.onerror = function() {
console.log("reader error");
};
reader.readAsText(file);
}, onErrorReadFile);
});
}, onErrorLoadFs);
var onErrorReadFile = function(){
console.log("error reading file");
}
var onErrorLoadFs = function() {
console.log("request file system has failed to load.");
}
})();
UPDATE
In case anyone else runs into this, I did find a way to read the saved file. The fileEntry object has a URL path to the saved file. To access the data on the file, I'm passing that URL to jQuery.getJSON, which gives us back some readable json.
readDataFromFile: function(){
window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, function (fs) {
fs.root.getFile("player_data.txt", {}, function (fileEntry) {
var entryURL = fileEntry.nativeURL;
jQuery.getJSON(entryURL, function(data) {
console.log(data);
}).fail(function(){
console.log("file found, but contents were empty");
});
}, onErrorGetFile);
}, onErrorLoadFs);
var onErrorLoadFs = function() {
console.log("request file system has failed to load.");
};
var onErrorGetFile = function() {
console.log("requested file can not be read or does not exist");
};
}
I have to upload an image to server using multi-part image upload from my ionic project. Here is my code,
$scope.uploadImage = function(imageUrl) {
var fileName = imageUrl.substring(imageUrl.lastIndexOf('/')+1);
var json= {
"id":123,
"name" :fileName
}
var fileUploadOptions = new FileUploadOptions();
fileUploadOptions.fileKey="file";
fileUploadOptions.fileName = fileName;
fileUploadOptions.params = {
json : json
};
fileUploadOptions.mimeType="image/jpeg";
var URL = 'http://192.168.43.7:8080/services/uploadImage'
var encodedURI = encodeURI(URL);
console.log('fileUploadOptions : ',fileUploadOptions);
var ft = new FileTransfer();
ft.upload(imageUrl, encodedURI, onSuccess, onError, fileUploadOptions, false);
function onSuccess(response){
console.log('file uploaded: ',response);
}
function onError(error){
console.log('upload failed',error);
}
}
I am using the following plugins
cordova-plugin-file
cordova-plugin-file-transfer
cordova-plugin-camera
My image capture code is
$scope.takePhoto = function() {
var options = {
quality: 75,
destinationType: Camera.DestinationType.FILE_URI,
sourceType: 1,
allowEdit: false,
encodingType: 0,
targetWidth: 1280,
targetHeight: 720,
popoverOptions: CameraPopoverOptions,
direction: 1,
saveToPhotoAlbum: true
};
var cameraSuccess = function(imageData) {
onPhotoURISuccess(imageData);
function onPhotoURISuccess(imageURI) {
createFileEntry(imageURI);
}
function createFileEntry(imageURI) {
window.resolveLocalFileSystemURL(imageURI, copyPhoto, fail);
}
function copyPhoto(fileEntry) {
window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, function(fileSys) {
fileSys.root.getDirectory("photos", { create: true, exclusive: false }, function(dir) {
var fileName = 12 + "_" + 56 + "_" + 67 + ".jpg";
fileEntry.copyTo(dir, fileName, onCopySuccess, fail);
}, fail);
}, fail);
}
function onCopySuccess(entry) {
console.log('Full path: ', JSON.stringify(entry));
var path = entry.toURL();
$scope.imageUrl = path;
console.log('imageUrl: ',$scope.imageUrl);
}
function fail(error) {
console.error(JSON.stringify(error));
var cause = "";
if (error.code == 20) {
cause = "Camera permission denied"
}
}
}
var cameraError = function(error) {
console.log('camera error: ', error);
}
navigator.camera.getPicture(cameraSuccess, cameraError, options);
}
I am passing the $scope.imageUrl variable to upload function.
The code works fine in android devices.
But iOS, the upload fails.
I am getting
com.fasterxml.jackson.databind.JsonMappingException: No content to map due to end-of-input
error in my server console.
In my device console I am getting the following error,
upload failed
body: "An error has occurred. Please contact system administrator."
code: 3
exception: null
http_status: 500
source: "file:///var/mobile/Containers/Data/Application/8C4518AC-5606-4806-A8D2-216125EFE725/Documents/photos/12_56_57.jpg"
target: "http://192.168.43.7:8080/services/uploadImage"
The message in the body of the error is from my server.
As per the error I get from server, I came to know that, the JSON part is not getting uploaded to server. I tried to recreate the same issue with postman without sending the JSON object. I got the same error.
Do anyone know what is the issue ? Why only in iOS device this issue is there ?
From the docs:
params: A set of optional key/value pairs to pass in the HTTP request. (Object, key/value - DOMString)
Try using fileUploadOptions.params = { json : JSON.stringify(json) } instead.
var imageUrI="file:///storage/emulated/0/newfile.csv";
var options = new FileUploadOptions();
options.fileKey = "file";
options.fileName = imageURI.substr(imageURI.lastIndexOf('/') + 1);
options.mimeType = "image/jpeg/csv";
var params = new Object();
params.value1 = "test";
params.value2 = "param";
options.params = params;
options.chunkedMode = false;
var ft = new FileTransfer();
ft.upload(imageURI, "http://fileupload/admin/add_image_my.php",
function (result) {
console.log(JSON.stringify(result));
},
function (error) {
console.log(JSON.stringify(error));
}, options);
I am trying to send a voice recording that I recorded via the Media plugin.
When I try to send the file I get this FileError.NOT_FOUND_ERR error:
Error opening file /myRecording100.wav: Error Domain=NSCocoaErrorDomain Code=260 "The operation couldn’t be completed. (Cocoa error 260.)" UserInfo=0xa358640 {NSFilePath=/myRecording100.wav, NSUnderlyingError=0xa34fb30 "The operation couldn’t be completed. No such file or directory"}
2014-08-06 17:02:26.919 Bring Me[40961:c07] FileTransferError {
code = 1;
source = "/myRecording100.wav";
target = "http://XXXX.xom";
}
However, I can play the voice recording after recording it.
Why would I be able to play the file (showing that the file was recorded and saved correctly) but FileTransfer be unable to send it?
Here is my code (for ios):
var my_recorder = null;
var mediaFileFullName = null; // iOS
var mediaRecFile = "myRecording100.wav";
var checkFileOnly = false;
/******
Call when start recording
******/
function startRecording() {
checkFileOnly = false;
window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, onSuccessFileSystem, function() {
console.log("***test: failed in creating media file in requestFileSystem");
});
}
function onSuccessFileSystem(fileSystem) {
if (checkFileOnly === true) {
// Get File and send
fileSystem.root.getFile(mediaRecFile, { create: false, exclusive: false }, onOK_GetFile, onFail_GetFile);
}
else {
// Create File
fileSystem.root.getFile(mediaRecFile, { create: true, exclusive: false }, onOK_SaveFile, onFail_GetFile);
}
}
/* Save the file*/
function onOK_SaveFile(fileEntry) {
mediaFileFullName = fileEntry.fullPath;
my_recorder = new Media(mediaFileFullName,
function() { document.location ="address_form.html"; // Redirect the user to an other page },
function(err) { console.log("playAudio():callback Record Error: "+err);}
);
my_recorder.startRecord();
}
/* Get the file and send it */
function onOK_GetFile(fileEntry) {
mediaFileFullName = fileEntry.fullPath;
/*
// Read the recorded file is WORKING !
my_player = new Media(mediaFileFullName, onMediaCallSuccess, onMediaCallError);
my_player.play();
*/
var options = new FileUploadOptions();
options.fileKey = "want";
options.fileName = "file.wav";
options.mimeType = "audio/wav";
options.chunkedMode = false;
options.params = parameters;
var ft = new FileTransfer();
ft.upload(mediaFileFullName, "https://SERVER_ADDRESS", win, fail, options);
}
/******
Called when stop recording
******/
function stopRecording() {
if (my_recorder) {
my_recorder.stopRecord();
}
}
Since the v1.0 of File plugin, to upload a file in the filesystem via the file-transfer plugin, you'll need to use the .toURL() method to access to it.
If you are upgrading to a new (1.0.0 or newer) version of File, and
you have previously been using entry.fullPath as arguments to
download() or upload(), then you will need to change your code to use
filesystem URLs instead.
FileEntry.toURL() and DirectoryEntry.toURL() return a filesystem URL
of the form
So the correct code is :
/* Get the file and send it */
function onOK_GetFile(fileEntry) {
var options = new FileUploadOptions();
options.fileKey = "want";
options.fileName = "file.wav";
options.mimeType = "audio/wav";
options.chunkedMode = false;
options.params = parameters;
var ft = new FileTransfer();
ft.upload(fileEntry.toURL(), "https://SERVER_ADDRESS", win, fail, options);
}
I got the exact same issue on iOS,and FileUploadOptions didn't work for me.
In case someone is struggling as well, the solution for me has been to switch to LocalFileSystem.Temporary.
Here there is a snippet which shows a full example (not tested on Android):
var accessType = LocalFileSystem.TEMPORARY; // It was LocalFileSystem.PERSISTENT;
/** Utility function to return a fileEntry together with the metadata. */
var getFile = function(name, create, successCallback, failCallback) {
WL.Logger.debug("Request for file " + name + " received, create is " + create + ".");
var onSuccessFileSystem = function(fileSystem) {
fileSystem.root.getFile(name, { create: create, exclusive: false },
function(fileEntry){
WL.Logger.debug("Success, file entry for " + name + " is " + JSON.stringify(fileEntry));
fileEntry.getMetadata(function(metadata){
WL.Logger.debug("File entry " + name + " metadata is: " + JSON.stringify(metadata));
successCallback(fileEntry, metadata);
}, function(err) {
WL.Logger.debug("Fail to retrieve metadata, error: " + JSON.stringify(err));
if(failCallback) failCallback(err);
});
},
function(err) {
WL.Logger.error("Failed to retrieve the media file " + name + ".");
if(failCallback) failCallback(err);
});
}
window.requestFileSystem = window.requestFileSystem || window.webkitRequestFileSystem;
window.requestFileSystem(accessType, 0, onSuccessFileSystem, function(err) {
WL.Logger.error("Failed to access file system.");
if(failCallback) failCallback(err);
});
};
var Recorder = declare([ ], {
mediaSrc : null,
mediaObj : null,
constructor : function(data, domNode){
this.mediaSrc = "new_recording.wav";
},
startRecord : function() {
var self = this;
var startRecording = function(source) {
var onMediaCallSuccess = function() { WL.Logger.debug("Media object success."); };
var onMediaCallError = function(err) { WL.Logger.error("Error on the media object: " + JSON.stringify(err)); };
self.mediaObj = new Media(source, onMediaCallSuccess, onMediaCallError);
self.mediaObj.startRecord();
};
// On iOS, first I need to create the file and then I can record.
if (deviceCheck.phone.ios) {
WL.Logger.debug("iOS detected, making sure the file exists.");
getFile(this.mediaSrc, true, function(fileEntry){ startRecording(fileEntry.fullPath); });
} else {
if (!deviceCheck.phone.android)
WL.Logger.warn("Don't know the device, trying to record ...");
else
WL.Logger.debug("Android detected.");
startRecording(this.mediaSrc);
}
},
stopRecord : function() {
this.mediaObj.stopRecord();
this.mediaObj.release();
},
play: function() {
var p,
playSuccess = function() { WL.Logger.debug("Play success."); p.release(); },
playFail = function() { WL.Logger.debug("Play fail."); };
p = new Media(this.mediaSrc, playSuccess, playFail);
p.play();
},
getData : function(successCallback, failCallback) {
var fileName = (deviceCheck.phone.android ? "/sdcard/" : "") + this.mediaSrc;
WL.Logger.debug("Asking for the file entry ... ");
getFile(this.mediaSrc, false,
function(fileEntry, metadata) {
WL.Logger.debug("Success: I found a file entry: " + fileEntry.nativeURL + ", size is " + metadata.size);
fileEntry.file(function(file) {
WL.Logger.debug("Success: file retrieved!");
var reader = new FileReader();
reader.onloadend = function(evt) {
WL.Logger.debug("Sending content and event data to success callback.");
successCallback(this.result, metadata, evt);
};
reader.readAsDataURL(file);
}, function(err){
WL.Logger.error("Error: Impossible to retrieve the file");
failCallback(err);
})
}, function(err){
WL.Logger.error("Fail: no file entry found: " + JSON.stringify(err));
failCallback(err);
});
}
});
There is a bit of Worklight (debug output) and dojo (declare), but this code could be useful as reference.
i am developing a phonegap project in mac os with xcode. in xcode if i create a cordova based application it automatically creates cordova-1.6.0.js. i am using fileupload plugin for sending svg file to my server. in fileupload.js i have written alert fileuplaoder function as following,
var FileUploader = function() {
alert("gi");
}
this alert is working, but when i give the aler under upload function,
FileUploader.prototype.upload = function(server, file, params, fileKey, fileName, mimeType, success, fail, progress) {
alert("upload");
this._doUpload('upload', server, file, params, fileKey, fileName, mimeType, success, fail, progress);
};
this alert is not working. my call for this plugin in html page is,
window.plugins.fileUploader.upload('http:192.168.1.54:8080/downloadFiles', '/Users/User/Library/Application Support/iPhone Simulator/5.0/Applications/408DBBC7-67F7-4E8B-B41C-663CDC0377B5/Documents/image5_1.jpg.txt.svg', {foo: 'bar'}, 'myPhoto', 'image5_1.jpg.txt.svg', 'image/svg',
function(result) {
console.log('Done: ' + result);
},
function(result) {
console.log("Error: " + result);
},
function(loaded, total) {
var percent = 100 / total * loaded;
console.log('Uploaded ' + percent);
}
);
in fileupload.js there is cordova.addConstructor method. but in my generated cordova.1.6.0.js file there is no such method. i dont know whats happening. pl help me to work this plugin.
i found the solution. there is a upload and download options in the cordova file api itself. its working fine. the code is,
document.addEventListener("deviceready", onDeviceReady, false);
// Cordova is ready
//
function onDeviceReady() {
window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, gotFS, fail);
}
function gotFS(fileSystem) {
fileSystem.root.getFile("image5_2.jpg.svg", {create: true, exclusive: false}, gotFileEntry, fail);
}
function gotFileEntry(fileEntry) {
var localpath=fileEntry.fullPath;
uploadPhoto(localpath);
//fileEntry.createWriter(gotFileWriter, fail);
}
function uploadPhoto(imageURI) {
alert(imageURI);
var options = new FileUploadOptions();
options.fileKey="file";
options.fileName="image5_2.jpg.svg";
options.mimeType="image/svg+xml";
var params = new Object();
params.value1 = "test";
params.value2 = "param";
options.params = params;
var ft = new FileTransfer();
ft.upload(imageURI, "http://192.168.1.54:8080/POC/fileUploader", win, fail, options);
}
function win(r) {
console.log("Code = " + r.responseCode);
console.log("Response = " + r.response);
console.log("Sent = " + r.bytesSent);
}
function fail(error) {
alert("An error has occurred: Code = " + error.code);
console.log("upload error source " + error.source);
console.log("upload error target " + error.target);
}
pl use this.