I'm trying to read a JSON file inside the www with Cordova.
I'm trying with a lot of systems, tests and solutions which, however, are failing one after the other.
The simplest concept (fetch)
Result: locally work. On app: "fetch fail" if use cordova.file.dataDirectory. The result is: "NetworkError when attempting to fetch resource".
document.addEventListener('click', test ,true);
document.addEventListener('touchstart', test ,true);
function test(){
alert("try fetch");
const jsonFile = "./geoita.json"; // fail on app
const jsonFile = cordova.file.dataDirectory+"geoita.json"; //security
var headers = new Headers({
"Content-Type": "text/plain",
"Accept": "text/plain"
});
window.fetch( jsonFile, headers )
.then( resp => resp.json() )
.then( json => {
console.log(json);
alert("Result: "+json);
document.body.innerHTML=JSON.stringify(json);
})
.catch(function(error) {
console.log('ERROR: ' + error.message);
alert('ERROR: ' + error.message);
});
};
TEST 2 (request)
Result: security on file. You can't get file, so you can't read it.
var req = new XMLHttpRequest();
req.onreadystatechange = () =>
{
console.log("try in api style...");
if (req.readyState==4 && req.status==200)
{
console.log("reading...");
let json = JSON.parse(req.responseText);
console.log(json);
}
else {
console.log("try in api style - error: "+req.readyState);
}
}
req.open("GET",(cordova.file.dataDirectory+"geoita.json"),true);
req.send();
TEST 3 (follow official guideline)
Result: file not found or encoding error.
const filePath = cordova.file.applicationDirectory+"geoita.json"; //return error code 5 ENCODING_ERR
//const filePath = "www/geoita.json"; // return error 1 NOT_FOUND_ERR
//const filePath ="geoita.json";
//const filePath = cordova.file.applicationDirectory+"geoita.txt"; // not changed
window.resolveLocalFileSystemURL( filePath ,
fileEntry => {
console.log("file object ready");
fileEntry.file(
File => {
console.log("content: ",File);
var reader = new FileReader();
reader.onloadend = function(evt)
{
console.log("read success",evt.target.result);
};
reader.readAsText(File);
});
}, error => console.error(error) );
I'm continuing to do many tests but I don't understand what is going wrong. I don't understand why it is so difficult to read a local file in the www folder of Cordova.
How can I do this?
Update
Over 32 tests after, the solution was wrong.
Unfortunately I just realized that he doesn't write the file from the www folder. What you can do is "create a file from the variable, historicize it in the permanent and then reread it. It still doesn't read as I wanted then.
What happened during the test is simply the result of previous tests where I had "copied the file into the variable by hand", therefore I had unknowingly saved it and was subsequently recovered as if it were reading the local one (which, of course, was identical)
Unfortunately I still can't find a solution to read the file. If you are aware of it, write!
For this example we have 2 type of data.
1) is a simple var within a json message;
2) It's a local file in the directory www (then create a file by hand that you can recover ... a text with false json data similar to the one in 1)
Step 00
add cordova-file-plugin in your project
https://cordova.apache.org/docs/en/latest/reference/cordova-plugin-file/index.html
Step 01
In config.xml
<platform name="android">
<preference name="AndroidPersistentFileLocation" value="Compatibility" />
<preference name="AndroidExtraFilesystems" value="assets,root, files, cache, sdcard, cache-external, files-external" />
</platform>
<platform name="ios">
<preference name="iosPersistentFileLocation" value="Compatibility" />
<preference name="iosExtraFilesystems" value="assets,root, files,cache, sdcard, cache-external, files-external" />
</platform>
Potentially you may also need to enter:
<access origin="*" /> <access origin="cdvfile://*"/> <access origin="file:///*"/>
Step 02
Now, after app is ready, example:
if('cordova' in window)
{
document.addEventListener('deviceready', mytest);
// console.log('device');
}
else
{
document.addEventListener('DOMContentLoaded', mytest);
// console.log('web device');
}
in alternative joint it on event:
document.addEventListener('click', mytest,true);
document.addEventListener('touchstart', mytest,true);
Step 03
Into your function of app
function mytest(){
// start for read (get the file and pass it on readFile method)
window.requestFileSystem(LocalFileSystem.PERSISTENT, 0,
(fs)=> {
var fileName = "test.txt",
fileDir = cordova.file.applicationDirectory.replace( cordova.file.applicationDirectory, ''), //cordova.file.applicationDirectory only get error on entry file
filePath = fileDir + fileName;
fs.root.getFile(
filePath,
null,
(fileEntry) => {
readFile(fileEntry)
}, fileEntryFail);
}, filesystemFail);
// start for write (set a file creator -> get data via var -> pass var on writeFile method)
window.requestFileSystem(LocalFileSystem.PERSISTENT, 0,
(fs)=> {
var fileName = "test.txt",
fileDir = cordova.file.applicationDirectory.replace( cordova.file.applicationDirectory, ''), //cordova.file.applicationDirectory only get error on entry file
filePath = fileDir + fileName;
fs.root.getFile(
filePath,
{ create: true, exclusive: false },
(fileEntry) => {
writeFile(fileEntry, filetowrite );
}, fileEntryFail);
}, filesystemFail);
// write a file whit data
function writeFile(fileEntry, dataObj) {
fileEntry.createWriter(function (fileWriter) {
fileWriter.onwrite = function() {
alert("file write");
// readFile(fileEntry); // if you wont read after write it
};
fileWriter.onerror = function (e) {
alert("Failed file write: " + e.toString());
};
fileWriter.write(dataObj);
});
}
// read a file getted
function readFile(fileEntry) {
alert('Reading file....');
fileEntry.file(function (fileEntry)
{
console.log("path to file: ",fileEntry.fullPath);
console.log("file to read: ",fileEntry.file);
var reader = new FileReader();
reader.onloadend = function()
{
alert("Successful file read");
// document.body.innerHTML = ""+this.result;
console.log("Successful file read: ",this.result);
// window.dataActive = JSON.parse(this.result);
// alert('dataActive was read as: ' + dataActive)
// displayFileData(fileEntry.fullPath + ": " + this.result);
};
reader.readAsText(fileEntry);
}, readFail );
};
// fails
function filesystemFail (err) { alert("FS: DATA FAIL"); console.log(err.code);};
function fileEntryFail (err) { alert("File entry: FAIL"); };
function writeFail (err) { alert("Writing: DATA FAIL"); };
function readFail (err) { alert("Reading: DATA FAIL"); };
//data test via var
var filetowrite = `{"message": "THIS IS SIMPLE TEST MESSAGE"}`
};
Now some important closing notes
It is obviously useless to keep both start read and start write which test on the same file or data. Either write the file and then read it or take it locally and read it directly. So for your tests comment one of the two at a time.
It's also stupid to keep them separate because it would be easy to optimize the system by calling the file system only once.
However, I left them separate to give a clear and functional example to those who, like me, are stuck on logic.
Update
Solution:
While waiting for the whole plugin I am testing to be built:
A) you have to "unlock" access to files in config.xml as I explained above.
B) cordova-file-plugin can only write, read, delete files in the permanent memory inside the app. (I will release a better model than the one above as soon as I can)
C) fetch does not work in any case. BE CAREFUL, it only works on the browser but not in the app
D-1) I am testing the writing and deleting of files in the www. I still need time.
D-2) it is possible to read through an XML request the file in the www in the following way:
var _filename = 'MYFILENAMEINWWW.txt',
_mimetype = 'text/plain'; // or application/json
function readfromwww(_mimetype,_filename,callback)
{
var request = new XMLHttpRequest();
request.overrideMimeType(_mimetype );
request.open("GET", _filename );
request.onreadystatechange = () =>
{
if(request.status > 300)
{
if(rs==404) console.log('file not found in www: ',request.status);
else console.log('error on request: ',request.status);
}
else if(request.responseText!=undefined && request.responseText!='')
{
//from json string to js obj content
if(_mimetype == "application/json")
callback(JSON.parse(request.responseText));
//return string into your file
else
callback(request.responseText);
}
}
request.send();
}
}
// now you can read a file in www calling the method:
readfromwww('text/plain', 'test.txt',
filecontent => {
console.log('OLE! INTO THE FILE: ',filecontent);
//not filecontent is the content of your file but... remember... the contents is loaded via ajax, isn't easy to storize it out this function.
});