tobydeh / nativescript-download-progress

Download large files in Nativescript with progress events
Apache License 2.0
11 stars 16 forks source link

Downloads fail with 'java.io.File is not a constructor' #17

Open MonasteryJohn opened 4 years ago

MonasteryJohn commented 4 years ago

I am using fairly vanilla download code in my application. The first attempt during a given application session succeeds, but any attempts at downloading additional files results in an error. The error in the promise rejection is just a blank object {} but I was able to figure out that the actual exception message in the android-worker.js is java.io.File is not a constructor. This error seems to come from the attempt at fs.File.fromPath(path).

I tried to isolate whether this bug was in this library or in the nativescript core itself, but I can make the call to fs.File.fromPath(path) successfully from my code before calling the downloader. It works fine in my code, but the attempt from the downloader (in the same method) fails. This makes me to think it has something to do with how the worker interacts with the file system.

Which platform(s) does your issue occur on?

Please, provide the following version numbers that your issue occurs with:

  "dependencies": {
    "@angular/animations": "~8.2.0",
    "@angular/common": "~8.2.0",
    "@angular/compiler": "~8.2.0",
    "@angular/core": "~8.2.0",
    "@angular/forms": "~8.2.0",
    "@angular/http": "8.0.0-beta.10",
    "@angular/platform-browser": "~8.2.0",
    "@angular/platform-browser-dynamic": "~8.2.0",
    "@angular/router": "~8.2.0",
    "@ngx-translate/core": "^10.0.2",
    "@ngx-translate/http-loader": "^3.0.1",
    "buffer": "^5.2.1",
    "moment": "^2.22.2",
    "nativescript-angular": "^8.21.0",
    "nativescript-appversion": "^1.4.1",
    "nativescript-checkbox": "^3.0.3",
    "nativescript-datetimepicker": "^1.2.2",
    "nativescript-download-progress": "^1.2.0",
    "nativescript-email": "^1.5.3",
    "nativescript-fingerprint-auth": "^7.0.2",
    "nativescript-imagepicker": "^6.0.3",
    "nativescript-iqkeyboardmanager": "^1.3.0",
    "nativescript-localstorage": "^1.1.5",
    "nativescript-mediafilepicker": "^2.0.12",
    "nativescript-permissions": "^1.2.3",
    "nativescript-printer": "^1.5.0",
    "nativescript-secure-storage": "^2.3.0",
    "nativescript-theme-core": "~1.0.4",
    "nativescript-timedatepicker": "^1.2.1",
    "nativescript-toasty": "^3.0.0-alpha.2",
    "nativescript-urlhandler": "^1.2.3",
    "reflect-metadata": "~0.1.8",
    "rxjs": "^6.4.0",
    "tns-core-modules": "^6.4.1",
    "url-parse": "^1.4.4",
    "zone.js": "^0.9.1"
  },
  "devDependencies": {
    "@angular/compiler-cli": "~8.2.0",
    "@ngtools/webpack": "~8.2.0",
    "nativescript-dev-webpack": "^1.5.1",
    "node-sass": "4.12.0",
    "tns-platform-declarations": "6.0.1",
    "typescript": "~3.5.3"
  }

Please, tell us how to recreate the issue in as much detail as possible.

The code for the download is pretty much equal to the sample code, it looks like this

function doDownload(url, filePath){
 let options = {
   method: "GET",
   headers: {
       "Cookie": //get an auth cookie and put it here
   }
 };

 const downloader = new DownloadProgress();

 downloader.downloadFile(url, options, filePath).then(f => {
  console.log("file download complete");
 }).catch(err=> {
   console.log("download error");
   console.log(err);
 });
}

This doDownload function is being called on an event from android.webkit.DownloadListener like this:

webview.android.setDownloadListener(
   new android.webkit.DownloadListener({
        onDownloadStart(
            url,
            userAgent,
            contentDisposition,
            mimeType,
            contentLength
          ) {                      
            perm
              .requestPermission(
                android.Manifest.permission.WRITE_EXTERNAL_STORAGE,
                "Needed to Download Documents from Vocus"
              )
              .then(
                () => {
                  _this.doDownload(url, getPath(...));
                },
                () => {
                      console.log("permissions rejected");
                 }
              );
          }
   });
tobydeh commented 4 years ago

I think this issue might be related to using DownloadProgress() inside webkit.DownloadListener. Could you please make a sample project that shows how you're using it and ill take a look.

nikoTM commented 4 years ago

@tobydeh probably not related, because I get the same error as well, but I am not using webkit.DownloadListener. For me the first download works as expected, but the second one fails with this error.

nikoTM commented 4 years ago

@MonasteryJohn @tobydeh upon further investigation it seems like this is happening because of worker terminations, after commenting out worker.terminate() and moving worker import/constructor to DownloadProgress -> constructor (binding to this.worker) it seems to be working as expected. I assume workers are supposed to be created once and reused. If I don't find further issues with this I will send a PR.

tobydeh commented 4 years ago

@nikoTM Thanks for taking the time to investigate the issue. I think you've hit the nail on the head - worker threads can't be reused after calling terminate()

tobydeh commented 4 years ago

I'm having trouble recreating this, can someone please create an example project demonstrating the issue?

erkanarslan commented 4 years ago

I tried @nikoTM's solution and it works. Not a good solution but you can replace the file in node_modules/nativescript-download-progress with this file. download-progress.android.js.zip

tobydeh commented 3 years ago

Please can you try nativescript-download-progress@next