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

filewriter always throws error code 2 #577

Closed
NAMUS09 opened this issue Jul 11, 2023 · 16 comments
Closed

filewriter always throws error code 2 #577

NAMUS09 opened this issue Jul 11, 2023 · 16 comments
Labels
Milestone

Comments

@NAMUS09
Copy link

NAMUS09 commented Jul 11, 2023

Bug Report

when writing file in this path " window.cordova.file.externalRootDirectory + 'Download' " always throws error in filewriter.onerror. Issue not there in cordova v11, cordova-android v11 and cordova-plugin-file v7.

Problem

What is expected to happen?

It should write the file and return success.

What does actually happen?

throws error code 2

Information

tying to save pdf in download folder. I tried updating the plugin file to v8. Still issue is there.

Command or Code

private writeToFile(pdfData: BlobPart, fileName: string): Promise {
return new Promise((resolve, reject) => {
var storageLocation = '';

  switch (window.cordova.platformId) {
    case 'android':
      storageLocation = window.cordova.file.externalRootDirectory + 'Download';
      break;

    case 'ios':
      storageLocation = window.cordova.file.documentsDirectory;
      break;
  }

  var folderPath = storageLocation;
  console.log(folderPath);

  window.resolveLocalFileSystemURL(
    folderPath,
    (directoryEntry: any) => {
      directoryEntry.getFile(
        fileName,
        { create: true },
        (fileEntry: any) => {
          fileEntry.createWriter(
            (fileWriter: any) => {
              fileWriter.onwriteend = () => {
                resolve('success');
                console.log('File written successfully.');
              };

              fileWriter.onerror = (error: any) => {
                console.log('Error writing file: ');
                reject(error);
              };

              const dataObj = new Blob([pdfData], { type: 'application/pdf' });
              console.log(dataObj);

              fileWriter.write(dataObj);
            },
            () => {
              reject('Error creating file writer.');
              console.log('Error creating file writer.');
            }
          );
        },
        () => {
          reject('Error getting file entry.');
          console.log('Error getting file entry.');
        }
      );
    },
    () => {
      reject('Error resolving file system URL.');
      console.log('Error resolving file system URL.');
    }
  );
});

}

Environment, Platform, Device

while targeting to api 33 issue occurs. There is no issue in cordova v11 ,cordova-android v11 and cordova-plugin-file v7 targeting to api 32.

Version information

Cordova CLI v12,
Cordova-android v12
Cordova v8, v7 (both tested)

Checklist

  • [x ] I searched for existing GitHub issues
  • [ x] I updated all Cordova tooling to most recent version
  • [ x] I included all the necessary information above
@EYALIN
Copy link
Contributor

EYALIN commented Jul 11, 2023

@NAMUS09 I added a PR that will solve it
#581

@breautek can you please merge it?

@MauriceFrank
Copy link
Contributor

file.removeFile(dir,name) throws permission error:

FileError {code: 6, message: 'NO_MODIFICATION_ALLOWED_ERR'}
code
:
6
message
:
"NO_MODIFICATION_ALLOWED_ERR"

Is this fixable with the READ_MEDIA_IMAGES permission somehow?
I tried your current Master @EYALIN in hope that it fixes removing files from external data directory also.

I Can access files with the READ-permission but it seems like removing and writing files is a problem on Android 13.

Any ideas? I would be glad for any help.

Thank you!

@breautek
Copy link
Contributor

I Can access files with the READ-permission but it seems like removing and writing files is a problem on Android 13.

PR #581 really only fixes the plugin by removing the request attempt on API 33+ for the obsolete WRITE_EXTERNAL_STORAGE permission which on API 33 is an auto rejection.

It assumes true which is not necessarily the case. With the scoped storage system that Android has, you no longer need permission to write to external storage, however cannot modify files owned by other apps, which is not possible at all using any file-system APIs. There is no permission grant that the app itself can request to gain permission to modify other app's files.

Instead, apps is suppose to use the MediaStore API which allows the app to request permission to write to a specific file (assuming that the owning app has a content provider implemented), allowing a temporary write grant to your app owned by a third-party app.

I've wrote a pretty large comment elsewhere that explains the nuances with interfacing the file plugin with the MediaStore API. TL;DR; I don't think it's feasible and if you require write access to third-party files, then you'll probably need a separate plugin that interfaces with the MediaStore API.

@EYALIN
Copy link
Contributor

EYALIN commented Jul 14, 2023

@breautek thanks for all your help. I see that you are very active in a few plugins. highly appreciate!

