Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

file.ReadAsText() doesn't resolve a promise #3265

Closed
vvche69 opened this issue Dec 22, 2019 · 28 comments
Closed

file.ReadAsText() doesn't resolve a promise #3265

vvche69 opened this issue Dec 22, 2019 · 28 comments

Comments

@vvche69
Copy link

vvche69 commented Dec 22, 2019

I'm submitting a ... (check one with "x")
[x ] bug report
[ ] feature request
[ ] support request => Please do not submit support requests here, use one of these channels: https://forum.ionicframework.com/ or https://ionicworldwide.herokuapp.com/

Current behavior:
file.readAsText returns nothing, but only when ionic app has built in production mode and deployed on Android device.

Expected behavior:
It's expected that this function must return a string with file content.

Related code:

this.file.readAsText(this.file.dataDirectory, 'myapp.log').then((logContent) => {
console.log('resolved', logContent);
resolve(logContent)
}).catch((errRes) => {
console.log('rejected', errRes);
reject(errRes);

Other information:
I can see in Android Studio that my file exists and I can download it from the device.
Moreover, I can see in Studio debugger in Java code, that this function is executed, result is not empty, but nothing returns to JS code:

public void readFileAs(final String srcURLstr, final int start, final int end, final CallbackContext callbackContext, final String encoding, final int resultType) throws MalformedURLException {
try {
LocalFilesystemURL inputURL = LocalFilesystemURL.parse(srcURLstr);
Filesystem fs = this.filesystemForURL(inputURL);
if (fs == null) {
throw new MalformedURLException("No installed handlers for this URL");
}

        fs.readFileAtURL(inputURL, start, end, new Filesystem.ReadFileCallback() {
            public void handleData(InputStream inputStream, String contentType) {
        		try {
                    ByteArrayOutputStream os = new ByteArrayOutputStream();
                    final int BUFFER_SIZE = 8192;
                    byte[] buffer = new byte[BUFFER_SIZE];

                    for (;;) {
                        int bytesRead = inputStream.read(buffer, 0, BUFFER_SIZE);

                        if (bytesRead <= 0) {
                            break;
                        }
                        os.write(buffer, 0, bytesRead);
                    }

        			PluginResult result;
        			switch (resultType) {
        			case PluginResult.MESSAGE_TYPE_STRING:
                        result = new PluginResult(PluginResult.Status.OK, os.toString(encoding));
        				break;

Ionic info: (run ionic info from a terminal/cmd prompt and paste output below):

` Ionic CLI : 5.4.5
Ionic Framework : @ionic/angular 4.11.7
@angular-devkit/build-angular : 0.803.21
@angular-devkit/schematics : 8.3.21
@angular/cli : 8.3.21
@ionic/angular-toolkit : 2.1.1

Capacitor:

Capacitor CLI : 1.4.0
@capacitor/core : 1.4.0

Cordova:

Cordova CLI : 9.0.0 ([email protected])
Cordova Platforms : android 8.1.0, browser 6.0.0
Cordova Plugins : cordova-plugin-file 6.0.2

Utility:

cordova-res : not installed
native-run : 0.2.9

System:

Android SDK Tools : 26.1.1
NodeJS : v13.0.1
npm : 6.13.2
OS : Windows 10

@NajiLouisAct
Copy link

Same issue.
Did you find any solution ?

@vvche69
Copy link
Author

vvche69 commented Jan 13, 2020

Same issue.
Did you find any solution ?

Not yet, unfortunately...

@NajiLouisAct
Copy link

I tried the solution mentioned in [https://forum.ionicframework.com/t/file-readastext-never-resolves/85375/2]
So just put polyfills.js before cordova.js in your index.html

@johandz
Copy link

johandz commented Jan 14, 2020

There's no polyfill.js or cordova.js in my src/index.html. Where is this file exactly?

@psanty
Copy link

psanty commented Feb 3, 2020

Hi there, having the same issue, also combining ionic native file with capacitor because capacitor does not yet support writing blobs.
I'm thinking of using it for just this reason, although it would be a very unclean solution.

@NajiLouisAct
Copy link

There's no polyfill.js or cordova.js in my src/index.html. Where is this file exactly?

I'm using ionic v3 that why am able to change the order of polyfills.js inside my index.html.
In your v4 app I guess you can update it inside the angular.json file (but am not sure 😕)

@psanty
Copy link

psanty commented Feb 5, 2020

Sadly no, the only way to change the file order would probably be to use a custom webpack build, but I don't really have time to learn how to do that. I decided to use Filesystem.readFile for this, which worked for android. However, on iOS, I have a problem.
Cordova's dataDirectory and Capacitor's FilesystemDirectory.DATA are apparently two different locations on ios. I have no simple way to check what the actual path of the capacitor variant is because there's no way to log it and it isn't in the docs. This is a real dilemma for me right now and any workaround would be highly appreciated.

@elenche
Copy link

elenche commented Mar 9, 2020

Still very relevant.
My specific issue is about readAsBinaryString(). As a workaround on Android I've used a similar approach to @psanty's:

  • Store binary file with file.writeFile()
  • Read binary file with Capacitor's Filesystem.readFile() without passing the encoding parameter in order to read data as binary and receive a base64-encoded string
  • Decode base64-encoded string into binary string with atob()

@psanty
Copy link

psanty commented Mar 9, 2020

Hi everyone,
thanks @elenche for the tip, that might have also worked - but I actually managed to solve this! I went on with the workaround, using cordova file to write and capacitor FileSystem to read. What I discovered was that there actually was a way to find out what FilesystemDirectory.DATA points to: the Filesystem.getUri function. I had simply missed it becaus the capacitor doc's top nav had blocked my view. It turns out that FilesystemDirectory.DATA points to the /documents folder on ios, not the data directory. This may be a bug.
So I just wrote the files into that directory and then was able to read it out without a problem.
Hope this helps!

@maximedasilva
Copy link

maximedasilva commented May 27, 2020

Hi everyone,
I had the same problem with another method of this plugin: readAsBinaryString with Capacitor 2.1.0 and ionic 5.22.0.

Following the @NajiLouisAct solution, I simply moved up Pollyfills before index.html on build options inside the angular.json.
Before:

"options": {
            "aot": true,
            "preserveSymlinks": true,
            "outputPath": "dist/project",
            "index": "project/src/index.html",
            "main": "project/src/main.ts",
            "polyfills": "project/src/polyfills.ts",
[...]

After:

 "options": {
            "aot": true,
            "preserveSymlinks": true,
            "outputPath": "dist/project",
            "polyfills": "project/src/polyfills.ts",
            "index": "project/src/index.html",
            "main": "project/src/main.ts",

and it did the trick for me !
Hope this will works for you too.

@greek-stasia
Copy link

greek-stasia commented Jul 17, 2020

I have the same problem. The above did not work for me. I have Ionic 5. This is the only way I've been able to get it to work:

readText(){
      let res;
      res = this.file.readAsText(this.fileDir, this.filename)
      .then((resp) => {
        return resp;
      }).catch((err) =>
      {
        return "";
      });
      return res;
  };

and then:

let text = "";
this.readText()
    .then((value) => {
            this.text = value;
      })
     .catch((err) => {
           console.log(err);
      });

very weird but it worked for me.

@Exocomp
Copy link

Exocomp commented Jul 24, 2020

On the Capacitor and Ionic 5, sadly none of the work arounds mentioned here worked for me with readAsDataURL.

@vvche69
Copy link
Author

vvche69 commented Aug 10, 2020

Suddenly this function started to work on some Android10 devices...

@n0hkie
Copy link

n0hkie commented Sep 4, 2020

Hi not working on android 10 but working on android 7.1, any solution?

@DjulLau
Copy link

DjulLau commented Sep 21, 2020

Same here with latest versions: Ionic 5, Capacitor 2.4, Cordova File 6.0, Ionic Native File 5.28 :/

@gnesher
Copy link

gnesher commented Oct 26, 2020

Making a local AJAX call seems to be the simplest solution. You can use Capacitor.convertFileSrc which turns the path to a URI you can use. Turns out something like this:

const path = Capacitor.convertFileSrc(file.uri);
const response = await fetch(path);
const rawData = await response.json();

Tested on files roughly 5MB in size, works fine
Hope this helps someone

@brospars
Copy link

brospars commented Nov 4, 2020

This seems related to #978, #505 and ionic-team/capacitor#1564

Why a 4 years old issue like this with a simple fix still isn't dealt with ?

Is the fix sustainable ?

@polnikale
Copy link

It seems like I was able to find the source of the issue.
The ionic-native/file API looks at the fileReader.on*, meanwhile, the file reader itself, when tries to deal with the file, works with the filereader._realReader. One thing is that you also need to change result to _result and error to _error for some unknown reason. I've really spent a ton of time looking into this. I'm currently going to apply a patch to see how it goes, but if any of you feel like it could be a real fix, I would be glad to submit a PR.
That's the code you'd like to have in a very weird location(@ionic-native/file/__ivy_ngcc/ngx/index.js) in the File.prototype.readFile

                reader._realReader.onloadend = function () {
                    if (reader._result != null) {
                        resolve(reader._result);
                    }
                    else if (reader._error != null) {
                        reject(reader._error);
                    }
                    else {
                        reject({ code: null, message: 'READER_ONLOADEND_ERR' });
                    }
                };

@BanTheRewind
Copy link

Using a combination of...

  • Putting polyfills.js before cordova.js in index.html
  • Creating reader from *._realReader or new FileReader based on file instanceof Blob
  • Listening on *._realReader when new FileReader was used

...finally cracked it for me. Working on both Android and iOS. Putting six hours into this solution sounds like I actually didn't have it as bad as some, so thank you all!

@AmanSingh23
Copy link

Any updates or any solution for this?

@muuvmuuv
Copy link

Facing the same with dataDirectory. Seems like it is not set or does it need to be anyway?

@github-actions
Copy link

There has been no recent activity and this issue has been marked inactive.

@shapebuster
Copy link

shapebuster commented Oct 19, 2021

Thanks, pasting this code over the original onloaded function worked for me

It seems like I was able to find the source of the issue.

                reader._realReader.onloadend = function () {
                    if (reader._result != null) {
                        resolve(reader._result);
                    }
                    else if (reader._error != null) {
                        reject(reader._error);
                    }
                    else {
                        reject({ code: null, message: 'READER_ONLOADEND_ERR' });
                    }
                };

@medbz
Copy link

medbz commented Oct 24, 2021

Hello guys, if anyone is still facing this issue, I suggest a workaround solution.
So It's about reading the file using httpClient and ionic webview .

  loadFiles(path,filename) {
    let converted = this.webview.convertFileSrc(this.file.dataDirectory + filename)
    this.downloadFile(converted,filename)
  }

downloadFile(route: string, filename: string = null): void{
   this.http.get(route ,{ responseType: 'blob' as 'json'}).subscribe(
      (response: any) =>{
         // uploads the file , in my case to AWS s3
          this.upload(response,filename,'')     
      }
  )
}

@brospars
Copy link

Yes but it does not work in development mode (live-reload) since you get a cross origin error

@luqmanyusof
Copy link

I endup using "Capacitor/Filesystem" library to read the file that was written by using "@ionic-native/file/ngx".

@github-actions
Copy link

There has been no recent activity and this issue has been marked inactive.

@saggio89
Copy link

saggio89 commented Nov 14, 2022

We randomly started experiencing this issue in Nov 2022 with the readAsArrayBuffer() function... not sure what changed or why it started happening. I followed advice in this thread & changed my .onloadend function to look like this and it seemed to fix it for me. Thanks everyone on this thread....

                reader._realReader.onloadend = () => {
                    if (reader._result != null) {
                        resolve(reader._result);
                    }
                    else if (reader._error != null) {
                        reject(reader._error);
                    }
                    else {
                        reject({ code: null, message: 'READER_ONLOADEND_ERR' });
                    }
                };```

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests