How do I read/write to files on Mobile?
This lesson looks at how to create a file and then read/write data to it. This has many practical applications from storing user settings between sessions to high score tracking. The sample stack we'll build together will be configured for the iPhone, but these principles will work for all the other mobile platforms - and indeed for desktop, if you want to write one block of code that works across all platforms.
You can download the sample stack from this url: https://tinyurl.com/ya4dfo2j
Create our basic stack
1) Create a new stack by selecting 'New Mainstack' from the file menu
2) Open the 'Stack Inspector' from the menubar
3) I've given my stack a name and also a title
4) Set the with and height of the stack to 320 * 460 (iPhone)
5) Prevent the stack from being resized
Our stack is now setup and we can move one to coding this example.
Decide where we want to write our file
Mobile deployment imposes strict controls over what you can and cannot access. Each application in mobile is stored in its own 'sandbox' folder (referred to as the home folder.) An application is free to read and write files within this folder and its descendants, but is not allowed to access anything outside of this.
When an application is installed on a phone (or in the simulator) a number of initial folders are created for use by the application. You can locate the paths to these folders using the specialFolderPath() function.
iOS
- home – the (unique) folder containing the application bundle and its associated data and folders.
- documents – the folder in which the application should store any document data (this folder is backed up by iTunes on sync)
- library – the folder in which to store data of various types (backed up by iTunes on sync). In particular, data private to the application should be stored in a folder named with the app's bundle identifier inside the "library" folder
- cache – the folder in which the application should store any transient data that needs to be preserved between launches (this folder is not backed up by iTunes on sync)
- temporary – the folder in which the application should store any temporary data that is not needed between launches (this folder is not backed up by iTunes on sync)
- engine – the folder containing the built standalone engine (i.e. the bundle). This is useful for constructing paths to resources that have been copied into the bundle at build time.
- resources - Same as "engine".
Android
- documents – the folder where application-specific data can be placed (typically valuable)
- cache – the folder where transient application-specific data can be placed (typically not valuable)
- temporary – same as "cache"
- engine – the (virtual) folder containing the application's LiveCode engine and other resources that were copied into the application at build time
- resources – same as "engine".
- external documents – the folder on the primary shared/external storage device where application-specific data can be placed
- external cache – the folder on the primary shared/external storage device where transient application-specific data can be placed
- external temporary – same as "external cache"
Special Folder Path
You can test this entering the following line of LiveCode into the message box:
put specialFolderPath("documents")
I am on a Mac so this will return the full path to my default Documents folder:
/Users/ben/Documents
This will be different for every user. It will also change depending on your platform. LiveCode will return the default location for documents on whichever platform your application runs on.
Setting the folder using specialFolderPath
You can reference files in 1 of two ways:
1) Build the full path to your file every time you want to access it.
2) Set the folder that LiveCode performs all File and Folder operation within (default)
set the defaultFolder to specialFolderPath("documents")
Now, whenever you look to perform a Read or Write it will be done relative to the documents folder.
Setup our example
1) Drag on a new button. Name it "Write"
2) Drag on a second button. Name it "Read"
3) Drag on a label. Name it "write" and add some text to its contents
4) Drag on a label. Name it "read". I've added "No Data" to its contents just so that I can see it
Write our data to our file
Add the following script to the "Write" button:
on mouseUp
set the defaultFolder to specialFolderPath("documents")
put field "write" into URL ("file:test.txt")
end mouseUp
There are various ways to read and write to files in LiveCode. You can 'Open' a file and then 'Read' or 'Write'. For smaller files I prefer to use the URL command. It allows us to simply 'Put' our data in the file. If the file you specified doesn't exist LiveCode will create it for you.
If you are writing binary data to your files your should use "binfile:" instead of "file:" before your filename.
Get the data back out of our file
Add the following script to your "Read" button:
on mouseUp
set the defaultFolder to specialFolderPath("documents")
put URL ("file:test.txt") into field "read"
end mouseUp
Standalone Application Settings
When building a standalone that reads and write files there are some relevant settings.
iOS - The "File Sharing" requirement determines whether the Shared Files feature of iTunes is enabled for this application (UIFileSharingEnabled)
Android - Check the "Write external storage" application permission if your app will read or write files on external storage (e.g. an SD card)
Ezra Weinstein
Please see my forum post if you are trying to copy a file from your application folder to another folder for write purposes (in my case I was shipping a database file that I had to move from the app folder which is read only to the Documents folder on an Android device).
http://forums.runrev.com/viewtopic.php?f=53&t=7669
Mike
How do you list the file names in the documents folder?
Elanor Buchanan
Hi Mike
You can use the function "the files" to list the documents in the defaultFolder.
I hope that helps.
Elanor
Seppo Hietanen
Is it wise to try to change the old Mac rev- stacks for iPad, or rewrite them?
Tbill
For the iPad - I need to create a series of tables with relationships between these tables. How is this done and how can I ensure that these tables are backed up using the 'iCloud'.
Hanson Schmidt-Cornelius
Hi Tbil,
you could use SQLite to create a database on your iPad. Look at this lesson for further information on the topic: http://lessons.runrev.com/s/lessons/m/4069/l/30516-how-to-create-and-use-an-sqlite-database.
If you write files to the "documents" path, then the content is automatically backed up, as long as the user has set permissions for this to happen. Have a look at the dictionary entry on "specialFolderPath" for more information on this.
Kind Regards,
Hanson
Ty
I can use the specialfolderpath when designing the app on my mac, but when I run the simulator or move it to my phone, it can find the file. Do I use "documents" or home for writeable file with a Iphone app?
Thank you
Hanson Schmidt-Cornelius
Hi Ty,
it depends for what you want to use the files you are saving on your iOS device. If they are only temporary files that are used during the execution of the application, then use the "temporary" path.
If the files are to remain accessible for each launch of the application, then use the "documents" path. This is where application specific information is stored that is also backed up by iTunes.
Kind Regards,
Hanson
Martin Meili
Hi there,
Is it also possible to create a specific folder within the documents folder? No problem on the osx side, but does this also work on the iOs side?
Cheers Martin
Hanson Schmidt-Cornelius
Hi Martin,
sure, you can create folders within the documents folder. Have a look at the dictionary entry for: "create folder".
Kind Regards,
Hanson
jim1001
Article says: "Mobile deployment imposes strict controls over what you can and cannot access. Each application in mobile is stored in its own 'sandbox' folder (referred to as the home folder.) An application is free to read and write files within this folder and its descendants, but is not allowed to access anything outside of this."
Might be true for Apple devices but you can write files to the outside file system on Android.
Elanor Buchanan
Hi Jim, thanks for your comment.
This is a good point, I just wanted to add that if you want to write files outside the apk bundle on Android you need to ensure you check the "Write External Storage" option in the Android Standalone Application Settings.
Kind regards
Elanor
ewan richardson
In this example there are a couple of references....
set the defaultFolder to specialFolderPath("Documents")
set the defaultFolder to specialFolderPath("documents")
Is this case sensitive? if so which should be used "Documents" or "documents"?
Elanor Buchanan
Hi Ewan, it is not case sensitive but having checked the documentation for the specialFolderPath() function I would suggest using "documents".
I have update the text of the lesson for consistency, thank you for bringing this to our attention.
Kind regards
Elanor
Roberto
I am a little confused on where to save my app files on iOS.
as of now, saving to specialfolderpath("documents"), I can see them:
- form the iOS app
- in the iTunes shared file of the connected OSX
I was expecting that the "Files" folder that I see on the iOS screen was the one containing the files, but it is not. I tried specialfolderpath("library") & "/com.trevix.nameofmyapp/" but it is not the one.
So, I do I put a file into the "Files" folder of iOS (in a folder with the name of the app)?
Also, do I have to write the file in two different positions, if I want it to appear on the "Files" folder and in the iTunes Shared file?
Thanks
Panos Merakos
Hello Roberto,
Just note that by exposing your app’s files to the Files app, you’re also making those same files available to other apps. So I suggest first make sure that no commercial secrets or sensitive user data are stored there.
Regards,
Panos
--
Panos Merakos
Hello Roberto,
If you want the files to appear in the "Files" app too, you have to use specialfolderPath("documents") AND add these two key-value pairs in the plist:
...
<key> UIFileSharingEnabled</key>
<string>true</string>
<key>LSSupportsOpeningDocumentsInPlace</key>
<string>true</string>
...
Hope this helps.
Kind regards,
Panos
--
Roberto
As from the content here:
https://lessons.livecode.com/m/4069/l/1069016-associating-a-file-type-file-extension-with-an-lc-ios-app
I have found that in order to be accepted by Apple distribution and also to be able to directly install it in my iPhone, the application has to have the LSSupportsOpeningDocumentsInPlace set to FALSE (I have shared docs to true). Don't know why but doing it like this seems to work. Setting it to true on installing, crashes the standalone when double-clicking the doc
Matthias Rebbe
@Roberto
But are you able to read files in the documents folder using the iOS Files app when LSSupportsOpeningDocumentsInPlace is set to FALSE? I tried here and i am only able to access the files in my app's document folder using the iOS Files app when i set it to TRUE. But with set it to TRUE it seems no UrlWakeUp message is fired up.
Roberto
iOS 14.4.2
Yes. My app has its own custom documents whose extension is SPmatch. When I send an email with the doc attached, I see on the device the doc with the correct icon and, if I click on it on Mail, this laugh my Standalone where urlWakeUp receives the path to it. My urlWakeUp command then opens the document in the app.
There should be a difference between false and true, but since true is not accepted in distribution, I am not digging any further. For my scope, I guess receiving the path to a copy of the file doesnt' make a difference.
Matthias Rebbe
But are you able to see the files in the documents folder of your LC iOS app using the iOS Files app when LSSupportsOpeningDocumentsInPlace is set to FALSE?
Roberto
If for "documents" you mean specialfolderpath("documents"), then yes.
BUT note, clicking on a custom doc, in my app this is what happens:
- the app get launched
- my urlWakeUp command receive the path as a var
- in my urlWakeUp I load the doc and then save it to specialfolderpath("documents")
- since is shared then I can also see it int the iTunes shared files
This is what happens in my case. I don't edit the doc on its original path.
If I want to see it in the "Files" app, I have, in the Mail message with contains the attached doc, to hold down the fingere until it ask me: Save to files, Share, copy.
Doing "Save to files", the doc gets saved in the "Files" folder.
Now, if I want to open it, while inside the "Files" folder, i cannot just click (nothing happens except showing me the name and size). I have to share it selecting my app on the list of icons. And everything start again.
I hope to have explained myself.
Should the behaviour be different?
PS this lesson should be updated with more details
Matthias Rebbe
Setting the LSSupportsOpeningDocumentsInPlace to true, would allow the iOS Files app to access the Documents folder of your app (as you wrote specialfolderPath....) but then the UrlWakeUp messages is not send.
So it's currently not possible to use custom file extensions and grant the iOS Files app access to the documents folder of the LC iOS app.
As i am not sure that this is the correct behaviour, I filed a bug for this.
In case you are interested....https://quality.livecode.com/show_bug.cgi?id=23150
Elanor Buchanan
Hi Roberto, I have made some small updates to the lesson but what do you feel is missing. It may be that a separate more specific lesson is needed.
Elanor
Elanor Buchanan
Hi Matthias, thank you for investigating and reporting the bug.
Elanor
Roberto
Well, to me the all storage ecosystem of iOS is rather confused.
For example, the Matthias statement "Setting the LSSupportsOpeningDocumentsInPlace to true, would allow the iOS Files app to access the Documents folder of your app", I don't think is correct. I think the only way to place my custom file in the "Files" folder is trough sharing. Also, clicking in my custom doc in the "Files" folder DOES NOT open the app. I have to share it to my app, pressiming the top btn of the "Files" app.
Elanor Buchanan
Hi Roberto
You can find the documentation for LSSupportsOpeningDocumentsInPlace here
https://developer.apple.com/documentation/bundleresources/information_property_list/lssupportsopeningdocumentsinplace
I am not sure exactly what you need in your app but you might find mergPop helpful, it allows you to present an action sheet, which includes saving a file to Files. We have a lesson on using mergPop here
https://lessons.livecode.com/m/4071/l/1388739-using-mergpop
I don't think the topics of the iOS file system and opening docs from the Files app quite fit into this lesson but perhaps a link to some of the Apple docs or a separate lesson is needed. I'll look into it.
Elanor