@MauriceFrank
Copy link
Contributor

MauriceFrank commented Jul 14, 2023

I Can access files with the READ-permission but it seems like removing and writing files is a problem on Android 13.

PR #581 really only fixes the plugin by removing the request attempt on API 33+ for the obsolete WRITE_EXTERNAL_STORAGE permission which on API 33 is an auto rejection.

It assumes true which is not necessarily the case. With the scoped storage system that Android has, you no longer need permission to write to external storage, however cannot modify files owned by other apps, which is not possible at all using any file-system APIs. There is no permission grant that the app itself can request to gain permission to modify other app's files.

Instead, apps is suppose to use the MediaStore API which allows the app to request permission to write to a specific file (assuming that the owning app has a content provider implemented), allowing a temporary write grant to your app owned by a third-party app.

I've wrote a pretty large comment elsewhere that explains the nuances with interfacing the file plugin with the MediaStore API. TL;DR; I don't think it's feasible and if you require write access to third-party files, then you'll probably need a separate plugin that interfaces with the MediaStore API.

Thanks for the detailed clarifications! I was part of this Android 13 conversation here too some weeks ago when I created a PR to fix Read permissions. This solved it at least for reading images in the gallery for me. I saw that it got merged. Still I noticed it is not the full solution and at this time I knew you were all waiting for cordova-android 12 which is finally here! I Just saw today that there is cordova-android 12 and the update on this plugin and im happy that it is still maintained by the community and you.

Unfortunately as I see now, Android is only allowing read-permissions to external storage with the normal file-system as you described in your post.
So I really have to try alternative cordova plugisn using the MediaStore. I did not have success in the past with some of them but there might be updates and since the cordova-android 12 release, it might have changed too,

I will give this plugin another try https://github.com/apache/cordova-plugin-file/issues/cordova-plugin-saf-mediastore.
At least only for the parts, where I have to remove images from the gallery.

Thank you for all the research!

@breautek
Copy link
Contributor

I still need to do more research on the implications on removing support for external storage when it comes to other plugins like the camera plugin that kinda uses external storage to some fashion (not that the file plugin works well to begin with in this area) but I feel like removing external support on the file plugin is going to end up being the best path forward, which leaves the file plugin purely for internal storage only, which still has a fully functional filesystem API on Android. For use cases involving external storage, a different plugin will work much better, since it can have an API more tailored to the MediaStore interface, like the cordova-plugin-saf-mediastore for example.

Once I understand what kind of problems will arise to dependent Apache plugins if the external storage support is removed, I'll open a topic on the Dev Mailing List for a more formal community vote on the subject, since it will be a fairly large change.

Only thing is... I don't use any external storage stuff at my day job, so I don't have much of an excuse to do allocate work time on this. So this is strictly volunteer time on my part, and well lately I've been pretty burnt out.

@Krantikc
Copy link

Even I am facing similar issue. It throws error code 2 while downloading the image/pdf file. It is failing while executing getDirectory command from DirectoryEntry.js (cordova-plugin-file) when targeted android API level to 33.
exec(win, fail, 'File', 'getDirectory', [this.toInternalURL(), path, options]).

I have also included required permissions in config.xml

<config-file parent="/manifest" target="app/src/main/AndroidManifest.xml" mode="merge">
    <uses-permission android:name="android.permission.READ_MEDIA_IMAGES"/>
    <uses-permission android:name="android.permission.READ_MEDIA_VIDEO"/>
    <uses-permission android:name="android.permission.READ_MEDIA_AUDIO"/>
</config-file>

Any solutions for this is appreciated. Thanks in advance !!

@EYALIN
Copy link
Contributor

EYALIN commented Jul 16, 2023

@Krantikc it is not enough.
use my PR, it will solve your issue
#581

@Krantikc
Copy link

@Krantikc it is not enough. use my PR, it will solve your issue #581

@EYALIN Thanks for suggestion, I have already tried your forked repo, but still no luck. I am wondering if I have to make any other modifications.

@EYALIN
Copy link
Contributor

EYALIN commented Jul 16, 2023

@Krantikc try to add logs and to see in log cat.
from what i see, you will arrive here:

private boolean hasReadPermission() {
        if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
            return PermissionHelper.hasPermission(this, Manifest.permission.READ_MEDIA_IMAGES) 
            && PermissionHelper.hasPermission(this, Manifest.permission.READ_MEDIA_VIDEO)
            && PermissionHelper.hasPermission(this, Manifest.permission.READ_MEDIA_AUDIO);
          } else {
            return PermissionHelper.hasPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE);
          }
    }

