I have the following code:
function wait(){
$(document).ready(function() {
//alert("Dentro de ready");
document.addEventListener("deviceready", init(), true);
});
}
Where "wait" is a Javascript function called from the onload event. I use the onload event, as well as $(document).ready and "deviceready" event to make sure every single thing is loaded when i start coding.
The "init()" method does a few things and then calls the following method:
function download_img(imgToDownload){
var url = remote_url+imgToDownload; // image url
alert("img url: "+url);
try{
window.requestFileSystem(**LocalFileSystem**.PERSISTENT, 0,
function (fs) {
var imagePath = fs.root.fullPath +"/"+ imgToDownload; // full file path
var fileTransfer = new FileTransfer();
fileTransfer.download(url, imagePath,
function (entry) {
alert("OK: " + entry.fullPath); // entry is fileEntry object
},
function (error) {
alert("download error source " + error.source);
alert("download error target " + error.target);
alert("upload error code" + error.code);
alert("http_status"+error.http_status);
}
);
}
);
}catch(err){
alert(err.message);
}
}
Where I get the error message: "LocalFileSystem is not defined".
My config.xml is:
<?xml version="1.0" encoding="UTF-8" ?>
<widget xmlns = "http://www.w3.org/ns/widgets"
xmlns:gap = "http://phonegap.com/ns/1.0"
id = "com.lamakun.mancomunidad"
version = "3.0.0">
<name>PhoneGap Build Application</name>
<description>
A simple PhoneGap Build application.
</description>
<author href="https://example.com" email="you#example.com">
Your Name
</author>
<preference name="phonegap-version" value="2.2.0" />
<access origin="http://www.mytests.es" subdomains="true"/>
</widget>
In case I might add any permission, even though I think right now I have them all.
Can anyone give me a clue on that?
It isn't:
document.addEventListener("deviceready", init(), true);
it should be:
document.addEventListener("deviceready", init, true);
having the () after init calls that function immediately before the deviceready event is fired.
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
write these lines in android manifiest file
Related
to try to solve another problem with the Tone.js library and the audio buffer (see here), I created a "default cordova hello world app", and added the "cordova-plugin-file" plugin.
I can't understand why, I can process a remote file and play it,
but the same file locally, I can't play it, what am I wrong ?.
I removed all the "Content-Security-Policy" from my index.html ... I changed the permissions in the Config.xml file as follows:
<preference name = "AndroidPersistentFileLocation" value = "Internal" />
<access origin = "cdvfile: //*" />
<access origin = "*" />
<allow-intent href = "cdvfile: //*/*" />
<allow-intent href = "http: //*/*" />
<allow-intent href = "https: //*/*" />
<allow-intent href = "tel: *" />
<allow-intent href = "sms: *" />
<allow-intent href = "mailto: *" />
<allow-intent href = "geo: *" />
Then in the deviceready, if I switch to Tone.js Player, the external url works, with the local url no, where am I wrong?
//Local NO ok!: "cdvfile://localhost/persistent/1_Hat.mp3"
//Remote OK!: "https://vivo-vivendo-musica.com/sample/1_Hat.mp3"
function onDeviceReady() {
// Cordova is now initialized. Have fun!
console.log('Running cordova-' + cordova.platformId + '#' + cordova.version);
document.getElementById('deviceready').classList.add('ready');
//Local NO ok!: "cdvfile://localhost/persistent/1_Hat.mp3"
//Remote OK!: "https://vivo-vivendo-musica.com/sample/1_Hat.mp3"
window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, function (fs) {
console.log('file system open: ' + fs.name);
fs.root.getFile("1_Hat.mp3", { exclusive: false }, function (fileEntry) {
console.log("fileEntry is file? " + fileEntry.isFile.toString());
fileEntry.file(function (file) {
console.log(file.localURL);
player = new Tone.Player(file.localURL).toDestination();
// play as soon as the buffer is loaded
player.autostart = true;
});
}, console.log("getFile") );
}, console.log("onErrorLoadFs") );
}
I think it's almost certainly a security issue, but I don't understand what's missing, I've tried all sorts of ways to get to this file, which is present in the www folder.
Finally I managed to solve in this way, I don't know if it is the best way, or if it is the only way, but in this way I can get to the resources, present in the www / directory. It hasn't been easy for me, and I think this can help someone else.
//attach a click listener to a play button
document.querySelector('#Play').addEventListener('click', async () => {
await Tone.start()
console.log('audio is ready');
play();
})
function play() {
var xhr = new XMLHttpRequest();
xhr.open("GET", "1_Hat.mp3", true);
xhr.responseType = 'blob';
xhr.onload = function(){
var blob = URL.createObjectURL(this.response);
console.log('pressed');
var player = new Tone.Player().toDestination();
player.load(blob);
player.autostart = true;
};
xhr.send();
}
Thanks for this! great help: #628 (comment)
I am having problem trying to upload an image file to my local web server (hosted using wampserver) for android hybrid app built using IBM Worklight 6.2.0 with Cordova version 3.4.0. The code snippet is as below:
<script type="text/javascript" charset="utf-8">
// Wait for Cordova to load
document.addEventListener("deviceready", onDeviceReady, false);
// Cordova is ready
function onDeviceReady() {
// Nothing here
}
function getImage() {
// Retrieve image file location from specified source
navigator.camera.getPicture(uploadPhoto, function(message) {
alert('get picture failed');
}, {
quality: 40,
destinationType: Camera.DestinationType.FILE_URI,
sourceType: Camera.PictureSourceType.PHOTOLIBRARY
});
}
function uploadPhoto(imageURI) {
var options = new FileUploadOptions();
options.fileKey = "file";
options.fileName = imageURI.substr(imageURI.lastIndexOf('/') + 1);
options.mimeType = "image/jpeg";
var params = new Object();
params.value1 = "test";
params.value2 = "param";
options.params = params;
options.chunkedMode = false;
var ft = new FileTransfer();
ft.upload(imageURI, encodeURI("http://192.168.1.4:8081/folder_name/upload2.php"), win, fail, options);
}
function win(r) {
console.log("Code = " + r.responseCode);
console.log("Response = " + r.response);
console.log("Sent = " + r.bytesSent);
alert(r.response);
}
function fail(error) {
alert("An error has occurred: Code = " + error.code);
}
</script>
<button onclick="getImage();">Upload a Photo</button>
upload2.php
<?php print_r($_FILES); $new_image_name="namethisimage.jpg" ; move_uploaded_file($_FILES[ "file"][ "tmp_name"], "folder_name/uploads/".$new_image_name); ?>
I'm getting http status 200 and an error code 3. Besides that, I also getting this error below the http status and error code error.
java.lang.SecurityException: Permission Denial: reading com.android.providers.media.MediaDocumentsProvider uri content://com.android.providers.media.documents/document/image:14584 from pid=4926, uid=10092 requires android.permission.MANAGE_DOCUMENTS, or grantUriPermission()
Is there any solution to this? Or is there a better way for me to upload the image file?
I've added the following to AndroidManifest.xml
<uses-permission android:name="android.permission.MANAGE_DOCUMENTS"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
I am not sure what's the issue here. My code just works suddenly, even with AngularJS. I will just share my working code here, if others might want to refer.
main.js
$scope.getImage = function() {
// Retrieve image file location from specified source
navigator.camera.getPicture(onSuccess, function(message) {
alert('get picture failed');
},{
quality: 50,
destinationType: Camera.DestinationType.FILE_URI,
sourceType: Camera.PictureSourceType.PHOTOLIBRARY
}
);
}
function onSuccess(imageURI) {
$scope.image = imageURI;
};
function uploadPhoto(image) {
var options = new FileUploadOptions();
options.fileKey="file";
options.fileName= $scope.imageName;
options.mimeType="image/jpeg";
var params = new Object();
params.value1 = "test";
params.value2 = "param";
options.params = params;
options.chunkedMode = false;
var ft = new FileTransfer();
ft.upload(image, encodeURI(ipaddress_to_your_server/root_folder/upload.php), win, fail, options);
}
function win(r) {
console.log("Code = " + r.responseCode);
console.log("Response = " + r.response);
console.log("Sent = " + r.bytesSent);
alert(r.response);
}
function fail(error) {
alert("An error has occurred: Code = " + error.code);
}
upload.php
<?php
print_r($_FILES);
$image_name = $_FILES['file']['name'];
move_uploaded_file($_FILES["file"]["tmp_name"], "uploads/".$image_name);
?>
You will just need to call the $scope.getImage function in html to open the device's photo library.
Based on the last image, it seems that you solved this somehow - you should share it as an answer.
Regardless,
Why is there PHP code in your code snippet? Is this code snippet originating from your Worklight-based app? You cannot have there PHP... This is a mobile app, running in your device, not on your server. There is nothing there that will interpret that code.
The following should not be used in your app, because Cordova is part of the Worklight framework and this check is done internally. Instead, your code should sit inside the wlCommonInit() function in main.js, or be called from there.
// Wait for Cordova to load
document.addEventListener("deviceready", onDeviceReady, false);
// Cordova is ready
function onDeviceReady() {
// Nothing here
}
I suspect that is why nothing works for you. Try to use AJAX to make the request to the server, to receive the sent image and store it in your web server.
I'm trying to code a dynamic phonegap app that retrieves and format information from a live database.
I use jsonp to get data from a php service I coded.
$(document).ready(function(){
var output = $('#output');
$.ajax({
url: 'http://example.com/service.php',
dataType: 'jsonp',
jsonp: 'jsoncallback',
timeout: 5000,
success: function(data, status){
//data loaded
$.each(data, function(c,comp){
window.alert(comp.filter); // I added this just to check I was getting data correctly.
var company = '<div class="project-post ' +comp.filter+ ' ">'
+'<img src=" ' +comp.img+ ' ">'
+'<div class="hover-box">'
+'<div class="project-title">'
+'<div><i class="fa fa-arrow-right"></i></div>'
+'</div></div></div>';
output.append(company);
});
},
error: function(){
//error loading data
output.text('Error loading data.');
}
});
});
My console doesn't display any errors, I've been trying to solve this for a long time. I have this in my config:
<access origin="*" />
Also I confirmed I was receiving data with window.alert(comp.filter); It's just not displaying at all, maybe something's wrong with my formatting but can't figure out what it is.
I think the issue because of dom formating, the img tag is not closed correctly it should be like:
var company = '<div class="project-post ' +comp.filter+ ' ">' +'<img src=" ' +comp.img+ ' "/>' +'<div class="hover-box">' +'<div class="project-title">' +'<div><i class="fa fa-arrow-right"></i></div>' +'</div></div></div>';
Also take care of your access policy to allow all urls, update your config.xml file with the following code:
<access origin="*" />
Problem description:
I can access the internal storage with either the file or the file-system-roots (read and write). But such a file can not be access from an other app. For example if I want to send this file through the emailComposerPlugin, the file can not be accessed by the email client. (Same goes for the "open with" function.)
If I change the options {sandboxed: true} to false (to write to the external storage), it does not work and ends up in a FileUtils.UNKNOWN_ERR. I tried the application while the phone disconnected from USB, as some docs mentioned that external storage can not be accessed while mounted on the pc - same result though.
From what I read on the mailing list this should be possible. It seems I miss a crucial point?
Context:
I try to enable an hybrid application created for iPhone to run on android devices. To have a little playground, I create a small test project.
Edit:
There seems to be a problem between file-system-roots and file plugin. But I have the newest versions of both of them. (File: 1.0.1 File-system-roots: 0.1.0)
Debugging the file-system and file classes show that
private String fullPathForLocalURL(Uri URL) {
if (FILESYSTEM_PROTOCOL.equals(URL.getScheme()) && "localhost".equals(URL.getHost())) {
String path = URL.getPath();
if (URL.getQuery() != null) {
path = path + "?" + URL.getQuery();
}
return path.substring(path.indexOf('/', 1));
// path = "/cache-external" at this point
// results in index out of bounds exception
What have I tried?
config.xml
<preference name="AndroidExtraFilesystems" value="files,files-external,documents,sdcard,cache,cache-external" />
AndroidManifest.xml
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
javascript code
function createTextDocument(filename, text) {
cordova.filesystem.getDirectoryForPurpose('cache', {sandboxed: false}, successCallback, failureCallback);
function successCallback(directoryEntry){
console.log('directory found (cordova): ' + directoryEntry.toURL());
console.log('directory found (native) : ' + directoryEntry.toNativeURL());
directoryEntry.getFile(filename, {create: true, exclusive: false},
function(fileEntry){
var filePath = fileEntry.toNativeURL();
fileEntry.createWriter(
function(fileWriter){
console.log('start writing to: ' + filePath );
fileWriter.write(text);
console.log('file written');
},failureCallback
);
}, failureCallback
);
}
function failureCallback(error){
console.log('error creating file: ' + error.code);
// results in code 1000
}
}
After digging this whole topic quite a bit, i figured out:
There is no need for the file system roots plugin.
There is more configuration needed in config.xml.
You need to use not the standard FileApi way, but the following to access the files.
JavaScript usage:
window.resolveLocalFileSystemURL(path, cbSuccess, cbFail);
#param path: {string} a cordova path with scheme:
'cdvfile://localhost/<file-system-name>/<path-to-file>'
Examples: 'cdvfile://localhost/sdcard/path/to/global/file'
'cdvfile://localhost/cache/onlyVisibleToTheApp.txt'
#param cbSuccess: {function} a callback method that receives a DirectoryEntry object.
#param cbFail: {function} a callback method that receives a FileError object.
config.xml
<preference name="AndroidPersistentFileLocation" value="Compatibility" />
<preference name="AndroidExtraFilesystems" value="sdcard,cache" />
AndroidManifest.xml
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
After hours of struggling, finally I'm able to scan sdcard and gain access to the files by providing a directory like "files://pathtofile/".I've submit an API and a sample project
https://github.com/xjxxjx1017/cordova-phonegap-android-sdcard-full-external-storage-access-library
Example of using the API
new ExternalStorageSdcardAccess( fileHandler ).scanPath( "file:///storage/sdcard1/music" );
function fileHandler( fileEntry ) {
console.log( fileEntry.name + " | " + fileEntry.toURL() );
}
The API source code
var ExternalStorageSdcardAccess = function ( _fileHandler, _errorHandler ) {
var errorHandler = _errorHandler || _defultErrorHandler;
var fileHandler = _fileHandler || _defultFileHandler;
var root = "file:///";
return {
scanRoot:scanRoot,
scanPath:scanPath
};
function scanPath( path ) {
window.resolveLocalFileSystemURL(path, _gotFiles, errorHandler );
}
function scanRoot() {
scanPath( root );
}
function _gotFiles(entry) {
// ? Check whether the entry is a file or a directory
if (entry.isFile) {
// * Handle file
fileHandler( entry );
}
else {
// * Scan directory and add media
var dirReader = entry.createReader();
dirReader.readEntries( function(entryList) {
entryList.forEach( function ( entr ) {
_gotFiles( entr );
} );
}, errorHandler );
}
}
function _defultFileHandler(fileEntry){
console.log( "FileEntry: " + fileEntry.name + " | " + fileEntry.fullPath );
}
function _defultErrorHandler(error){
console.log( 'File System Error: ' + error.code );
}
};
Configurations
config.xml
delete preference: preference name="AndroidExtraFilesystems"
make sure testing environment can access it's own external storage at the time of testing. ( e.p. if you connect it with usb, make sure it is connected as a camera; Call the APIs after recieving the "deviceready" event )
Path example:
file:///
file:///somefile/
file:///somefile
file:///somefile/music/aaaaa.mp3
I am having a problem storing a file locally on an iOS (or android) device using apache cordova's "file" plugin. The problem I believe is setting the path properly.
this is the error message I get from Xcode
Could not create path to save downloaded file: The operation couldn\U2019t be completed. (Cocoa error 512.)
Here is the code where I am attempting to save the file locally:
<script type="text/javascript" charset="utf-8" src="cordova.js"></script>
<script type="text/javascript" charset="utf-8">
document.addEventListener("deviceready", onDeviceReady, false);
var root;
function onDeviceReady(){
// Note: The file system has been prefixed as of Google Chrome 12:
window.requestFileSystem = window.requestFileSystem || window.webkitRequestFileSystem;
window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, onInitFs, errorHandler);
}
function onInitFs(fs) {
var fileURL = "cdvfile://localhost/persistant/file.png";
var fileTransfer = new FileTransfer();
var uri = encodeURI("http://upload.wikimedia.org/wikipedia/commons/6/64/Gnu_meditate_levitate.png");
fileTransfer.download(
uri,
fileURL,
function(entry) {
console.log("download complete: " + entry.fullPath);
},
function(error) {
console.log("download error source " + error.source);
console.log("download error target " + error.target);
console.log("upload error code" + error.code);
},
false,
{
headers: {
"Authorization": "Basic dGVzdHVzZXJuYW1lOnRlc3RwYXNzd29yZA=="
}
}
);
}
function errorHandler(e) {
var msg = '';
switch (e.code) {
case FileError.QUOTA_EXCEEDED_ERR:
msg = 'QUOTA_EXCEEDED_ERR';
break;
case FileError.NOT_FOUND_ERR:
msg = 'NOT_FOUND_ERR';
break;
case FileError.SECURITY_ERR:
msg = 'SECURITY_ERR';
break;
case FileError.INVALID_MODIFICATION_ERR:
msg = 'INVALID_MODIFICATION_ERR';
break;
case FileError.INVALID_STATE_ERR:
msg = 'INVALID_STATE_ERR';
break;
default:
msg = 'Unknown Error';
break;
};
alert('Error: ' + msg);
}
</script>
Your file path contains a typo (or a grammar error):
var fileURL = "cdvfile://localhost/persistant/file.png";
You should write it as persistent.
Correct code:
var fileURL = "cdvfile://localhost/persistent/file.png";
Check out these links :
http://cordova.apache.org/docs/en/3.4.0/cordova_plugins_pluginapis.md.html#Plugin%20APIs
https://github.com/apache/cordova-plugin-file/blob/dev/doc/index.md
http://cordova.apache.org/docs/en/3.0.0/cordova_file_file.md.html#File
First and second links provide you information about the plugin File and how to install it.
The third one show you how to use the File plugin.
Everytime you need to do something with Cordova, check if a plugin is available to do it :)
regards.
So far I have only tested this on Android, but I believe it should work as-is, or with little modification on IOS:
var url = 'example.com/foo'
window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, function(fileSystem){
fileSystem.root.getFile('foo_file', {create: true, exclusive: false},
function(file_entry){
var ft = new FileTransfer()
ft.download(url, file_entry.toURL(), function(fe){
fe.file(function(f){
reader = new FileReader()
reader.onloadend = function(ev){
console.log('READ!', ev.target.result)
}
reader.readAsText(f)
})
})
}
)
})
Note that I also needed the contents of the file, so the bit at the end may be omitted if you don't need the contents at the time of downloading.
Also note that there is a far simpler method using window.saveAs but it's only available in Android 4.4.