apache / cordova-plugin-file

Apache Cordova File Plugin
https://cordova.apache.org/
Apache License 2.0
742 stars 762 forks source link

FileReader.readAs*(file) returns null onloadend #348

Open eduardoewgo opened 5 years ago

eduardoewgo commented 5 years ago

Bug Report

FileReader.readAs*(file) returns null in this.result and has FileError with code: 1 (not found) with video file.

Problem

The exact same code works fine on iOS, however I can't get it to work on Android.

Information

The command below will make it easier to understand what I'm trying to do.

Code

This is already set

<meta http-equiv="Content-Security-Policy" content="default-src * 'self' 'unsafe-inline' 'unsafe-eval' data: gap:">

Actual code

async captureVideoErrorOnAndroid() {
        const printError = (e) => console.log(e);
        navigator.device.capture.captureVideo(function(mediaFiles) {
            const mediaFile = mediaFiles[0];
            console.log(`capture: Got media file: ${JSON.stringify(mediaFile)}`);

            // note, on iOS I have to use media.localURL rather than media.fullPath
            // I also tried media.localURL on Android, but the results are the same 
            window.resolveLocalFileSystemURL(mediaFile.fullPath, function(fileEntry){
                console.log(`capture: Got fileEntry: ${JSON.stringify(fileEntry)}`);
                fileEntry.file(function (file) {
                    console.log(`capture: Got file: ${JSON.stringify(file)} `);
                    const reader = new FileReader();

                    reader.onloadend = function() {
                        console.log(`capture: result: ${this.result}, error: ${JSON.stringify(this.error)}`);
                    };
                    reader.readAsArrayBuffer(file);

                }, printError);
            }, printError)
        }, printError, {limit: 1, quality: 0, duration: 10})
    }

Output for iOS (working just fine)

capture: Got media file: {"name":"58568874201__E85C0792-08F4-4652-9776-9E0815101786.MOV","localURL":"cdvfile://localhost/temporary/58568874201__E85C0792-08F4-4652-9776-9E0815101786.MOV","type":"video/quicktime","lastModified":null,"lastModifiedDate":1563995943708.5723,"size":87457,"start":0,"end":0,"fullPath":"/private/var/mobile/Containers/Data/Application/B8A6D1DC-72B7-4F8C-A106-A137E358E0AA/tmp/58568874201__E85C0792-08F4-4652-9776-9E0815101786.MOV"} (cordova.js, line 1732)
capture: Got fileEntry: {"isFile":true,"isDirectory":false,"name":"58568874201__E85C0792-08F4-4652-9776-9E0815101786.MOV","fullPath":"/58568874201__E85C0792-08F4-4652-9776-9E0815101786.MOV","filesystem":"<FileSystem: temporary>","nativeURL":"file:///var/mobile/Containers/Data/Application/B8A6D1DC-72B7-4F8C-A106-A137E358E0AA/tmp/58568874201__E85C0792-08F4-4652-9776-9E0815101786.MOV"} (cordova.js, line 1732)
capture: Got file: {"name":"58568874201__E85C0792-08F4-4652-9776-9E0815101786.MOV","localURL":"cdvfile://localhost/temporary/58568874201__E85C0792-08F4-4652-9776-9E0815101786.MOV","type":"video/quicktime","lastModified":1563995943708.5723,"lastModifiedDate":1563995943708.5723,"size":87457,"start":0,"end":87457}  (cordova.js, line 1732)
capture: result: [object ArrayBuffer], error: null (cordova.js, line 1732)

Output for Android (with result being null)