or here:

  private boolean hasWritePermission() {
          if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
                return true;
              } else {
                return PermissionHelper.hasPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE);
              }
    }

please make sure you have those changes (for the write permission).

try remove ing the plugin and add it from my fork, i tried on few devices android 10-13 and all works.
cordova plugin remove cordova-plugin-file
cordova plugin add https://github.com/EYALIN/cordova-plugin-file.git

@Krantikc
Copy link

@Krantikc try to add logs and to see in log cat. from what i see, you will arrive here:

private boolean hasReadPermission() {
        if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
            return PermissionHelper.hasPermission(this, Manifest.permission.READ_MEDIA_IMAGES) 
            && PermissionHelper.hasPermission(this, Manifest.permission.READ_MEDIA_VIDEO)
            && PermissionHelper.hasPermission(this, Manifest.permission.READ_MEDIA_AUDIO);
          } else {
            return PermissionHelper.hasPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE);
          }
    }

or here:

  private boolean hasWritePermission() {
          if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
                return true;
              } else {
                return PermissionHelper.hasPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE);
              }
    }

please make sure you have those changes (for the write permission).

try remove ing the plugin and add it from my fork, i tried on few devices android 10-13 and all works. cordova plugin remove cordova-plugin-file cordova plugin add https://github.com/EYALIN/cordova-plugin-file.git

@EYALIN Thanks a lot for quick reply, it's working fine. My bad, after importing your forked repo, issue was resolved, but file was not opening up because of cordova-plugin-file-opener2 plugin. I was getting NOT_FOUND error, as there was mismatch in file protocol, whose way handling has been changed as part of cordova-plugin-file-opener2@7.0.0.

Thanks Again !! :)

@EYALIN
Copy link
Contributor

EYALIN commented Jul 17, 2023

@NAMUS09 @Krantikc no problem :-)
regarding the file opener, so you can use my plugin which I maintain and update all the time.
https://github.com/EYALIN/community-cordova-plugin-file-opener

generally, you can use all my community Cordova plugins, I maintain them each time there is an update and expand some of them to support more features.
here you can see all my Cordova plugins (suggest you move to my plugin in case you are using not maintained one):
https://github.com/EYALIN?tab=repositories&q=community&type=&language=&sort=

@appidemic1
Copy link

appidemic1 commented Aug 23, 2023

@Krantikc try to add logs and to see in log cat. from what i see, you will arrive here:

private boolean hasReadPermission() {
        if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
            return PermissionHelper.hasPermission(this, Manifest.permission.READ_MEDIA_IMAGES) 
            && PermissionHelper.hasPermission(this, Manifest.permission.READ_MEDIA_VIDEO)
            && PermissionHelper.hasPermission(this, Manifest.permission.READ_MEDIA_AUDIO);
          } else {
            return PermissionHelper.hasPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE);
          }
    }

or here:

  private boolean hasWritePermission() {
          if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
                return true;
              } else {
                return PermissionHelper.hasPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE);
              }
    }

please make sure you have those changes (for the write permission).

try remove ing the plugin and add it from my fork, i tried on few devices android 10-13 and all works. cordova plugin remove cordova-plugin-file cordova plugin add https://github.com/EYALIN/cordova-plugin-file.git

Thanks! @EYALIN https://github.com/EYALIN/cordova-plugin-file.git worked when i tried to write to cordova.file.externalRootDirectory + "Pictures/test/"

But i get error 2 (security error) when i try to read the files and list them cordova.file.externalRootDirectory + "Pictures/test/"

Any help would be great

@ssnctracweb
Copy link

This issue is major blocker for us as our apps are build using CI/CD pipelines and there's no way to patch it in run time builds.
So any estimate by when this issue will be fixed for android version 13 and above ?

@breautek
Copy link
Contributor

So any estimate by when this issue will be fixed for android version 13 and above ?

Because Apache Cordova is entirely driven by volunteers providing contributions on their free time, we can't really give any meaningful estimates. PR #581 requires changes and currently we are giving time for the OP to make those changes. If the OP happens to make those changes it may move quicker, otherwise someone will have to (volunteerly) pull the and rebase the fork and make any required changes necessary.

Should someone take the fork and rebase it, it's important to rebase it in such a way that the original author commit is left in tact so that credit is provided to the original author.

@erisu
Copy link
Member

erisu commented Oct 17, 2023

Should be resolved by #608

@erisu erisu closed this as completed Oct 17, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

8 participants