After having dabbled in iOS development since 2013, about a year ago I finally had the urge to put an iPhone app into the App Store for others to enjoy. On December 31, 2017, I announced the launch of Yearly, a simple app that lets you read the Bible in one year. I’d built most of it in a single day, on Christmas, in Swift. My expectation was that a few family and friends would download it, and that would be that. What I wasn’t expecting was for it to steadily average a few downloads every day. People were discovering the app without any effort on my part; they were using it, leaving reviews, and emailing me with questions and requests.
About 3 weeks into August, less than 9 months after Yearly’s debut, it reached 1,000 unit downloads. This wasn’t bad for an app with limited functionality and for which I was doing zero marketing.
Then in December, I got an idea based on some feedback I was hearing from different people: Yearly should support deep linking its daily reading to the corresponding book and chapter in YouVersion, the number one Bible app on the App Store. On Wednesday, December 7, 2018, I arrived at my co-working space in the cold 7:00 AM darkness, and began working on this. I finished this on the 8th and submitted the change to the App Store for review.
Then something unexpected happened that threw me off guard. The team reviewed the app on the 9th and rejected it. I’d never had an app update get rejected. This was new territory for me. The explanation for the rejection was twofold:
- First, the deep linking wasn’t working for the reviewer because they didn’t have YouVersion installed. If you don’t have an app installed that’s being deep linked to, nothing happens by default. It just fails silently.
- The second stated reason was that the app was failing to meet minimum functionality guidelines.
I ignored the second message at first, thinking it was optional guidance, and not a big deal. I updated the deep linking process so that if you didn’t have the YouVersion app installed, you would get redirected in Safari to the equivalent on Bible.com, a website maintained by LifeChurch, the same outfit that produced YouVersion. This way, no matter what, tapping on the schedule for a given day would result in something happening. I updated the build number and resubmitted the app on the 9th.
On the 10th, the review team again reviewed and rejected the app. As I conversed with the reviewer in the Resolution Center it became apparent to me that this second guideline failure was indeed a sticky point. Here I was, extending the functionality of my iPhone app, and the purported reason this update was getting rejected was because the app didn’t have enough functionality. It made no sense to me. Going back and forth, I could tell we were getting nowhere. The canned, nebulous responses from the other end began to irritate me. My app was creating value for hundreds of people who were using it on a regular basis and my update was making it even more useful, and this update was getting rejected on the grounds that it failed to meet certain guidelines. I was experiencing the walled garden of Apple and starting to have sympathy for Android’s open stance on apps. Flustered, I threatened to submit an appeal to the App Review Board if the app weren’t approved. The reviewer took the hint and on the 12th scheduled for an Apple representative to call me and discuss my app’s review.
On December 19th at 6:17 PM CST, I got a phone call from San Jose.1,2 The person identified herself as Kelley from Apple. We talked for 17 minutes. She was very friendly and professional and I finally got clear answers. What I learned was this. Apple’s guidelines had changed. As its APIs increased in robustness, the bar for what’s expected likewise increased. The version of Yearly I had submitted in late 2017 would likely not have been approved had I submitted it today. The fact that people were getting value out of the app had no bearing on this. An app, no matter how useful to a segment of users, is either in compliance or it’s not, and Yearly was not in compliance. Because of this, Apple could pull the app from the App Store at any time it wanted, and in the interim it would only accept an update that brought it back into compliance. In order to achieve this, Kelly told me that the Yearly would need to allow users to interact with the content more. Some examples she gave me were:
- It could allow people to share its readings on social media. Or,
- It could offer a journal where people could write about a given reading for that day. Or,
- It could have an in-app Bible so people could visit it directly without leaving the app.
This last part was a sticky point. By deep-linking to YouVersion and then sending people to the Bible.com equivalent as a fallback, I was breaking a few different guidelines:
- An app cannot be dependent upon another app to meet its functionality, so shuttling you off to YouVersion like that was a no-no.
- An app cannot take you to a website in Safari without a way to get back to the app. You’d need to use a
UIWebViewwithin the app itself, but doing that would require permission from the website if you weren’t its owner.
We finished the conversation on amiable terms. I had a clear picture of what I’d need to do in order to get Yearly back in compliance. I had two choices. First, I could do nothing, and freeze Yearly until the App Store finally decided to pull it from the store for being out of compliance. Second, I could roll up my sleeves and get to work bringing it back into compliance. It wasn’t hard for me to decide which of the two options I’d choose.
On Saturday, December 22, I began work on Yearly 2.0. I completely scrapped the StoryBoard I’d originally built it in and used programmatically-generated
UIView's instead, learning how to set auto constraints programmatically (hint: it’s actually a lot faster than using StoryBoard once you get the hang of it). I made a lot of improvements, including switching the home screen to a scrollable
UITableView for your entire year, with each day locking into place as you scroll.3 I added the ability to earmark each day as read. I added the ability to share on social media. I overhauled the screen for how to change your start day. And then I added an easter egg: by double tapping on the lower region of the screen, I deep-linked you to the YouVersion reading. The left half sent you to the Old Testament reading for the current day, and the right half sent you to the New Testament reading. That was a feature I wanted — I frequently listen to the YouVersion audio on my way to work — and I was going to get the last laugh on this.
By January 3rd I’d finished my development after 25.77 hours of intense focus over the holidays, and submitted the new build to the App Store for review. On the 4th the team reviewed and approved the 2.0 update. Yearly was back in compliance once more. In hindsight, the rejection it’d had weeks earlier was the best thing that could’ve happened to Yearly. It forced me to retool and make it better.
Meanwhile, something else was afoot. Yearly’s popularity was skyrocketing as Bible readers prepared for a new year. As I’m writing this, the most recent analytics I have in App Store Connect are for January 3. In the 7 day window ending with that day, Yearly was downloaded 2,372 times. On the 4th I noticed that it was 97th overall for the Reference category. Presumably its rank was higher on January 1 when it had 795 downloads in a single day. All of those downloads were for an app that, at the time, was out of compliance with Apple’s guidelines.
In the grand scheme of things these numbers are small potatoes. Yearly is just a side project. But I’ve learned a lot from it. If you haven’t downloaded Yearly for iPhone, you should. And if you’re not already on a good Bible reading schedule, I recommend starting today!
The days leading up to this, I’d made the unusual step of keeping my phone’s volume turned on more frequently (normally, I keep my ringer off perennially), and paid closer attention to my calls. The annoyance of having to carry my phone with me everywhere and answering a myriad of robot calls reminded me of why call-based communication is one of my least favorite. But I didn’t want to risk missing that call, so it was worth it. ↩︎
Thirty-six minutes earlier I’d finished a 10K run, at a pace that at the time was a record for me. The 6:57/mi pace effort had me in an exhausted but euphoric state of mind. Just nine days later I would break that record with a 6:49/mi pace. Of course, I didn’t know this at the time, and when the phone call was over that evening, I mused that this record wouldn’t have happened if the call had occurred less than an hour earlier. I would’ve resorted to a walk to field that call. ↩︎
Having 365 rows in a
UITableViewis no laughing matter. At 200 pixels height per row, that’s 73,000 pixels in height. Programmatically detecting how far down you’ve scrolled becomes unreliable and caps around 25,000 pixels in my experience. Getting this UX to be smooth and knowing how to properly scroll was non-trivial. ↩︎