capture: Got media file: {"name":"VID_20190725_030555.3gp","localURL":"cdvfile://localhost/sdcard/DCIM/Camera/VID_20190725_030555.3gp","type":"video/3gpp","lastModified":null,"lastModifiedDate":1563995159000,"size":75157,"start":0,"end":0,"fullPath":"file:///storage/emulated/0/DCIM/Camera/VID_20190725_030555.3gp"}
capture: Got fileEntry: {"isFile":true,"isDirectory":false,"name":"VID_20190725_030555.3gp","fullPath":"/DCIM/Camera/VID_20190725_030555.3gp","filesystem":"<FileSystem: sdcard>","nativeURL":"file:///storage/emulated/0/DCIM/Camera/VID_20190725_030555.3gp"}
capture: Got file: {"name":"VID_20190725_030555.3gp","localURL":"cdvfile://localhost/sdcard/DCIM/Camera/VID_20190725_030555.3gp","type":"video/3gpp","lastModified":1563995159000,"lastModifiedDate":1563995159000,"size":75157,"start":0,"end":75157} 
capture: result: null, error: {"code":1}

Platform

Android 8.0.0

Version information

Cordova 8.1.2 cordova-plugin-file 6.0.2

Checklist

phiferd commented 5 years ago

This may resolve https://github.com/apache/cordova-plugin-media-capture/issues/135

ryandsjoquist commented 5 years ago

I second this issue. The solution provided in #135 doesn't seem to fix the read file issue.

eduardoewgo commented 5 years ago

I created a sample app logging the issue here.

phiferd commented 5 years ago

@janpio any chance you can take a quick look at the repo linked by @eduardoewgo (sorry, I just grabbed your username from the contributors page)? We're trying to understand if the issue is with cordova-plugin-media-capture, cordova-plugin-file, or something else. We've spent a good deal of time attempting to resolve this on our own and we're not sure what the issue could be.

If there's anything we can do to more clearly define the issue, please let me know. Or, if you think there's another person that might be able to help move this forward, would you mention them here?

phiferd commented 5 years ago

Never mind, looks like the issue was related to the way permissions are requested in the capture media plugin. In captureVideo, it didn't ask for the permissions needed to actually get the contents of the file after capturing it.

ryandsjoquist commented 5 years ago

What would be the additional permissions needed?

phiferd commented 5 years ago

Here's a link to the PR: https://github.com/apache/cordova-plugin-media-capture/pull/147/files

The issue was that the READ_EXTERNAL_STORAGE permission was not requested. Maybe there's another way to do it, but the update I made to captureVideo seems to be in line with the way captureImage works.

ryandsjoquist commented 5 years ago

Thanks so much for finding that!

breautek commented 5 years ago

Potentially related to https://github.com/apache/cordova-plugin-file/issues/350 (both dealing with sdcard external storage)

milanzivic commented 5 years ago

Any updates on this?

felipecaparelli commented 4 years ago

I am just trying to use it (with Ionic) to get files from any Android folders (WhatsApp, Documents, etc), but it always returns null, even using other methods like readAsText, readAsDataURL or the readAsArrayBuffer. Follow my config:

Ionic:

Ionic CLI : 5.4.15 Ionic Framework : @ionic/angular 5.2.2 @angular-devkit/build-angular : 0.901.9 @angular-devkit/schematics : 9.1.9 @angular/cli : 9.1.9 @ionic/angular-toolkit : 2.2.0

Cordova:

Cordova CLI : 9.0.0 (cordova-lib@9.0.1) Cordova Platforms : android 8.1.0 Cordova Plugins : cordova-plugin-file: 6.0.2 cordova-plugin-file-opener2: 3.0.4 cordova-plugin-filechooser: 1.2.0 cordova-plugin-filepath": 1.5.8

The code that fails is:

    async openFiles() {
        this.fileChooser
            .open()
           .then(contentPath => {
             const that = this;
              this.filePath.resolveNativePath(contentPath).then(uri => {
              const lastSeparator = uri.lastIndexOf('/');
               const fileName = uri.substr(lastSeparator + 1);
               const sysPath = uri.substr(0, lastSeparator);
               that.file.readAsArrayBuffer(sysPath, fileName).then(buff => {
                // buff is always null
                const blob = new Blob([new Uint8Array(buff)], { type: 'image/jpg' });
                });
              });
            });
    }
olsbg commented 3 years ago

Adding ' android:requestLegacyExternalStorage="true"' to AndroidManifest.xml solves the problem.

Read more at https://developer.android.com/training/data-storage/use-cases.