apache / cordova-plugin-file

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

Cordova Plugin File doesn't work on Android 13 #610

Closed JMrJImmy closed 6 months ago

JMrJImmy commented 7 months ago

Discussed in https://github.com/apache/cordova/discussions/424

Originally posted by **leonelgregioauler** July 10, 2023 Good morning! What permission should I add to be able to write a .CSV file in the "Documents" folder ? I've tried all the permissions below. ![image](https://github.com/apache/cordova/assets/12154804/e51043b9-e57d-4353-a53d-8320115d9a31) I got this error: "**onErrorGetDir**". The folder is: **file:///storage/emulated/0/** ![image](https://github.com/apache/cordova/assets/12154804/96fb28cc-aa88-436e-8124-c8de11edffb6) Remember, this works fine on others versions, like Android 11 or below. Android 12 I haven't tested yet, but it seems to work ! Thank you for now !
breautek commented 7 months ago

Access to externalRootDirectory is limited under Android's scoped storage rules, though I think resolveLocalFileSystemURL should still "work", but what you do on it might be limited. I don't believe you can create new directories in the root external directory anymore. You don't tell us what the n error function is actually attached to, or what the actual error is.

If you're trying to resolve to the Documents directory, that directory is a standard directory on android, therefore it should be safe to do something like

const documentsDir = cordova.file.externalRootDirectory + "Documents";
window.resolveLocalFileSystemURL(documentsDir, function (dirEntry) {

}

What permission should I add to be able to write a .CSV file in the "Documents" folder ?

Now this largely depends on whether your app "owns" the csv file. The short answer is, no permission is needed, or there is no permission available and what you're attempting to do is now impossible with the filesystem.

Under scoped storage rules, no permissions are needed to read/write to files that your files owns/created.

If the file is owned by another application, then you cannot write to that file using filesystem. Android literally does not support overwriting other apps files directly through the filesystem. Additionally for third-party files, Android only supports reading Images, Videos, and Audio files, but not "Document" files like a CSV file, with the appropriate permissions (READ_EXTERNAL STORAGE for API 32 and earlier, or READ_MEDIA_IMAGE, READ_MEDIA_VIDEO, READ_MEDIA_AUDIO for API 33 and later).

If you wish to write a third-party file, a media store plugin that interfaces with the native MediaStore API must be used, which unlike the filesystem api that this plugin implements, has support to get temporary permission to read/write to a third-party file.

Also note that specifically on API 29 (Android 10) Android does not support the external filesystem at all via filesystem APIs. See more details.

JMrJImmy commented 6 months ago

I am using the internal storage. The photo is in the applications cache. so the above is irrelevant. Just want to know what to do to a fileURI that is returned from your photo plugin, in order to get a file entry object getfile(fileURI... no longer excepts it ... it is FILE NOT FOUND . How do I format the returned fileURI to get it in the appropriate format for getfile() operation??

breautek commented 6 months ago

I am using the internal storage. The photo is in the applications cache

In the details provided in your original post, it shows you were using cordova.file.externalRootDirectory which isn't internal storage.

If you're using internal storage then please share the relevant code, or share a sample reproduction app that reproduces your issue.

JMrJImmy commented 6 months ago

Function Mimageonclick() options={quality : 75, correctOrientation: True, allowEdit : False, _ destinationType : 1}
navigator.camera.getPicture(onPictureReturned, onPictureError, options) End Function Function onPictureReturned(fileURI) varLastSlash = InStrR(fileURI, "/", 0) varfileURI = fileURI varCacheSubfolder = InStr(1, fileURI, "cache", 0) 'NewDirectory = Left(varfileURI, varCacheSubfolder - 1) & "/data/data/com.nsbasic.Vantastic/files/" varROOT = InStr(1,fileURI, "Android",0) PhotoName = Mid(fileURI, varROOT) 'The PhoneGap root file name varDate = FormatDateTime(Now, vbYYYYhyphenMMhyphenDD) rowindex = $("#GridQuest").jqxGrid("getselectedrowindex") 'gSelectedCategoryNumber = $("#GridQuest").jqxGrid("getcellvalue", rowindex, "SURVEY_NO") varQuestionNO = $("#GridQuest").jqxGrid("getcellvalue", rowindex, "QUESTION_NO") If Day(varDate) < 10 Then PhotoDay = "0" & CStr(Day(varDate)) Else PhotoDay = CStr(Day(varDate)) End If If Month(varDate) <10 Then PhotoMonth = "0" & CStr(Month(varDate)) Else PhotoMonth = CStr(Month(varDate)) End If varPicture = Trim(gSelectedBroker) & "-" & Trim(gSelectedCategoryNumber) & "-" & Trim(gSelectedChainNumber) & "-" & Trim(gSelectedStoreNumber) & "-" & CStr(Year(varDate)) & PhotoMonth & PhotoDay & "-" & Trim(varQuestionNO) varPicture = varPicture & ".jpg" Call MovePicS() End Function Function onPictureError(message) MsgBox "Failed because " & message End Function Function MovePicS() gfileSystem.root.getFile(PhotoName, {create: False}, gotFileEntryS, fail2) End Function Function gotFileEntryS(fe) FileEntry = fe FileEntry.moveTo(gdataDir, varPicture, SubSuccess2, fail3) End Function Function SubSuccess2(entry) 'MsgBox "Successfully Moved file from Cache:" & vbCRLF & PhotoName & vbCRLF & "To Photos: " & varPicture NSB.MsgBox("Press [SAVE ANSWER] to Complete Process...",0,"Photo Successfull") End Function Function fail(error) MsgBox "Error Getting File System: " + error.code End Function Function fail2(error) MsgBox "Error getting: " + error.code + " --" + PhotoName End Function Function fail3(error) MsgBox "Error writing: " + error.code + " -- " + varPicture End Function

breautek commented 6 months ago

I don't know if there is a language barrier but the code doesn't appear to be at all related to the original issue.

First you were asking

What permission should I add to be able to write a .CSV file in the "Documents" folder ?

Then you're showing camera usage, I don't understand how this relates to the CSV file. This thread has kind of gone off the rails so I'm closing it.

I'll say that writing documents to the Documents folder is not possible under android scoped storage system because it forbids write access to file APIs. To do this action, it needs to go through the media store. There are third-party plugins that interfaces with the media store to do this. More info can be found here