iCloud files aren't found by app

My app started to delete it’s own data and files randomly for some users. They swear they used the program for years and then one day everything was gone.
Took a long time to work out what’s wrong. Here’s what I’m sure is happening -

On startup my app checks to see if an output folder exists in the users Documents.
If it doesn’t find the folder it creates one as it is the location for it to store it’s file output (documents and images eg. pdf, jpg).
Somewhere along the line the user decides to allow iCloud to backup Documents, Desktop etc.
All is fine until a period of time passes where they don’t modify or access the output files. iCloud now deletes the output folder from their Mac and shows the download icon (cloud) next to the folder name in Finder.

If you double-click it in Finder it will download again, but that’s not how the program works.

After a time the user opens my app as usual.
The app uses this code on startup to check for the folder -

'Create an output folder
  outputFolder = DocFolder.child("output")
  if not outputFolder.Exists then
    outputFolder.CreateAsFolder

This doesn’t see the folder (with the cloud icon which is visible in Finder) and creates a new output folder which uploads overwriting the one on iCloud with an empty folder.

Disaster - all previously created files gone!!!
(not even visible online in iCloud > Deleted files).

Note: Please leave conversations about where I should be storing program output for another post. That’s not relevant here as a user can choose any folder to sync with iCloud.

Strange. If I remove downloads for files in a folder, the folder stays as folder there.

iCloud is a POS.

If you get a hold of a library that can utilize NSURL, you can check for the value of “NSURLIsUbiquitousItemKey” If it returns True, then this file is synced with iCloud.

If you have the MBS, you should be able to access it, if not I also sell a library “Ohanaware App Kit” which can be used to read this key.

I swear at one time there was a key to prevent iCloud from ■■■■■■■ with your files, but I don’t see it in the documentation at the moment.

1 Like

Big problem if you ask me. You can’t rely on files being in the right place when you need them once the user chooses the iCloud option.
I’ve had people lose their registration key file because they’ve stored it on their desktop. The program searches to import it but nothing shows up. The user can see it right in front of them on their Desktop and thinks there’s something wrong with it because it won’t import.

Right so it would appear that you need to use NSURL API to validate if the file is there or not and if it’s in the cloud or not.

@Greg_O_Lone would it be possible to know which Apple API folderitem.exists actually calls?

This situation worries me, Apple auto-enable iCloud on new devices when you log-in with a Apple ID. Which means that potentially any app that doesn’t get used frequently enough can have it’s data ripped away.

I had assumed that Apple would auto-handle this for the developer, so we effectively don’t know where the data is.

Which leaves me thinking, either we need to use a different API to check for the existence of a file (that trigger an auto download), or we need to perform additional checks ourselves. As I’ve just made a change to an app that some users use infrequently, I am going to look into this and see what I can find. The last thing I want is my user to open the app to do a 2 minute task and for the data to all be gone.

For some customers having the same files across multiple devices is a boon, but in cases like this, we (the developers of 3rd Party Apps) will get the blame for how Apple decided to handle this.

While looking up something else, I came across an interesting tidbit. The Open dialog contains the functionality to auto download files from iCloud. All the user needs to do is to select the file/folder in the dialog and the OS will handle the rest.

Perhaps if you change the design of your application to ask the user where they want to save their data (I dislike this approach personally), then save the path into your preferences.

Now when they re-open the app and auto-restoration of the path fails, show the user an open dialog and set the default to be that path. When they click OK, the OS should then auto-download the file for you.

I took a brief glimpse of what’s involved to do this without a open dialog, so far it looks like a lot of work and you have to use alternative objects for handling files.

2 Likes

Well, we have NSFileManagerMBS where you can use fileExists function.
Or get a NSURLMBS for the folderitem to query resources for NSURLIsUbiquitousItemKey key.

Yes I think this is the best way.
My app shows a page displaying a list of the user files so they can select which one to open. This doesn’t work with iCloud as it doesn’t find anything causing them a lot of grief and worry.
I will have to revert to using a button to open a dialog to select a file and changing he programs list to something else.
I was thinking maybe recently opened files (after checking if they still exist).

I hope that it helps, because right now, looking at the alternative seems a huge amount of work to overcome something that probably should never have been enabled in the first place (auto removal of local copies).

Ouch. I can confirm the problem. Isn’t this a bug in Xojo? The folderitem should report .exists = true and not false.

How do I use the NSURLIsUbiquitousItemKey thing?

In

dim s as String = "/Users/beatrixwillius\ 1/Library/Mobile\ Documents/com\~apple\~CloudDocs/flame/\ files/flame\ files/\ flame8/79y.flame"
dim f as new FolderItem(s, FolderItem.PathModes.Shell)

dim n as new NSURLMBS(f)

dim key as String = n.NSURLIsUbiquitousItemKey

key = “key”

Well, NSURLIsUbiquitousItemKey is a function to return the name for that key, which is not always the name of the function:

Dim n As New NSURLMBS(f)

dim value as Variant 
dim error as NSErrorMBS
Dim result As Boolean = n.getResourceValue(value, n.NSURLIsUbiquitousItemKey, error)

I don’t think it is, I was curious to know what API Xojo uses to check the existence of a file, and once I know, I can look for others and do some testing.

However looking at the docs I found this morning, it seems like the “Correct” way to handle is via other classes and not the default NSURL object. I may be wrong as I only glanced at the docs. It also appears that you have to handle the display of the download process yourself.

If this opendialog trick works, you should be able to trigger it by setting the default directory to be the actual file itself.

if f <> nil and f.exists = false then
  Dim nod as new openFileDialog
  nod.initialDirectory = f
  
  f = nod.showModal
end if

Should do it, but I avoid iCloud and it’s kin, so it’s hard for me to test.

If you call it often and check stack trace. e.g. you may see FSGetCatalogInfo being queried for a folderitem I got from specialfolder.desktop.

@Christian Schmitz: thanks, that works.

@Sam_Rowlands: as Xojo user I expect that the code is simple. If there is a file and the file reports .exists = false then I actually expect that the file doesn’t exist. My app can write lots and lots of PDF files. Only the parent folder is selected. But the user doesn’t need to re-select the folder because the folder is saved to the prefs.

Another question: Can I force a download?

  1. I understand what you are saying. I don’t think it’s a bug, because I think that’s how the NSURL API works (is what I assume Xojo is using, until I am told otherwise). Apple have added the functionality for a developer to manage the download via other classes for interacting with files. At least that what it seems like to me at this very moment.

  2. In theory, showing the open dialog and preselecting the file, should trigger the download when the user clicks “Opens” and the dialog should download it for you. The other option will require more reading and experimentation to get an understanding of how the alternative file API works, before I can write any code.

Doing a file dialog for the file doesn’t make sense when my app can write 10s of thousands of file. At least nobody has encountered such a problem before. Still the discovery doesn’t make me happy. I think the best way to handle the situation for now is to add the check with the code from Christian and make an error message.

FWIW, I seem to recall that if you add an extension on the folder of .nosync the Finder won’t send it to the server and won’t remove it from the computer either. There may be another extension (or a file attribute) you can use to prevent this behavior too.

1 Like

I’ll test with the file.

AFAIK, you only need to do this if the file doesn’t exist, you shouldn’t have to do it for every file every time.