I am trying to use the file picker to read and write text files.
I have a simple two file picker button setup, one for reading and one for writing.
These are my blocks.
I am trying to use this to read and write to the downloads folder of my Android 9 phone.
Here are my questions:
The reading part is fine, but I do not have access to a newer Android, so I would like to ask about the compatibility for newer operating systems. Can this code still read files from the downloads folder even if the file was put there by other apps? As far as I can tell from what I read, this should be fine, but I would like to double check.
The writing part starts fine, an empty file is created with the name I specify in the folder I choose, but I do not know how to write content in this file. The blocks I have give an error message when I click on the "write" button. This is the screenshot of the runtime error message I get (sorry, I tried to copy/paste it, but it did not work):
it looks like the file component is not able to write to a content uri like
content://com.android.providers.media.documents/document/document%3A10000233404
even if your app owns it
also why not keep it simple and just writing some text and store it directly into a file without first picking a new file?
you could try a relative path like /Documents/myFile.txt
as a side note my tests do not have been successful to convert the content uri from the file picker component to a filepath, neither with my file extension nor with the filetools extension from @vknow360 ... further investigation required...
EDIT: after thinking about it, it probably is not possible like this, because your app does not own that file? This is only a guess and I might be wrong. See also our storage access bible Some basics on Android storage system
EDIT2: my guess seems to be correct. After picking the previously stored textfile the content uri can be converted successfully into a filepath
EDIT3: Conclusion: you can pick a text file using the filepicker and read it and you can modify the text, but to store it again you have to use another filename. You can't overwrite the existing file if you do not own it. To do this you have to use SAF SAF: App Inventor implementation of Storage Access Framework
The reason I would like to do it using file picker is because I do not want to fix the directory to write into, I want to let the user choose.
I did some experimenting myself and the following code works for me on Android 9.
I would be interested to see if it works on newer Android versions or not.
If anyone would try, I would be interested to know the result.
Also, this method relies on the particular way my system gave the file picker uri. I am not sure how universal that is. I will try the file tools approach, too.
I do not think it is an accessibility issue, the empty file was created without problem.
this is not strange, because you do not own the file and therefore do not have write permission
try it with a file your app owns (i.e. pick a file you previously stored using the SaveFile method) to see the difference
As for using sharing, it is OK (and I know that these days most people use android devices continuously connected to the web), but if it can be done without it, then why not?
As for accessibility, from what I read in the documentations and in the guides, it should be OK to read files from the Downloads and Documents folder of android as long as the file scope is either legacy (which I use) or shared. The guides also say that if the file is created by the app (which is true in this case), then it is also writeable in these folders. Do I understand this correctly?
Can you please try my version that works for me on Android 9?
Here is the file: readWrite(1).aia (2.9 KB)
Yes, I know.
I am now trying on an Android 10, this is the newest I have.
On this one the uri is of a different format, I need to experiment with it to get the file path out of it.
It would be nice to know what the syntax of an uri for a file is, but I could not find any documentation about it.
Is there by chance a resource where I can find how the app inventor handles it in the "read file" block?
the uri decode method of web component is not able to convert a content uri into a filepath
try one of the file extensions
EDIT: also I think, it is not necessary to do the conversion. If you own the file it theoretically should be possible to store it using the content uri...
EDIT: no, I was wrong, it produces the same runtime error as in your first post of this thread
Yes, I read the guidance you linked and yes, I am planning to publish the app, so I do not want to ask for writing permission.
I do not want to use extensions, I want to keep it open to also publish on iOS
I will try to do some workaround and maybe use the file picker to find the directory and use the save option to create an empty file by the app before I fill it up with content.
If there is an example somewhere where I could see how to handle the file picker to look for directories, it would be helpful. Otherwise, I will need to experiment to see what the return value of the file picker is in the "select directory" mode.
It was new to me to hear that whatever the file picker creates from the app is not considered as created by the app, but that's life, I need to work around it.
This is why I was surprised that this is simply not the case. On my Android 9, using the uri did not work when I tried to write in the file (see my code in my starting post), but I could write in the file after conversion.
@ewpatton why is it not possible to use the file component and the SaveFile method together with a content uri provided by the file picker to store a file the app owns?
java.lang.IllegalArgumentException: URI scheme is not "file" at java.io.File.(File.java:429) at com.google.appinventor.components.runtime.util.ScopedFile.resolve(ScopedFile.java:65) at com.google.appinventor.components.runtime.File$9.processFile(File.java:628) at com.google.appinventor.components.runtime.util.SingleFileOperation.performOperation(SingleFileOperation.java:163) at com.google.appinventor.components.runtime.util.FileOperation.run(FileOperation.java:135) at java.lang.Thread.run(Thread.java:1119)
Thank you for trying. As I said, I will do some workaround, but in your example the program did not even get to the point to try to write in the file, because the split of the uri did not give the file name. On your system a different split would be needed, but it is not worth trying it, because first of all, I beleive you that it will not work, and secondly, if the uri is this different on every system, thne there is no point trying to find a universal way of getting a file path out of it (although the app inventor file reading block manages to do it).