Rejected: Holding My Data Wrong
/I have a shameful secret. I’ve never told anyone. I can trust you, right?
I have never actually read most of the App Store Review Guidelines.
I know, I know. How can I call myself a developer? In my defense, in its current incarnation, it’s like 12 whole pages[1].
While there is some obvious laziness involved, I actually assumed most were super obvious. Additionally, none of my apps did anything remotely close to pushing the boundaries of what is allowed. My apps rarely ever used the latest, shiny technologies available. And when they did, they generally did so following Apple’s example code.
Nothing groundbreaking.
This does not mean my apps are boring. I swear.
The rejection
So I was quite surprised on January 11th, when Apple rejected my initial build for Stories by Gus on the Go. While I was on vacation. Naturally.
I had violated guideline 2.23.
Apps must follow the iOS Data Storage Guidelines or they will be rejected
Ok…
Luckily, in the details section, the reviewer told me exactly why it had been rejected. After downloading the content from an In-App Purchase, 13.95 MB were being synced to iCloud.
This surprised me. This was my first experience creating an app with downloadable content. I was not using any iCloud APIs that I knew about.
As a user I have limited experience using iCloud. I don’t do iCloud backups, which means I did not know there could be a problem.
After downloading the IAP content, I was moving it out of the cache directory to one that was guaranteed to persist. Short of deleting the app. What I did not know is that most of these sandboxed directories are automatically backed up to iCloud. Oops[2].
It makes sense. Users’ iCloud drives have limited capacity. If every app they used sent a bunch of unnecessary data during a backup, they would quickly run out of space and have to pay for more[3].
Dang. It really was my fault.
The fix
After some quick research, I discovered I needed to set a flag on the IAP files telling the system that they are excluded from backups.
NSError *error; BOOL success = [iapContentURL setResourceValue:[NSNumber numberWithBool:YES] forKey:NSURLIsExcludedFromBackupKey error:&error];
Sorry for the Objective-C. Most of Stories is in C++, which makes it much easier to mix with Objective-C than with Swift[4].
I believe this key also excludes the files from backing up to iTunes, which in this case is fine. IAPs can always be restored via the app.
The fix was so simple. A fact that made the rejection that much more frustrating. But not less warranted.
Resubmission
There was still one potential issue with the app when I resubmitted. Stories allows users to create multiple profiles to keep track of their learning progress. However, since most users will not use this feature, there is a default user that is automatically created and used. This improves the user experience by not requiring an on boarding process.
Created user profiles should and do get backed up to iCloud. However, the default profile gets backed up if the user never creates a profile.
The default profile uses an extremely small amount of space. If guideline 2.23 were interpreted strictly by a reviewer, the app could once again be rejected.
I decided to take the advice of a recently read blog post titled, A simple tip to reduce App Store rejections. In the App Review Information section, I made use of the Notes box.
A Default user profile is provided in the Documents directory (and therefore also synced to iCloud) upon first launch as a convenience to the user to allow she/he to immediately enjoy the app. The user can edit this default user profile to suit themselves or delete it and create another, but as the app can track the learning progress of multiple users, at least a single user profile needs to exist and persist from the first launch. The space required to save the default user profile is minimal.
While I don’t know if I would get rejected for syncing a profile the user did not create to iCloud, I feel better about explaining my design decision to the reviewer.
Success!
Stories was reviewed again and this time accepted. I have left the note to the reviewer for three further updates and so far no hiccups.
Will I finally actually read the App Store Review Guidelines? Originally, I had planned to answer that question with a “sadly, probably not”. However, since discovering how short it is while writing this blog post, I actually may. Probably. We’ll see.
If you want, follow me on Twitter. I’m @yonomitt.
Have a nice day,
Yono