There are a few factors:
-
We need a sync solution that is cross-platform and works with Windows as well as Mac.
-
We needed a sync solution with an API readily available in Objective-C, so that I didn’t have to write everything based on web hooks from the ground up.
-
We needed something a lot of users have.
-
We needed something that we knew synced reliably on macOS and Windows.
Dropbox ticked all of those boxes, and is the most popular sync solution. On the Mac, iCloud is equally popular, but it’s not as good a solution for Windows users and it also has real problems with the Scrivener file format, so isn’t really compatible.
Scrivener’s sync code is essentially split into two units:
-
The code that uses the Dropbox APIs. This replicates what the Dropbox client does on the Mac, uploading, downloading and dealing with conflicts.
-
The code that reads the files changed by the mobile version and merges them with desktop changes.
This means that, in theory, I can add other sync solutions at a later date. I “just” have to write the code that does (1) for other sync solutions.
The problem is that for each sync solution, I pretty much have to code from scratch what the sync provider’s desktop client does automatically. There are 4,000+ lines of code in my Dropbox sync file (probably 2,500+ once you remove blank lines and braces). And that’s for an API that provides an Objective-C wrapper (i.e. a wrapper in the language I use). For other APIs, I would have to replicate everything this does, but it would take more code because few, if any, of the other APIs have Objective-C wrappers, meaning I would have to write lots of code to wrap around the raw server calls.
It wouldn’t be so bad if the APIs provided by sync providers could do exactly what the sync clients do on the desktop. For instance, with Dropbox, on the desktop you just install the Dropbox app and that automatically syncs all the files in the Dropbox folder across machines and with their servers. It would be wonderful if the Dropbox APIs did the same, because then I could just write code that said, “Hey, Dropbox API, sync everything in this folder with the same folders on your servers.” That’s not how it works, however. Instead, I have to write code that replicates what Dropbox do for free on the desktop. I have to write the code that says, “Check what’s changed online, download this, and upload this. Create this folder, and make sure you create all these folders before putting files in them. Oh, and this file seems to have changed in two places, so rename one version and place it here, and upload the other here. Delete these files.” I also have to deal with storing a cache of the current folder state after a sync so that I can compare it to the Dropbox servers and the latest folder state when syncing to see what has changed.
All of this was a couple of months’ work at least. To add OneDrive support and support for other, similar solutions, I would have to do all of this again, plus the extra code (and learning time) to create my own wrapper for their server calls. So you are looking at probably a couple of months of coding for each sync solution.
I certainly don’t rule out adding support for other sync solutions in the future, but it won’t be for a little while. Things are further complicated by the fact that Scrivener uses Dropbox API 1, because that is the version of their API that has an Objective-C wrapper. But Dropbox has just deprecated API 1, and are turning it off entirely this time next year. But their Objective-C wrapper for API 2 won’t be available until August. This means that later this year, I am going to have to rewrite a lot of the Dropbox syncing code to support Dropbox API 2.
In other words, it all comes down to the practicalities of being a tiny team (i.e. a one-man coder in this case, as I’m the sole coder for macOS and iOS).
Now, at some point I do need to find a second developer to help me, and I want someone with sync expertise. That might open up possibilities. (Another practicality there is that we don’t even have offices, though!)
I hope that all makes sense and doesn’t come across as making excuses.
All the best,
Keith