I am trying to download some image files and store it for offline accessibility purpose of the app using Ionic framework. I have used two Cordova plugins named "Cordova-plugin-file" and "Cordova-plugin-file transfer". My code works on Android but faces a strange issue in iOS platform.
Error in Success callbackId: FileTransfer552364304 : TypeError: null
is not an object (evaluating 'result.lengthComputable'),
callbackFromNativecordova.js
Sometimes the code works, sometimes it throws me this error. Also I cannot access the error from my javascript code. Can anyone help? The code snippet is given below:
downloadImage: function(url, fileName) {
var deferred = $q.defer();
window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, function(fs) {
fs.root.getDirectory(
LOCAL_STORAGE_KEYS.app, {
create: true
},
function(dirEntry) {
// console.log(arguments);
dirEntry.getFile(
fileName, {
create: true,
exclusive: false
},
function(fe) {
console.log(arguments);
var p = fe.toURL();
console.log("In service the url path:", p);
fe.remove();
var ft = new FileTransfer();
console.log('File Transfer instance:',ft);
ft.download(
encodeURI(url),
p,
function(entry) {
console.log('In service the entry callback:',entry);
if (entry && entry.toURL) {
deferred.resolve(entry.toURL());
} else {
deferred.resolve();
}
},
function(err) {
console.log('Getting rejected:',err);
deferred.reject(err);
},
false,
null
);
},
function() {
deferred.reject(new Error('get file failed'));
}
);
}
);
},
function() {
deferred.reject(new Error('get directory failed'));
});
return deferred.promise;
}
Related
I am using below code to write a file on android using PhoneGap, I think that this line window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, function (fs) { is giving the error, can't find the exact error, just because I can't debug on android.
I find PhoneGap documentation confusing.
function download_file(cur_filename)
{
alert(5);
window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, function (fs) {
alert(2);
console.log('file system open: ' + fs.name);
alert(3);
fs.root.getFile(cur_filename, { create: true, exclusive: false }, function (fileEntry) {
alert("fileEntry is file?" + fileEntry.isFile.toString());
// fileEntry.name == 'someFile.txt'
fileEntry.name==cur_filename;
// fileEntry.fullPath == '/someFile.txt'
writeFile(fileEntry, null);
}, onErrorCreateFile);
}, onErrorLoadFs);
}
function writeFile(fileEntry, dataObj) {
aler(4);
// Create a FileWriter object for our FileEntry (log.txt).
fileEntry.createWriter(function (fileWriter) {
fileWriter.onwriteend = function() {
console.log("Successful file write...");
readFile(fileEntry);
};
fileWriter.onerror = function (e) {
console.log("Failed file write: " + e.toString());
};
// If data object is not passed in,
// create a new Blob instead.
if (!dataObj) {
dataObj = new Blob(['some file data'], { type: 'text/plain' });
}
fileWriter.write(dataObj);
});
}
Firstly, you can directly download the file rather than having to create and write a new one. You need to first install the following plugins
cordova plugin add cordova-plugin-file
cordova plugin add cordova-plugin-file-transfer
Now, you need to enclose the below logic inside deviceready event in case you are accessing plugins on app launch. The file-transfer ships with a download() that you need to use for downloading your file. Please find a sample code below
document.addEventListener("deviceready", startDownload, false);
function startDownload() {
var fileTransfer = new FileTransfer();
// replace uri with -> http://192.168.43.54/text.csv
var uri = encodeURI("https://file-examples.com/wp-content/uploads/2017/04/file_example_MP4_1920_18MG.mp4");
fileTransfer.download(
uri,
cordova.file.dataDirectory + 'videos/big_buck_bunny_720p_1mb.mp4',
function(entry) {
console.log("download complete: ", entry);
},
function(error) {
console.log("download error source " + error.source);
console.log("download error target " + error.target);
console.log("download error code" + error.code);
}
);
}
Once the download is completed, the entry object will have a nativeURL property that holds the local URL to the file.
More info
File Plugin
File-Transfer Download
In Chrome Apps, I'm downloading a blob content from a server using JavaScript XHR (Angular $http GET in particular, with response type 'blob')
How should I save this to chrome application's file system?
Currently using an Angular wrapper on HTML5 filesystem API
https://github.com/maciel310/angular-filesystem
I do not want to show user a popup (hence I can't use chrome.fileSystem. chooseEntry )
The chrome.fileSystem.requestFileSystem API is only supported by Kiosk-only apps.
Hence I'm using HTML5 FileSystem API instead of chrome's.
I'm using following code to make XHR to fetch blob.
$http({
url: SERVER_URL+"/someVideo.mp4",
method: "GET",
responseType: "blob"
}).then(function(response) {
console.log(response);
fileSystem.writeBlob(response.name, response).then(function() {
console.log("file saved");
}, function(err) {
console.log(err);
});
}, function (response) {
});
This is my writeBlob method
writeBlob: function(fileName, blob, append) {
append = (typeof append == 'undefined' ? false : append);
var def = $q.defer();
fsDefer.promise.then(function(fs) {
fs.root.getFile(fileName, {create: true}, function(fileEntry) {
fileEntry.createWriter(function(fileWriter) {
if(append) {
fileWriter.seek(fileWriter.length);
}
var truncated = false;
fileWriter.onwriteend = function(e) {
//truncate all data after current position
if (!truncated) {
truncated = true;
this.truncate(this.position);
return;
}
safeResolve(def, "");
};
fileWriter.onerror = function(e) {
safeReject(def, {text: 'Write failed', obj: e});
};
fileWriter.write(blob);
}, function(e) {
safeReject(def, {text: "Error creating file", obj: e});
});
}, function(e) {
safeReject(def, {text: "Error getting file", obj: e});
});
}, function(err) {
def.reject(err);
});
return def.promise;
},
This shows SECURITY_ERR as It was determined that certain files are unsafe for access within a Web application, or that too many calls are being made on file resources.
What's the solution for this?
I've tried using --allow-file-access-from-files flag while launching app. It doesn't help.
Chrome Application's sandbox storage doesn't allow files to be stored in root directory (i.e. / )
Modify the code to save it in a specific sub-directory under it.
For example -
fileSystem.writeBlob("/new"+response.name, response).then(function() {
console.log("file saved");
}, function(err) {
console.log(err);
});
This would successfully save the file under /new/ directory.
To expand on this, here is a full example app on how to download a file and save the blob and display it back to the user.
https://github.com/PierBover/chrome-os-app-download-example
I am trying to get slingshot to work but having a hard time, I am attaching here the code I have.
The error I get n the console is:
"Exception in delivering result of invoking 'slingshot/uploadRequest': TypeError: Cannot read property 'response' of undefined"
client
Template.hello.events({
'change .uploadFile': function(event, template) {
event.preventDefault();
var uploader = new Slingshot.Upload("myFileUploads");
uploader.send(document.getElementById('uploadFile').files[0], function (error, downloadUrl) {
if (error) {
// Log service detailed response
console.error('Error uploading', uploader.xhr.response);
alert (error);
}
else{
console.log("Worked!");
}
});
}
});
lib
Slingshot.fileRestrictions("myFileUploads", {
allowedFileTypes: ["image/png", "image/jpeg", "image/gif"],
maxSize: null // 10 MB (use null for unlimited)
});
server
Slingshot.fileRestrictions("myFileUploads", {
allowedFileTypes: ["image/png", "image/jpeg", "image/gif"],
maxSize: null,
});
Slingshot.createDirective("myFileUploads", Slingshot.S3Storage, {
AWSAccessKeyId: "my-AWSAccessKeyId",
AWSSecretAccessKey: "my-AWSSecretAccessKey",
bucket: "slingshot-trial-2",
acl: "public-read",
authorize: function () {
//Deny uploads if user is not logged in.
},
key: function (file) {
//Store file into a directory by the user's username.
return file.name;
}
});
I saw the same issue and it was due to xhr being null - try removing the console error line that references it and I'm assuming you'll start seeing the alert with the actual error message:
console.error('Error uploading', uploader.xhr.response);
I ended up putting in a check for xhr before referencing it and then logging it if it existed.
I have literally spent the last 6 hours trying to persist data using phonegap, my first approach was using the localStorate API but that was killed everytime the app restarted so it was useless. Now I implemented it by writing a file to the the filesystem, but with the following problems:
The file is created ok
The file has the corrent content doing adb pull /data/data/[package name]/friends.txt) I can see the content of the file
But trying to read from it I always get NULL.
This is my code if anyone can help me... I am out of ideas now :(
var friends = [];
// Initialize the Facebook SDK
document.addEventListener('deviceready', function() {
FB.init({
appId: '[myAppID]',
nativeInterface: CDV.FB,
useCachedDialogs: false
});
// Check if we already fetched our friends
readSavedContent();
});
function readSavedContent() {
window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, gotFileSystemForRead, fail);
}
function gotFileSystemForRead(fileSystem) {
fileSystem.root.getFile("friends.txt", {create: true, exclusive: false}, gotFileEntryForRead, fail);
}
function gotFileSystemForWrite(fileSystem) {
fileSystem.root.getFile("friends.txt", {create: true, exclusive: false}, gotFileEntryForWrite, fail);
}
function gotFileEntryForRead(fileEntry) {
var reader = new FileReader();
reader.onloadend = function(evt) {
alert("Data stored is " + evt.target.result);
};
reader.readAsText(fileEntry);
}
function gotFileEntryForWrite(fileEntry) {
fileEntry.createWriter(gotFileWriter, fail);
}
function gotFileWriter(writer) {
writer.onwriteend = function(evt) {
// show a message
alert(friends.length + " friends fetched, you should be able to see them if you restart the app");
};
writer.write(JSON.stringify(friends));
}
function fail(error) {
console.log(error.code);
alert(error);
}
function login() {
FB.login(function (response) {
console.log(JSON.stringify(response));
if (response.status === "connected") {
alert("logged in: fetching friends now");
// Fetch my friends
FB.api("/fql?q=" + encodeURIComponent('SELECT uid, first_name, last_name, email, pic, pic_big, is_app_user, devices FROM user WHERE uid IN (SELECT uid2 FROM friend WHERE uid1= me()) ORDER BY first_name LIMIT 2000'),
function(response) {
friends = response.data;
// Store the data to the disk
window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, gotFileSystemForWrite, fail);
}
);
} else {
alert('not logged in');
}
}, {
scope: "email"
});
}
From what I can see you have forgotten one step during the file read operation.
In your case you have this order:
function gotFileSystemForRead(fileSystem) {
fileSystem.root.getFile("friends.txt", {create: true, exclusive: false}, gotFileEntryForRead, fail);
}
function gotFileEntryForRead(fileEntry) {
var reader = new FileReader();
reader.onloadend = function(evt) {
alert("Data stored is " + evt.target.result);
};
reader.readAsText(fileEntry);
}
When it should look like this:
function gotFileSystemForRead(fileSystem) {
fileSystem.root.getFile("friends.txt", {create: true, exclusive: false}, gotFileEntry, fail);
}
function gotFileEntry(fileEntry) {
fileEntry.file(gotFileEntryForRead, fail);
}
function gotFileEntryForRead(file) {
var reader = new FileReader();
reader.onloadend = function(evt) {
alert("Data stored is " + evt.target.result);
};
reader.readAsText(file);
}
To find out more take a look at this official Phonegape FileReader documentation.
Then again you can always abandon this solution and use a persistance js for data storage. It will provide you 4+1 different options for file/data storage and it works on numerous platforms.
As a side note, localstorage persistence was bugged in cordova(phonegap) version 2.6, so if this is your case, try migrating to cordova 2.7 recently released or downgrade to 2.5 to get rid of said bug.
I've been working on this bit of PhoneGap (cordova-2.0.0.js) code for an Android* device to persist some data. I'm getting this weird error code and the file doesn't seem to be getting written. I started with the example code and could write an inline string to a file handle successfully, so I'm sure my permissions and all are correct.
Perhaps I'm not handling all the callbacks correctly? There are a lot to listen for! It could be something with truncate(0); I had a hard time finding much documentation on it. Do I need to call window.requestFileSystem more than once? I do it 2x to register different callbacks. If not this, what is causing the error?
Suggestions on reducing the total number of lines for a Read + Write operation will be gladly accepted as well...
*Emulator running Android 2.3.4
here's my code:
var CREDENTIALS_FILE_NAME = "credentials.json";
var credentials;
// INIT -- Wait for PhoneGap to load
document.addEventListener("deviceready", onDeviceReady, false);
function onDeviceReady() {
window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, initCredentialReader, fail);
}
function initCredentialReader(fileSystem) {
fileSystem.root.getFile(CREDENTIALS_FILE_NAME, {create: true}, gotFileEntryReader, fail);
}
function gotFileEntryReader(fileEntry) {
fileEntry.file(gotFileToRead, fail);
}
function gotFileToRead(file){
var reader = new FileReader();
reader.onloadend = function(e) {
console.log("--FILE READER: "+e.target.result);
if( e.target.result.length < 1 ) {
credentials = newCredentials();
} else {
credentials = JSON.parse( e.target.result );
}
};
reader.readAsText(file);
}
// END CHAIN
function initCredentialWriter(fileSystem) {
fileSystem.root.getFile(CREDENTIALS_FILE_NAME, {create: true}, gotFileEntryWriter, fail);
}
function gotFileEntryWriter(fileEntry) {
fileEntry.createWriter(gotFileWriter, fail);
}
function gotFileWriter(writer) {
writer.onwrite = function(e) {
console.log("--- write success");
};
var toWrite = JSON.stringify(credentials);
console.log("--- toWrite: "+toWrite);
writer.truncate(0);
writer.seek(0);
writer.write(toWrite);
}
function fail(error) {
console.log("--- write FAIL: "+error.code);
}
function newCredentials() {
console.log("returning newCredentials!");
return {
"username" : "",
"password" : "",
"organization" : "",
"cookieValue" : "" };
}
function getCredentials() {
console.log("--- getCredentials: "+credentials);
return credentials;
}
function saveCredentials( jsonCredentials ) {
console.log('--- saveCredentials jsonCredentials: '+ jsonCredentials);
credentials = JSON.stringify( jsonCredentials );
console.log('--- credentials to save: '+credentials)
window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, initCredentialWriter, fail);
return credentials;
}
ERROR
08-14 18:41:38.839: I/Web Console(2678): Error in success callback:
File9 =
{"code":7,"line":2863,"expressionBeginOffset":91407,"expressionEndOffset":91455,"sourceId":4122528,"sourceURL":"file:///android_asset/www/cordova-2.0.0.js"}
at file:///android_asset/www/cordova-2.0.0.js:258
So, turns out that calling truncate() and write() is not asynchronously correct-- just had implement more callbacks, like so:
function initCredentialTruncate(fileSystem) {
fileSystem.root.getFile(CREDENTIALS_FILE_NAME, {create: true}, gotFileEntryTruncate, fail);
}
function gotFileEntryTruncate(fileEntry) {
fileEntry.createWriter(gotFileTruncate, fail);
}
function gotFileTruncate(writer) {
writer.onwrite = function(e) {
console.log("--- truncate success");
};
writer.truncate(0);
//writer.seek(0);
}
// END CHAIN
and call the init function when necessary. thx for letting me vent, StackOverflow...