I'm developing a cordova/phonegap app. Right now, I'm testing the app on Android.
If I include files (audio, video, ...) by default, I can access to that files indicating the "url" like audio/filesong.mp3 or video/filevideo.mp4.
But if I download files with the next code:
function downloadFile() {
var fileTransfer = new FileTransfer();
var uri = encodeURI("UrlOfTheFile");
var fileURL = "cdvfile://localhost/persistent/appcustomstorage/";
fileTransfer.download(
uri, fileURL + "file.extension", function(entry) {
console.log("download complete: " + entry.toURL());
}, 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=="
}
});
}
I download the file in StorageRoot/appcustomstorage/file.extension
It is possible to store the file in the app package, i.e., in, for example, Android/data/com.example.app??
Or a method to get the Android/data/com.example.app url and then add the necessary folder?
Solution:
In this case I find all mp3 in the device. It works on Nexus 4.
index.html
<ul data-role="listview" data-inset="true" id="ulsongs">
</ul>
index JavaScript:
document.addEventListener("deviceready", onDeviceReady, false);
// device APIs are available
function onDeviceReady() {
window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, gotFS, fail);
}
function gotFS(fileSystem) {
FileSystem = fileSystem;
// Call to start to find all files
getFileSystem();
}
storageScript:
var FileSystem = null;
var AudioExtensions = [ '.mp3' ];// , '.wav', '.m4a' ];
var my_media = null;
function listDir(directoryEntry, level) {
if (level === undefined)
level = 0;
var directoryReader = directoryEntry.createReader();
directoryReader.readEntries(function(entries) { // success get files and
// folders
for ( var i = 0; i < entries.length; ++i) {
if (entries[i].name === '.')
continue;
if (entries[i].isDirectory) {
FileSystem.root.getDirectory(entries[i].fullPath.slice(1,
entries[i].fullPath.length), {
create : false
}, function(dirEntry) {
listDir(dirEntry, level + 1);
}, function(error) {
console.log('ERROR');
alert(error.code);
});
}
if (entries[i].isFile) {
var extension;
extension = entries[i].name.substr(entries[i].name
.lastIndexOf('.'));
if (entries[i].isFile === true
&& $.inArray(extension, AudioExtensions) >= 0) {
// Add a song to the list
$("#ulsongs").append(
"<li id='" + entries[i].fullPath + "'"
+ " data-icon=\"audio\"><a>"
+ entries[i].name + "</a></li>");
$('#ulsongs').listview('refresh');
}
}
}
}, function(error) { // error get files and folders
alert('Error. Code: ' + error.code);
});
// Action listener
$('#ulsongs li').click(function(e) {
pathsong = $(this).attr('id');
console.log('item clicked. Path: ' + pathsong);
if (typeof (pathsong) != 'undefined' && pathsong != null) {
// Stop previous song
if ((audio_status != null) && (audio_status == 2)) {
console.log('STOP AUDIO');
my_media.stop();
my_media.release();
}
// Play the audio file at url
my_media = new Media(pathsong,
// success callback
function() {
console.log("playAudio():Audio Success");
},
// error callback
function(err) {
console.log("playAudio():Audio Error: " + err);
}, status);
// Play audio
my_media.play();
}
});
}
var audio_status = null;
function status(stat) {
audio_status = stat;
}
/**
*
*/
function getFileSystem() {
console.log('entra getFileSystem');
window.requestFileSystem(LocalFileSystem.PERSISTENT, 0,
function(fileSystem) { // success get file system
var sdcard = fileSystem.root;
sdcard.getDirectory('', {
create : false
}, function(dirEntry) {
listDir(dirEntry);
}, function(error) {
alert(error.code);
})
}, function(evt) { // error get file system
console
.log('ERROR GETTING FILE SYSTEM'
+ evt.target.error.code);
});
}
I create a list of mp3.
I use jQuery and jQueryMobile
Edit
The process may need a bit of time. It is recommended to show a loading popup.
Related
I am creating an app with cordova for android using plugin file-transfer. The download is going to a certain folder but I can't read the file despite indicating the correct path follows the code
var uri = encodeURI(mypage);
var fileURL = cordova.file.externalDataDirectory + "teste.ogg";
fileTransfer.download(
uri, fileURL, function(entry) {
console.log("download complete: " + entry.toURL());
$("#audio-teste").attr('src',fileURL)
/*--codigo de teste--*/
var meuFile = cordova.file.externalDataDirectory;
resolveLocalFileSystemURL(meuFile, function(entry) {
var readerN = fileSystem.createReader();
readerN.readEntries(
function (entry) {
var arrayN =[];
for(var i="0"; i < entry.length; ++i){
var entradaN = entry[i].name;
arrayN.push(entradaN);
//console.log(array);
console.log('teste aq' + arrayN);
}
}
)
//console.log(entry);
});
/*----*/
},
function(error) {
console.log("download error source " + error.source);
console.log("download error target " + error.target);
console.log("download error code" + error.code);
},
false, {
headers: {
"Authorization": "Basic dGVzdHVzZXJuYW1lOnRlc3RwYXNzd29yZA=="
}
}
);
/*----*/
The cordova plugin cordova-plugin-file-transfer is due to be deprecated and its latest npm version fails on iOS.
Therefore these two working functions are purely based on vanilla JS, and thus no need to use extra plugins, besides the standard plugin cordova-plugin-file. Therefore this is compatible with any platform.
https://gist.github.com/jfoclpf/07e52f6bdf9c967449c4bc06af44c94a
I paste here for your convenience:
// for different types of cordovaFileSystem check here:
// https://cordova.apache.org/docs/en/latest/reference/cordova-plugin-file/#where-to-store-files
// or simply type in the console `console.log(cordova.file)`
function downloadFileToDevice (fileurl, filename, cordovaFileSystem, callback) {
var onerror = (err) => {
console.error(`Error downloading from ${fileurl} to cordovaFileSystem ${cordovaFileSystem}`,
err, new Error(err))
if (typeof callback === 'function') { callback(Error(err)) }
}
var blob = null
var xhr = new XMLHttpRequest()
xhr.open('GET', fileurl)
xhr.responseType = 'blob' // force the HTTP response, response-type header to be blob
xhr.onload = () => {
blob = xhr.response // xhr.response is now a blob object
var DataBlob = blob
window.resolveLocalFileSystemURL(cordovaFileSystem, (dirEntry) => {
const sanitizedFilename = filename.replace(/[^a-z0-9\.]/gi, '_').toLowerCase() // sanitize filename
dirEntry.getFile(sanitizedFilename, { create: true }, (file) => {
file.createWriter((fileWriter) => {
fileWriter.write(DataBlob)
if (typeof callback === 'function') { callback(null, cordovaFileSystem + sanitizedFilename) }
}, (err) => { console.error('Error on file.createWriter'); onerror(err) })
}, (err) => { console.error('Error on dirEntry.getFile'); onerror(err) })
}, (err) => { console.error('Error on resolveLocalFileSystemURL'); onerror(err) })
}
xhr.onerror = (err) => { console.error('Error on XMLHttpRequest'); onerror(err) }
xhr.send()
}
An example for downloading a file
downloadFileToDevice('https://example.com/img.jpg',
'myImg.jpg',
cordova.file.cacheDirectory,
(err, localFilePath) => {
if (err) {
console.error('An error occured downloading file:', err)
} else {
console.log('Download file with success: ' + localFilePath)
}
})
Can you try with this? I tried and it works like a charm
From my Phonegap App I am downloading my APK which happens with no issues but I cannot get the file installed once its there.
The following bit of code just fails during the WEB INTENT section which should install the APk but its having trouble reading the file.
var apkFilePath = cordova.file.externalApplicationStorageDirectory+'myapp.apk';
// Android UPDATE routine
function downloadApkAndroid(data) {
var permissions = cordova.plugins.permissions;
permissions.hasPermission(permissions.WRITE_EXTERNAL_STORAGE, function (status) {
if (!status.hasPermission) {
var errorCallback = function () {
alert("Error: app requires storage permission");
if (callBack && callBack !== null) {
callBack();
}
};
permissions.requestPermission(permissions.WRITE_EXTERNAL_STORAGE,
function (status) {
if (!status.hasPermission)
errorCallback();
else {
downloadFile();
}
},
errorCallback);
}
else {
downloadFile();
}
}, null);
}
function downloadFile(){
var fileTransfer = new FileTransfer();
var url = "https://myappurl.com/myapp.apk";
var uri = encodeURI(url);
var filePath = getFilePath();
fileTransfer.download(
uri,
apkFilePath,
function (entry) {
console.log("Download complete: " + entry.fullPath);
promptForUpdateAndroid(entry);
},
function (error) {
console.error("Download error source " + error.source);
console.error("Download error target " + error.target);
console.error("Download error code " + error.code);
},
false,
{
}
);
}
/*
* Uses the borismus webintent plugin
*/
function promptForUpdateAndroid(entry) {
console.log(apkFilePath);
window.plugins.webintent.startActivity(
{
action: window.plugins.webintent.ACTION_VIEW,
url: apkFilePath,
type: 'application/vnd.android.package-archive'
},
function () {
},
function () {
// alert('Failed to open URL via Android Intent.');
console.log("Failed to open URL via Android Intent. URL: " + entry.fullPath);
}
);
}
So figured this out by using cordova-plugin-file-opener2 and changing the promptForUpdateAndroid() to get rid of Web Intents:
var myFilePath = cordova.file.dataDirectory+'myApp.apk';
function promptForUpdateAndroid(entry) {
cordova.plugins.fileOpener2.open(
myFilePath,
'application/vnd.android.package-archive',
{
error : function(e) {
console.log('Error status: ' + e.status + ' - Error message: ' + e.message);
},
success : function () {
console.log('file opened successfully');
}
}
);
This instantly installed the app, though it didn't re-open once installed. I'm off to figure that out.
I have uploaded vcf file successfully on server on getting help from my previous question (the one which is edited)
Now I need a help in how to read that vcf file or vcard from server and display as a contact number and contact name in my phonegap app.
plugin used cordova-plugin-file-transfer
Can anyone help on this ?
Using plugin cordova-plugin-file-transfer https://github.com/apache/cordova-plugin-file-transfer you can download file from server.
For Read vcf file, you need https://github.com/nilclass/vcardjs JavaScript based library. you can directly use .js files.
You can follow below example.
window.requestFileSystem(window.TEMPORARY, 1 * 1024 * 1024, function (fs) {
console.log('file system open: ' + fs.name);
var fileName = "temp.vcf";
var dirEntry = fs.root;
dirEntry.getFile(fileName, { create: true, exclusive: false }, function (fileEntry) {
download(fileEntry,"server-path-to-file.vcf");
}, onErrorCreateFile);
}, onErrorLoadFs);
function download(fileEntry, uri) {
var fileTransfer = new FileTransfer();
var fileURL = fileEntry.toURL();
fileTransfer.download(
uri,
fileURL,
function (entry) {
console.log("Successful download...");
console.log("download complete: " + entry.toURL());
readFile(entry);
},
function (error) {
console.log("download error source " + error.source);
console.log("download error target " + error.target);
console.log("upload error code" + error.code);
},
null, // or, pass false
{
//headers: {
// "Authorization": "Basic dGVzdHVzZXJuYW1lOnRlc3RwYXNzd29yZA=="
//}
}
);
}
function readFile(fileEntry) {
fileEntry.file(function (file) {
var reader = new FileReader();
reader.onloadend = function () {
console.log("Successful file read: " + reader.result);
reader.parseVCard(reader.result);
};
reader.readAsText(file);
}, onErrorReadFile);
}
function parseVCard(vCarddata){
VCF.parse(vCarddata, function(vcard) {
// this function is called with a VCard instance.
// If the input contains more than one vCard, it is called multiple times.
console.log("Formatted name", vcard.fn);
console.log("Names", JSON.stringify(vcard.n));
});
//Fore more help:https://github.com/nilclass/vcardjs
}
Let's say I have a API that stores some .mp3 music.
The sample link here:
https://118.69.201.34:8882/api/ApiMusic/Download?songId=2000
Now I want to write an API calling function in Angularjs to download the music to my Android devices with the song's Id number as in the link.
How can I do that? Please help :(
You can use the ngCordova FileTransfer library here: http://ngcordova.com/docs/plugins/fileTransfer/
Here's example code from that page, tweaked to your example URL:
document.addEventListener('deviceready', function () {
var fileid = "2000";
var url = "https://118.69.201.34:8882/api/ApiMusic/Download?songId=" + fileid;
var targetPath = cordova.file.documentsDirectory + fileid + ".mp3";
var trustHosts = true
var options = {};
$cordovaFileTransfer.download(url, targetPath, options, trustHosts)
.then(function(result) {
// Success!
}, function(err) {
// Error
}, function (progress) {
$timeout(function () {
$scope.downloadProgress = (progress.loaded / progress.total) * 100;
})
});
}, false);
I did it finally, here is my code. Just share for those who want to refer to this issue in the future. Thanks you guys for your answers
$scope.download = function(songId, songName) {
$ionicLoading.show({
template: 'Downloading...'
});
window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, function (fs) {
fs.root.getDirectory(
"fMusic",
{
create: true
},
function (dirEntry) {
dirEntry.getFile(
songName + ".mp3",
{
create: true,
exclusive: false
},
function gotFileEntry(fe) {
var p = fe.toURL();
fe.remove();
ft = new FileTransfer();
ft.download(
encodeURI(APIUrl + songId),
p,
function (entry) {
$ionicLoading.hide();
$scope.mp3File = entry.toURL();
},
function (error) {
$ionicLoading.hide();
alert("Download Error Source --> " + error.source);
},
false,
null
);
},
function () {
$ionicLoading.hide();
console.log("Get the file failed");
}
);
}
);
},
function () {
$ionicLoading.hide();
console.log("Request for filesystem failed");
});
}
I am developing an app with JQM and then using build.phonegap.com, i am building the app.
I have a feature to download the audio file from the server and then play it in the app.
it is working perfectly in android.
I tried all possibilities to make it work.
can some one help on this.
here is my complete file handling code
fileSystem.root.getDirectory("auidofiles", {
create : true,
exclusive : false
}, function(dirEntry) {
dirEntry.getFile(mp3_file, {
create : false,
exclusive : false
}, function(fileEntry) {
alert("File Already downloaded");
if (device.platform == "Android") {
FILEPATH = fileEntry.fullPath;
//FILEPATH = fileEntry.toURI();
playAudio();
} else {
var filePathLocal1 = getPhoneGapPath() + "auidofiles/" + mp3_file;
//var filePathLocal = fileSystem.root.toURL() + "auidofiles/" + mp3_file;
//alert("Ios File Path:" + filePathLocal);
//FILEPATH = filePathLocal;
//FILEPATH = fileEntry.fullPath;
//FILEPATH = fileEntry.toURI();
playAudio();
}
}, function(fileFail) {
alert("File Not found");
var ft = new FileTransfer();
ft.onprogress = function(progressEvent) {
if (progressEvent.lengthComputable) {
var perc = Math.floor(progressEvent.loaded
/ progressEvent.total * 100);
$('#downloadStatus').html(perc + "% loaded...");
} else {
if ($('#downloadStatus').html() == "") {
$('#downloadStatus').html("Loading");
} else {
$('#downloadStatus').html(
$('#downloadStatus').html() + ".");
}
}
}; //ft.Progress
var filePathLocal = fileSystem.root.toURL() + "auidofiles/" + mp3_file;
ft.download(audioStreamUrl, filePathLocal, function(entry) {
//alert("File = " + entry.toURI());
if (device.platform == "Android") {
FILEPATH = entry.fullPath;
//FILEPATH = entry.toURI();
playAudio();
} else {
var filePathLocal1 = getPhoneGapPath() + "auidofiles/" + mp3_file;
//alert("Ios File Path:" + filePathLocal);
FILEPATH = filePathLocal;
//FILEPATH = entry.fullPath;
//FILEPATH = entry.toURI();
playAudio();
}
}, function(error) {
$('#downloadStatus').html(
"download error source " + error.source);
$('#downloadStatus').html(
"download error target " + error.target);
$('#downloadStatus').html("upload error code" + error.code);
}); //ft.Download
}); //getFile End
}, function(dirfail) {
alert("dirfail");
alert(JSON.stringify(dirfail))
$('#downloadStatus').html(JSON.stringify(dirfail));
})
function getPhoneGapPath() {
var path = window.location.pathname;
path = path.substr( 0, path.length - 10 );
return 'file://' + path;
};
There is a new requirement to use .toURL() instead of .fullPath
This fixes the majority of these type of problems - however I have experienced a similar problem using older versions of the iOS (5.x) where filetransfer.download never fires success/fail/progress events even though it does actually download the file. I then get an app crash when I try to restart the app...
I had the same issue and fixed it with downgrading the Cordova Plugin FileTransfer from v0.4.2 to v0.3.3 while using Phonegap/Cordova v3.3.