Hi Ive got an app that im trying to add a built in updater to. The app contains a button that downloads an apk file from my server. The file names on the server are named as follows:
"App-1.apk",
"App-2.apk",
"App-3.apk"
...
The button is currently setup like this:
download = (Button) findViewById(R.id.bDownload);
versionNum = 3;
download.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
Intent downloadFromServer = new Intent();
downloadFromServer.setAction(Intent.ACTION_VIEW);
downloadFromServer.addCategory(Intent.CATEGORY_BROWSABLE);
downloadFromServer.setData(Uri.parse("http://server.com/Files/App-" + versionNum + ".apk"));
startActivity(downloadFromServer);
}
});
What would be a good way to check for the highest available app version on the server, and pick that one to download?
Edit: How can I use java to check the server directory for the highest numbered app?
Edit2: Heres what i ended up doing. Not the best solution, but good enough for now:
try {
PackageInfo appInfo = getPackageManager().getPackageInfo(getPackageName(), 0);
installedVersion = appInfo.versionName;
} catch (PackageManager.NameNotFoundException e) {
// Handle exception
}
//Latest version available on my server. Must update this value for each new release
latestVersion = 3.1;
//Convert string value of installed version to double so that it can be compared with value of latest version
installedVersionValue = Double.parseDouble(installedVersion);
download = (Button) findViewById(R.id.bDownload);
download.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
if (installedVersionValue<latestVersion) { //If latest version available on server is greater than installed version, download the latest
Intent downloadFromServer = new Intent();
downloadFromServer.setAction(Intent.ACTION_VIEW);
downloadFromServer.addCategory(Intent.CATEGORY_BROWSABLE);
downloadFromServer.setData(Uri.parse("http://server.com/Files//App-" + latestVersion + ".apk"));
startActivity(downloadFromServer);
}
else if (installedVersionValue==latestVersion) { //If user clicks the update button while they already have the latest, let them no what's up
Toast.makeText(getApplicationContext(), "You are already running the latest version (" + installedVersionValue +")",
Toast.LENGTH_LONG).show();
}
}
});
You can add the version of code, or the version of your app in manifest, as you can see here:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.package.name"
android:versionCode="2"
android:versionName="1.1">
And you can check it:
PackageInfo pinfo = getPackageManager().getPackageInfo(getPackageName(), 0);
int versionNumber = pinfo.versionCode;
You can set the number of code as name in a table of db on your server, and then you check that field to update your app.
You can try something like this:
pass to server a request like this: youServer/apkUpdate?versionCode={versionCode}
and in your server you use a method like this:
#RequestMapping(method = RequestMethod.GET)
public void getUpdatedApk(
#RequestParam(value = "versionCode", required = true) final Integer versionCode,
#RequestParam(value = "androidVersion", required = false) final Integer androidVersion,
final HttpServletRequest request,
final HttpServletResponse response) throws Exception{
apkUpdateService.getUpdate(new Long(versionCode), response);
}
Where the api update service is:
public void getUpdate(Long currentVersionCode, HttpServletResponse response) throws Exception {
//get latest number of apk from a db field
Long dbVersionCode = apkUpdateRepository.findLastVersion();
ServletOutputStream servletOutputStream = null;
if (currentVersionCode == dbVersionCode){
LOG.info("You have the last version");
return;
}
if (currentVersionCode < dbVersionCode){
FileInputStream inputStream = null;
String filename = String.format(pathToApk, dbVersionCode);
try{
inputStream = new FileInputStream(filename);
servletOutputStream = response.getOutputStream();
byte[] buffer = new byte[1024];
int bytesRead = 0;
while ((bytesRead = inputStream.read(buffer)) != -1) {
servletOutputStream.write(buffer, 0, bytesRead);
}
servletOutputStream.flush();
LOG.info("File streamed");
LOG.info("Download "+filename);
}finally{
if (inputStream!=null){
inputStream.close();
}
if (servletOutputStream != null){
servletOutputStream.close();
}
}
}
}
You could for example:
String installedVersion = "";
try {
PackageInfo manager = activity.getPackageManager().getPackageInfo(activity.getPackageName(), 0);
installedVersion = manager.versionCode + "";
} catch (PackageManager.NameNotFoundException e) {
// Handle exception
}
"http://server.com/Files/update?installed=" + installedVersion
On the server side you could do something like:
int installedVersion = ...
int latestVersion = ...
if(installedVersion < latestVersion){
//return file
}else{
//Return message: you have the latest
}
I think the easiest would be checking file existence in ascending order and than downloading the last present one. File existence checking was already answered here: Check if file exists on remote server using its URL
Related
I'm trying to implement a wrapped "move" function with Xodus, but something is not working out right:
#Override
public boolean move(String appId, String name, String targetName) {
final boolean[] success = new boolean[1];
final Environment env = manager.getEnvironment(xodusRoot, appId);
final VirtualFileSystem vfs = manager.getVirtualFileSystem(env);
env.executeInTransaction(
new TransactionalExecutable() {
#Override
public void execute(#NotNull final Transaction txn) {
File file = vfs.openFile(txn, name, false);
InputStream input = vfs.readFile(txn, file);
if(input != null) {
File targetFile = vfs.openFile(txn, targetName, true);
DataOutputStream output = new DataOutputStream(vfs.writeFile(txn, targetFile));
try {
output.write(ByteStreams.toByteArray(input));
} catch (IOException e) {
e.printStackTrace();
}
vfs.deleteFile(txn, name);
success[0] = true;
}
}
});
// vfs.shutdown();
// env.close();
return success[0];
}
The problem is the file gets moved but the byte array is not getting copied, not sure if the problem is because of multiple VFS operation in the same transaction. Can someone give me a hint of why the bytes from the source file are not getting copied properly?
Looks like you are trying to implement another version of VirtualFileSystem.renameFile(..).
I'm trying to add a class in my application by which I can download different type of files instead of pdf on API 23 and lower.
I have tested my codes on API 24 and upper and I can easily download pdf files but I don't know why it's not working on API <= 23.
public class FileDownloader {
private static final int MEGA_BYTE = 1024 * 1024;
public interface OnDownloadListener{
void onStarted();
void onProgressUpdate(int upd);
void onFinished(String result);
void onError(Exception e);
}
// usually, subclasses of AsyncTask are declared inside the activity class.
// that way, you can easily modify the UI thread from here
public static class DownloadTask extends AsyncTask<String, Integer, String> {
private Context context;
private OnDownloadListener onDownloadListener;
public DownloadTask(Context context, OnDownloadListener onDownloadListener) {
this.context = context;
this.onDownloadListener = onDownloadListener;
}
#Override
protected String doInBackground(String... str) {
// take CPU lock to prevent CPU from going off if the user
// presses the power button during download
PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
getClass().getName());
wl.acquire();
try {
InputStream input = null;
OutputStream output = null;
HttpURLConnection connection = null;
try {
URL url = new URL(str[0]);
connection = (HttpURLConnection) url.openConnection();
connection.connect();
// expect HTTP 200 OK, so we don't mistakenly save error report
// instead of the file
if (connection.getResponseCode() != HttpURLConnection.HTTP_OK)
return "Server returned HTTP " + connection.getResponseCode()
+ " " + connection.getResponseMessage();
// this will be useful to display download percentage
// might be -1: server did not report the length
int fileLength = connection.getContentLength();
// download the file
input = connection.getInputStream();
output = new FileOutputStream(str[1]); // /sdcard/file_name.extension
byte data[] = new byte[MEGA_BYTE];
long total = 0;
int count;
while ((count = input.read(data)) != -1) {
// allow canceling with back button
if (isCancelled())
return null;
total += count;
// publishing the progress....
if (fileLength > 0) // only if total length is known
publishProgress((int) (total * 100 / fileLength));
output.write(data, 0, count);
}
} catch (Exception e) {
e.printStackTrace();
if(onDownloadListener != null){
onDownloadListener.onError(e);
}
return e.toString();
}finally {
try {
if (output != null)
output.close();
if (input != null)
input.close();
}catch (IOException ignored) { }
if (connection != null)
connection.disconnect();
}
} finally {
wl.release();
}
return null;
}
#Override
protected void onPreExecute() {
super.onPreExecute();
if(onDownloadListener != null){
onDownloadListener.onStarted();
}
}
#Override
protected void onProgressUpdate(Integer... progress) {
super.onProgressUpdate(progress);
// if we get here, length is known, now set indeterminate to fals
if(onDownloadListener != null){
onDownloadListener.onProgressUpdate(progress[0]);
}
}
#Override
protected void onPostExecute(String result) {
if(onDownloadListener != null){
onDownloadListener.onFinished(result);
}
}
}
}
When "HttpURLConnection" tries to connect it returns error code 404 which means "HTTP 404 Not Found" but on API >= 24 it works fine and also I can download these files via web browsers too.
I also tried to use "DownloadManager" class but it returns "Failed" when I start downloading pdf files on API <= 23.
How can I fix this problem on API <= 23?!!
Thanks in advance.
Set your minSdkVersion to maybe 15. This will make your app compatible with devices API 15 and above
I am building an android email client app. I managed to display the emails headers/senders in a RecylerView. Next, I want to start a new activity that will display the email content/attachments when the user chooses a specific mail.
I have a hard time doing this through intents. I am able to get the contents of the email (text, inline images, attachments) but I can't figure out a way to display them as close to the original format as possible. I thought of putting the text in a StringBuilder and sending it through an intent in order to display the text, but this way I can't display the inline images in the right place and there are also formatting problems.
Any kind of guidance towards the way I should approach this is much appreciated.
The class that displays the list of the available mails and gets the content of the specific mail to send it another activity for displaying it. I know the code is a little hazardous, I tried many approaches and it is far from the final form.
public class CheckMail extends Activity {
static List<Message> messages = new ArrayList<>();
String[] sender;
String[] date;
String[] subject;
boolean[] seen;
Context context = null;
ListView listView;
Intent intent;
Store store;
StringBuilder content = new StringBuilder();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_check_mail);
if (android.os.Build.VERSION.SDK_INT > 9)
{
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
}
context = this;
ReadEmails task = new ReadEmails();
task.execute();
}
public void writePart(Part p) throws Exception {
if (p instanceof Message)
this.writeEnvelope((Message) p);
//check if the content is plain text
if (p.isMimeType("text/plain")) {
content.append(p.getContent().toString());
}
//check if the content has attachment
else if (p.isMimeType("multipart/*")) {
System.out.println("This is a Multipart");
System.out.println("---------------------------");
Multipart mp = (Multipart) p.getContent();
int count = mp.getCount();
for (int i = 0; i < count; i++)
writePart(mp.getBodyPart(i));
}
//check if the content is a nested message
else if (p.isMimeType("message/rfc822")) {
System.out.println("This is a Nested Message");
System.out.println("---------------------------");
writePart((Part) p.getContent());
}
/*
//check if the content is an inline image
else if (p.isMimeType("image/jpeg")) {
System.out.println("--------> image/jpeg");
Object o = p.getContent();
InputStream x = (InputStream) o;
// Construct the required byte array
System.out.println("x.length = " + x.available());
while ((i = (int) ((InputStream) x).available()) > 0) {
int result = (int) (((InputStream) x).read(bArray));
if (result == -1)
int i = 0;
byte[] bArray = new byte[x.available()];
break;
}
FileOutputStream f2 = new FileOutputStream("/tmp/image.jpg");
f2.write(bArray);
}
else if (p.getContentType().contains("image/")) {
System.out.println("content type" + p.getContentType());
File f = new File("image" + new Date().getTime() + ".jpg");
DataOutputStream output = new DataOutputStream(
new BufferedOutputStream(new FileOutputStream(f)));
com.sun.mail.util.BASE64DecoderStream test =
(com.sun.mail.util.BASE64DecoderStream) p
.getContent();
byte[] buffer = new byte[1024];
int bytesRead;
while ((bytesRead = test.read(buffer)) != -1) {
output.write(buffer, 0, bytesRead);
}
}
else {
Object o = p.getContent();
if (o instanceof String) {
System.out.println("This is a string");
System.out.println("---------------------------");
System.out.println((String) o);
}
else if (o instanceof InputStream) {
System.out.println("This is just an input stream");
System.out.println("---------------------------");
InputStream is = (InputStream) o;
is = (InputStream) o;
int c;
while ((c = is.read()) != -1)
System.out.write(c);
}
else {
System.out.println("This is an unknown type");
System.out.println("---------------------------");
System.out.println(o.toString());
}
}
*/
}
public void writeEnvelope(Message m) throws Exception {
System.out.println("This is the message envelope");
System.out.println("---------------------------");
Address[] a;
StringBuilder sender = new StringBuilder();
StringBuilder recipients = new StringBuilder();
String subject = "";
// FROM
if ((a = m.getFrom()) != null) {
for (int j = 0; j < a.length; j++)
sender.append(a[j].toString());
}
// TO
if ((a = m.getRecipients(Message.RecipientType.TO)) != null) {
for (int j = 0; j < a.length; j++)
recipients.append(a[j].toString());
}
// SUBJECT
if (m.getSubject() != null)
subject = m.getSubject();
intent.putExtra("Sender", sender.toString());
intent.putExtra("Recipients", recipients.toString());
intent.putExtra("Message", subject);
intent.putExtra("Date", m.getReceivedDate().toString());
}
class ReadEmails extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(String... params) {
// Create all the needed properties - empty!
Properties connectionProperties = new Properties();
// Create the session
Session session = Session.getDefaultInstance(connectionProperties, null);
try {
System.out.print("Connecting to the IMAP server...");
// Connecting to the server
// Set the store depending on the parameter flag value
store = session.getStore("imaps");
// Set the server depending on the parameter flag value
String server = "imap.gmail.com";
store.connect(server, "....#gmail.com", "password");
System.out.println("done!");
// Get the Inbox folder
Folder inbox = store.getFolder("Inbox");
// Set the mode to the read-only mode
inbox.open(Folder.READ_ONLY);
// Get messages
CheckMail.messages = Arrays.asList(inbox.getMessages());
System.out.println("Reading messages...");
sender = new String[messages.size()];
date = new String[messages.size()];
subject = new String[messages.size()];
seen = new boolean[messages.size()];
for (int i = 0; i < messages.size(); i++) {
try {
Address[] froms = messages.get(i).getFrom();
String email = froms == null ? null : ((InternetAddress) froms[0]).getAddress();
sender[i] = email;
date[i] = messages.get(i).getReceivedDate().toString();
subject[i] = messages.get(i).getSubject();
Flags flags = messages.get(i).getFlags();
Flags.Flag[] sf = flags.getSystemFlags();
for (int j = 0; j < sf.length; j++) {
if (sf[j] == Flags.Flag.SEEN)
seen[i] = true;
else
seen[i] = false;
}
} catch (MessagingException e) {
e.printStackTrace();
}
}
System.out.println("Done reading...");
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(String result) {
CustomListAdapter whatever = new CustomListAdapter((Activity) context, sender, date, subject, seen);
listView = (ListView) findViewById(R.id.listviewID);
listView.setAdapter(whatever);
listView.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position,
long id) {
try {
content.delete(0, content.length());
intent = new Intent(context, OpenMail.class);
writePart(messages.get(position));
intent.putExtra("Content", content.toString());
startActivity(intent);
}
catch (Exception e)
{e.printStackTrace();}
}
});
}
}
}
Since no one answered...I display emails via Javamail in some of my apps.
I think you're on the right track, having separate activities for the list and viewer is a good approach. [Or separate fragments because on a tablet you may want to display the list and the body on the same screen, side by side]
Couple issues that might come up:
I would be cautious about putting the email content in an extra to start the activity and/or committing it to saved instance state in the viewer activity because there are size limits [For example, 1MB for saved instance state on Android 7+]
Downloading the email in a ASyncTask in the activity might not be the best approach. I don't know the full purpose of the app, but I assume that is something that should succeed whether the user waits or not? The ASyncTask will continue to run if they task away, but it will hold on to the activity context causing a so called 'temporary memory leak'. It is probably best to put it in a service and download it in a separate thread. However, doing it in the activity as a proof of concept is perfectly reasonable...
I don't think that walking the message structure in the email list activity is the best approach. In my apps, I download email in a background service and commit the data to an SQL-DB via a ContentProvider. On the message viewer screen the email body is retrieved from the ContentProvider/SQL-DB using a component called the CursorLoader. It handles all the loading in the background so that the UI remains responsive whilst loading large mails. But in any event, I avoid passing the message body between activities.
A lot of emails have HTML parts (multipart/alternative: text/plain & text/html) so the viewer was implemented as a WebView. The WebView produced good looking emails with minimal effort.
Couple miscellaneous gotchas, when retrieving the mail, take care to call setPeek(true). It will stop the the READ flag being set. It is not an issue for GMail, but some IMAP servers will set this flag. Users will complain if any app other than their primary email app changes the READ flag. Also don't assume that any of the headers are present, SPAM emails are notorious for leaving out the message ID, subject and other fields. Finally, it might be worth considering implementing authentication via OAuth2 which will enable your app to connect to a user's GMail account via Javamail without needing their password.
I'm not sure that any of that really helps because it is a pretty big job, but one step at a time...Cheers!
I referenced a question here about how one might approach (outside of Google Play) having an app essentially update itself. For testing, I simply wanted to try to see if I could get it to download and install. Unfortunately, I get a parse error.
I would greatly appreciate any help:
A snippet from the class that calls the AsyncTask class:
public class downloadReceiver extends BroadcastReceiver {
private Context context;
private long localUpdate;
private long remoteUpdate = 20;
#Override
public void onReceive(final Context c, Intent i) {
new Thread(new Runnable() {
#Override
public void run() {
SharedPreferences preferences = c.getSharedPreferences("config", c.MODE_PRIVATE);
final String store = preferences.getString("store", "");
final String id = preferences.getString("id", "");
final long lastUpdated = preferences.getLong("updated", 0);
// autoUpdate app
appUpdater updater = new appUpdater(c);
try {
updater.execute(new URL("http://midamcorp.com/myApp.php"));
} catch (Exception e) {Log.e(this.getClass().toString(), " " + e.getMessage()); }
and the appUpdater class:
public class appUpdater extends AsyncTask<URL, String, String> {
private Context c;
public appUpdater(Context context) {
this.c = context;
}
protected String doInBackground(URL... appUrl) {
String location = c.getFilesDir() + "/app.apk";
try {
URL url = appUrl[0];
URLConnection con = url.openConnection();
con.connect();
InputStream input = new BufferedInputStream(url.openStream());
OutputStream output = new FileOutputStream(location);
byte[] buffer = new byte[1024];
int read = 0;
while ((read = input.read(buffer)) != -1) {
output.write(buffer, 0, read);
}
output.close();
input.close();
} catch(Exception e){
Log.e(this.getClass().toString(), " " + e.getMessage());
}
return location;
}
#Override
protected void onPostExecute(String saveLocation) {
Intent i = new Intent();
i.setAction(Intent.ACTION_VIEW);
Log.i("Location of app is: ", " " + saveLocation);
i.setDataAndType(Uri.fromFile(new File(saveLocation)), "application/vnd.android.package-archive");
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
c.startActivity(i);
}
}
Please note, the URL is linked to a PHP file that forces a download because the server I have it on has trouble with .apk files.
Your primary problem is that the installer does not have access to your portion of internal storage (getFilesDir()). Use external storage.
I also recommend that you call flush(), getFD().sync(), and close() in succession on your FileOutputStream, before trying to install the app.
Here is the problem. I got an app that download audio files to the phone then play it back. All works without problem. But the little problem is - the customer wants to have something that play straight away when the other files are being download.
So I put an short audio in the www/files/ folder. That works without any issue with iOS. I just reference it (from media player) as
document.addEventListener('deviceready' , function()
{
var media = new Media('files/default.m4a' , function()
{
// this success call back never works!
});
setTimeout(function()
{
media.play();
},100);
});
Now the problem is Android. Got a FileError.NOT_FOUND_ERR error. Looking at LogCat (From Android studio)
The path become
/mnt/sdcard/files/default.m4a
It seems that Android couldn't handle a relative path like iOS (strange enough all the images or template are relative path in the js app. And they all work fine).
Been searching up and down a solution how do I copy just that one audio file to the sd card. no luck so far. The problem is I couldn't correctly find the absolute path to the original file. There are lots of example out there which is total BS. They hardcoded the path in! Android can be anything, in the emulator is /mnt/sdcard/ on my test device turns into /external/sdcard0
And that just from (java):
String path = Environment.getExternalStorageDirectory().getAbsolutePath();
I seen tons and tons of people got the same problem. But the solution out there are pretty out date. Or not really solve the first problem (which is finding out where is the original file in the first place). There must be one problem many people face right?
Thanks in advance.
P.S. I also try this
this.getClass().getPackage().getName();
call from inside the onCreate method. That only got me partial but not the absolute path.
UPDATE
Here is the complete working code (for PhoneGap 3.1)
package YOUR_PACKAGE_NAME;
import android.os.Bundle;
import org.apache.cordova.*;
/* for the other two plugins */
import java.io.*;
import android.os.Environment;
import android.util.Log;
import android.content.res.AssetManager;
public class YourAppName extends CordovaActivity
{
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
super.init();
this.CopyAssets();
super.loadUrl(Config.getStartUrl());
}
private void CopyAssets() {
AssetManager assetManager = getAssets();
InputStream in = null;
OutputStream out = null;
try {
in = assetManager.open(FILE_YOU_WANT_TO_COPY_IN_WWW);
out = new FileOutputStream(Environment.getExternalStorageDirectory()
.toString()
+ WHERE_YOU_WANT_TO_PUT_IT_PLUS_NAME);
this.copyFile(in, out);
in.close();
in = null;
out.flush();
out.close();
out = null;
} catch (Exception e) {
Log.e("tag", e.getMessage());
}
}
private void copyFile(InputStream in, OutputStream out) throws IOException {
byte[] buffer = new byte[1024];
int read;
while ((read = in.read(buffer)) != -1) {
out.write(buffer, 0, read);
}
}
}
Try this :
public class testsample extends DroidGap {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Set by <content src="index.html" /> in config.xml
CopyAssets();
super.setIntegerProperty("loadUrlTimeoutValue", 6000);
super.loadUrl(Config.getStartUrl());
}
private void CopyAssets() {
AssetManager assetManager = getAssets();
InputStream in = null;
OutputStream out = null;
try {
in = assetManager.open("www/img/logo.png"); // if files resides
// inside the "Files"
// directory itself
// "www/img/logo.png" is path of assets/www folder
out = new FileOutputStream(Environment
.getExternalStorageDirectory().toString()
+ "/"
+ "logo.png");
copyFile(in, out);
in.close();
in = null;
out.flush();
out.close();
out = null;
} catch (Exception e) {
Log.e("tag", e.getMessage());
}
}
private void copyFile(InputStream in, OutputStream out) throws IOException {
byte[] buffer = new byte[1024];
int read;
while ((read = in.read(buffer)) != -1) {
out.write(buffer, 0, read);
}
}
}
Do't Forget to Add Permission on AndroidManifest.xml
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
A cleaner option is to install the org.apache.cordova.file-transfer plugin and transfer the file from "file:///android_asset/www/song.mp3" to /YourApp/song.mp3
cordova plugin add org.apache.cordova.file#1.1.0
cordova plugin add org.apache.cordova.file-transfer
And then:
// Assumes variable fileURL contains a valid URL to a path on the device,
// for example, cdvfile://localhost/persistent/path/to/downloads/
var fileTransfer = new FileTransfer();
var uri = encodeURI("http://some.server.com/download.php");
fileTransfer.download(
uri,
fileURL,
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=="
//}
}
);
More info here:
https://github.com/apache/cordova-plugin-file-transfer/blob/master/doc/index.md
This way you only wave to worry about your javascript