I've been trying to run the following code but the callbacks [ok() and ko()] are not called.
Using Worklight 6.2 (Cordova 3.4).
function wlCommonInit() {
window.requestFileSystem(LocalFileSystem.PERSISTENT, 0,
success, fail);
window.resolveLocalFileSystemURL(cordova.file.applicationDirectory
+ "www/index.html", ok, ko);
}
function ko(e) {
alert("NO");
}
function ok(fileEntry) {
alert("OK");
}
On the other hand requestFileSystem callbacks are called regularly.
The code snippet in the question will not work in Android due to a Cordova defect: https://issues.apache.org/jira/browse/CB-7273.
To progress further, it would help to understand what are your plans for the file itself.
Do you simply want the path to the file
Or do you want to alter the contents of the file?
Or?
You can read more about file system operations in Cordova in this question/answer: Where does LocalFileSystem.PERSISTENT point to?
I managed to access local fiiles in Worklight running an Android environment using a XMLHttpRequest:
//Works only on Android
function prendiCaricaRisorsaWorklight(percorsoPiuNomeFile) {
var xmlhttp = new XMLHttpRequest();
var risposta = "";
xmlhttp.onreadystatechange = function() {
if (xmlhttp.readyState == 4
&& (xmlhttp.status == 200 || xmlhttp.status == 0)) {
risposta = xmlhttp.responseText;
alert(risposta);
}
}
xmlhttp.open("GET", "file:///android_asset/www/default/"
+ percorsoPiuNomeFile, true);
xmlhttp.send(null);
}
Usage example:
prendiCaricaRisorsaWorklight("css/cssInterno.css");
prendiCaricaRisorsaWorklight("js/jsInterno.js");
This shows on Android an alert with the file content.
Related
I am working on Cordova app. I wannt to implement a qrcode reader. I tried plugins available in Cordova but they all are buggy and some doesnot provide preview of scanner/video on same screen.
So I decided to use instascan which is a js based library to be used with webcams. I used it and implemented it in a simple cordova app and its working.
Now I see preview of my scan (camera video which is currently being scanned) and it scans perfectly.
But later I merged that code with my actual Cordova app which uses Vue cli. Now I am getting:
Error: Cannot access video stream (NotReadableError)
This error is probably (as I read) due to Chrome's https policy. But the problem is, Cordova uses webview and another cordova app which is basic cordova instance with this plugin only is working perfectly.
My implementation:
mounted: function () {
var _this = this;
this.$ons.ready(function () { // this is ready event fired by Onsen UI when cordova's native APIs are loaded
var scanner = new Instascan.Scanner({
continuous: true,
mirror: false,
video: document.getElementById('scannerPreview'),
});
scanner.addListener('scan', function (content) {
alert('scan' + content);
});
Instascan.Camera.getCameras().then(function (cameras) {
if (cameras.length > 0) {
if (cameras.length === 1) {
scanner.start(cameras[0]);
} else {
scanner.start(cameras[1]);
}
scanner.start(cameras[0]);
} else {
alert('No cameras found.');
}
}).catch(function (e) {
alert(e);
});
});
},
first add the permissions plugin:
cordova plugin add cordova-plugin-permission
And then you must request the permits in the camera:
permissions.requestPermission(permissions.CAMERA, success, error);
function error() {
return false;
}
function success( status ) {
if( !status.hasPermission ) error();
return true;
}
In my app, I need to download few files form server. I used the following code:
function downloadFile(index:int):void
{
var urlLoader:URLLoader = new URLLoader();
urlLoader.dataFormat = URLLoaderDataFormat.BINARY;
urlLoader.addEventListener(Event.COMPLETE, onLoadFileComplete);
urlLoader.addEventListener(ProgressEvent.PROGRESS, onLoadFileProgress);
urlLoader.addEventListener(IOErrorEvent.IO_ERROR, onURLIOError);
urlLoader.load(new URLRequest("some url"));
fileNameToSave = "some name";
trace("file name:" + fileNameToSave);
downloading = true;
}
function onLoadFileProgress(e:ProgressEvent):void
{
var loadedPct:uint = Math.round(100 * (e.bytesLoaded / e.bytesTotal));
}
function onURLIOError(e:IOErrorEvent):void
{
trace("error msg");
e.target.removeEventListener(IOErrorEvent.IO_ERROR, onURLIOError);
}
function onLoadFileComplete(e:Event):void
{
trace("File downloaded");
var file:File;
file = File.documentsDirectory.resolvePath("somelocation/" + fileNameToSave);
if(file != null)
{
var fileStream:FileStream = new FileStream();
fileStream.openAsync(file, FileMode.WRITE);
fileStream.addEventListener(OutputProgressEvent.OUTPUT_PROGRESS, outputProgressHandler);
fileStream.addEventListener(Event.CLOSE, onSaveFile);
fileStream.writeBytes(e.target.data);
fileStream.close();
}
e.currentTarget.removeEventListener(Event.COMPLETE, onLoadFileComplete);
e.currentTarget.removeEventListener(ProgressEvent.PROGRESS, onLoadFileProgress);
e.currentTarget.removeEventListener(IOErrorEvent.IO_ERROR, onURLIOError);
}
function outputProgressHandler(e:OutputProgressEvent):void
{
if (e.bytesPending == 0)
{
trace("File is completely written");
}
}
function onSaveFile(e:Event):void
{
trace("Saved Complete");
loadfiles();
e.currentTarget.removeEventListener(Event.CLOSE, onSaveFile);
}
It works fine. But the problem I'm having is when the internet is slow, sometime it triggers complete event even if the file is not fully downloaded. Is there anyway to prevent this? Any help would be appreciated.
UPDATE: Is it a good practice to use progress event to check if the download is complete rather than using complete event. Like:
if(e.bytesLoaded >= e.bytesTotal)
{
//downloadComplete
}
else
{
//not complete
}
I can not comment because I have insufficient reputation.
I have previously had similar issue where filestream write reports as complete when in fact it has not. This occurs only on older devices and occurs randomly. My testing seemed to confirm that Flash reports file saved before the OS had actually completed. When a read then occurred it would report as file not found.
I solved it rather crudely using setTimeout and repeatedly checked if the data was complete.
I have serious issues loading binary image data into a simple image-element. I coded a cordova app (using Sencha touch) which loads images the following way:
xhr.open('GET', imageUrl, true);
xhr.responseType = 'blob';
xhr.addEventListener('load', function () {
if (xhr.status === 200) {
// onload needed since Google Chrome doesn't support addEventListener for FileReader
fileReader.onload = function (evt) {
image.setSrc(evt.target.result);
};
// Load blob as Data URL
fileReader.readAsDataURL(xhr.response);
}
}, false);
On Android 5 and 4.4 (these are the ones I tested) it works like a charm. Now I ran it Android 4.1 on an ASUS Tablet and the onload callback doesn't get fired. When I throw a blob in the readAsDataURL-function, at least the onload callback is fired, but the image doesn't show any image as well :(
Has anyone a suggestion, what the failure could be or what I'm doing wrong?
Ah, finally I got it to work on Android 4.1.1 (ASUS Tablet) with the following code. Another issue was, that saving an arraybuffer response from the xhr could not simply serialized, so I converted the stuff to string. Also I receive the blob taking into account, that on some systems the Blob object simply isn't there:
function arrayBufferToString(buf) {
return String.fromCharCode.apply(null, new Uint8Array(buf));
};
function stringToArrayBuffer(str) {
var buf = new ArrayBuffer(str.length*2); // 2 bytes for each char
var bufView = new Uint8Array(buf);
for (var i=0, strLen=str.length; i<strLen; i++) {
bufView[i] = str.charCodeAt(i);
}
return buf;
};
function getBlob(content, type) {
var blob = null;
// Android 4 only has the deprecated BlobBuilder :-(
try {
blob = new Blob([content], {type: type});
} catch(e) {
window.BlobBuilder = window.BlobBuilder || window.WebKitBlobBuilder ||
window.MozBlobBuilder || window.MSBlobBuilder;
if (window.BlobBuilder)
{
var bb = new BlobBuilder();
bb.append(content);
blob = bb.getBlob(type);
}
}
return blob;
};
cachedFile = getCachedFile(...); // not of interest here, I think :-)
if (cachedFile)
{
callback.apply(this, [window.webkitURL.createObjectURL(getBlob(stringToArrayBuffer(cachedFile.data), 'image/jpeg'))]);
}
else {
xhr.open('GET', imageUrl, true);
xhr.responseType = 'arraybuffer';
xhr.addEventListener('load', function () {
if (xhr.status === 200) {
cachedFile = {
url: imageUrl,
data: arrayBufferToString(xhr.response)
};
addCachedFile(cachedFile); // not of interest here, I think :-)
callback.apply(this, [window.webkitURL.createObjectURL(getBlob(xhr.response, 'image/jpeg'))]);
}
}, false);
// Send XHR
xhr.send();
}
Edit: Just did a little change and now used the Uint8Array Class instead of the Uint16Array Class because I got errors: "RangeError: byte length of Uint16Array should be a multiple of 2". Now it works well.
Edit2: Just saw, that the above code doesn't work out in all situations because of the usage of Uint8Array resp. Uint16Array.
Now I think I have a solid solution: I convert the binary responded by the image url into a base64 using canvas with the function from here http://appcropolis.com/blog/web-technology/javascript-encode-images-dataurl/ . Takes a little time, but still a working solution :)
i am using cordova-ionic framework to build app. i am new to the iOS or iPhone
in my requirement, i have to read a file in the app. i am reading file in the android app but same code showing error (code: 5).
i am following code types:
in android:
$cordovaFile.writeFile(( 'user.json', data, {'append':false} )).then(function(result) {
alert('file created.');
alert(JSON.stringify(result));
}, function(err) {
// An error occured. Show a message to the user
alert('file writed');
alert(JSON.stringify(err));
});
i can create file, writing, reading data and removing the file but in ios phone i am not able to create file using the same code.
in iPhone:
var data = {"user":{"name":"errer","email":"sdsdff#gmail.com","username":"sdfsdfsd"}};
$cordovaFile.writeFile(( 'user.json', data, {'append':false} )).then(function(result) {
// Success!
alert('file created.');
alert(JSON.stringify(result));
}, function(err) {
// An error occured. Show a message to the user
alert('file writed');
alert(JSON.stringify(err));
});
i just change my directory is cordova.file.cacheDirecotry/cordova.file.applicationDirectory
$cordovaFile.createFile(( cordova.file.cacheDirecotry+'user.json', true )).then(function(result) {
// Success!
alert('file created.');
alert(JSON.stringify(result));
}, function(err) {
// An error occured. Show a message to the user
alert('file writed');
alert(JSON.stringify(err));
});
all way getting the error like code: 12 or code: 5
please help me to solve this or give me a idea to get application file path
I have some progression.
First, I alert my cordova.file.dataDirectory or cordova.file.documentsDirectory.
They are
file:///var/mobile/...../Library/NoCloud
and
file:///var/mobile/..../Documents
Then I create a File without the prefix and succeed. Referring to this https://github.com/driftyco/ng-cordova/issues/362
and the success message shows that the native url of the file is saved in
file:///var/mobile/...../Library/files
Which is quite strange. By the way, I add the
<preference name="iosPersistentFileLocation" value="Library" />
according to https://github.com/apache/cordova-plugin-file/blob/master/doc/index.md#ios-persistent-storage-location
All the tests are running on IOS, i haven't test for Android.
Updates
All the following code worked for me and give success response
$cordovaFile.checkFile('/test.data')
$cordovaFile.createFile('test.data',false)
$cordovaFile.checkDir('/')
Hope this can solve your problems.
/*
Here is what I am using for my Android and IOS apps
Keep attention to a couple of things:
- Android and IOS have other directorynames for files
- Android devices have different root (myFSRootDirectory1 = Samsung Tab 3, msFSRootDirectory2 = Samsung SII)
- $cordovaFile functions prefixes all pathnames with root
$cordovaFileTransfer functions needs absolute pathnames
Here I create the prefixes for File functions and FileTransfer functions for Android and IOS
*/
// The $ionicPlatform and ionic.Platorm are from Ionic framework
//
$ionicPlatform.ready(function() {
if (ionic.Platform.isAndroid()) {
// If running on Android
console.log('cordova.file.externalDataDirectory: ' + cordova.file.externalDataDirectory);
//
// I use cordova.file.externalDataDirectory because this url is for Android devices
// If you remove the app from the device these url are cleared too on the device. So keep it clean.
// Remove the root from cordova.file.externalDataDirectory
//
myFsRootDirectory1 = 'file:///storage/emulated/0/'; // path for tablet
myFsRootDirectory2 = 'file:///storage/sdcard0/'; // path for phone
fileTransferDir = cordova.file.externalDataDirectory;
if (fileTransferDir.indexOf(myFsRootDirectory1) === 0) {
fileDir = fileTransferDir.replace(myFsRootDirectory1, '');
}
if (fileTransferDir.indexOf(myFsRootDirectory2) === 0) {
fileDir = fileTransferDir.replace(myFsRootDirectory2, '');
}
console.log('Android FILETRANSFERDIR: ' + fileTransferDir);
console.log('Android FILEDIR: ' + fileDir);
}
if (ionic.Platform.isIOS()) {
// if running on IOS
console.log('cordova.file.documentsDirectory: ' + cordova.file.documentsDirectory);
// I use cordova.file.documentsDirectory because this url is for IOS (NOT backed on iCloud) devices
fileTransferDir = cordova.file.documentsDirectory;
fileDir = '';
console.log('IOS FILETRANSFERDIR: ' + fileTransferDir);
console.log('IOS FILEDIR: ' + fileDir);
}
if (ionic.Platform.isAndroid() || ionic.Platform.isIOS()) {
//
// Just functions from the list below one by one ( or chain them)
//
}
});
// Download file from 'http://www.yourdomain.com/test.jpg' to test/one/test.jpg on device Filesystem
var hostPath = 'http://www.yourdomain.com/test.jpg';
var clientPath = fileTransferDir + 'test/one/test.jpg';
var fileTransferOptions = {};
$cordovaFile.downloadFile(hostPath, clientPath, true, fileTransferOptions).then (function() {
});
// Create dir test
$cordovaFile.createDir(fileDir + 'test/').then( function(dirEntry) {
});
// Create dir aganin in dir test
$cordovaFile.createDir(fileDir + 'test/one/').then( function(dirEntry) {
});
// Create empty file test.txt in test/again/
$cordovaFile.createFile(fileDir + 'test/one/test.txt', true).then( function(fileEntry) {
});
// List of files in test/again
$cordovaFile.listDir(fileDir + 'test/one/').then( function(entries) {
console.log('list dir: ', entries);
});
// Write some text into file
$cordovaFile.writeFile(fileDir + 'test/one/test.txt', 'Some text te test filewrite', '').then( function(result) {
});
// Read text written in file
$cordovaFile.readAsText(fileDir + 'test/one/test.txt').then( function(result) {
console.log('readAsText: ', result);
});
Perhaps it's because of a typo? You have cordova.file.cacheDirecotry. Shouldn't that be : cordova.file.cacheDirectory ?
Refer to the original documentation :-
https://github.com/apache/cordova-plugin-file/blob/master/doc/index.md#ios-file-system-layout
iOS has some directories as read-only. Try changing your path.
Let me know if it does not work for you.
i am trying to do login application which takes id and password..when i click on logi button then it will connect to our local server by JSON..with the specified URL..the code is..
var loginReq = Titanium.Network.createHTTPClient();
loginReq.onload = function()
{
var json = this.responseText; alert(json);
var response = JSON.parse(json);
if (response.data.status == "success")
{ alert("Welcome ");
}
else
{ alert(response.data.status);
}
};
loginReq.onerror = function(event)
{
alert(event.toSource());
//alert("Network error");
};
loginBtn.addEventListener('click',function(e)
{ if (username.value != '' && password.value != '')
{
var url = 'our local url action=login&id='+username.value+'&pwd='+password.value;
loginReq.open("POST",url);
loginReq.send();
}
else
{
alert("Username/Password are required");
}
});
Here it is not connecting our URl..so it is entering into loginReq.onerror function...instead of loginReq.onload function..why it is throwing run time error.. The same code working fine with Iphone..
The Run Time Error is..
TypeError:Cannot call property toSource in object{'source':[Ti.Network.HttpClient],specified url} is not a function,it is a object.
This is wat the error..please let me Know...
Apparently the toSource() function does not exist in android, as it is an object. Try debugging and see what the object event contains.
You could do that by adding a line above the alert line, and adding a debug line to it.
Look in debug mode and see all variables
"toSource()" is not a documented function for either platform, and I also do not see it in the source for Titanium Mobile. If you aren't getting the error on iOS, I'm guessing it is because the error handler isn't getting called. Perhaps your emulator or device does not have internet access, whereas your iOS simulator or device does?
Regardless, error handling in the HTTPClient normally looks something like this:
loginReq.onerror = function(e)
{
Ti.API.info("ERROR " + e.error);
alert(e.error);
};