Contrast Keyboard a behind the scenes look

Recently I released an iOS 8 keyboard app called Contrast Keyboard. Creating that app gained me tons of programmer experience points. So I figured it’d be cool to outline the big topics that came up along the way.

Swift

This is my first app I built using Swift. I wanted to get out of my comfort zone with Objective-C and ship something written 100% with Swift. Swift was a good experience and I think Contrast was a good project to learn Swift on (all cocoa-touch). Overall, I’ll keep down the Swift bandwagon but its a very bumpy road to travel right now. I learned the Swift fine, but The language and the tools are too fragile still. I hope to go into better detail on a “What I leanred with Swift” style blog post soon.

Design

I wanted something visually simple. Since I am not a designer, simple is an easy starting place for me. The final design was decided early on. The first keyboard hack had ugly buttons. So I removed the borders. But Once I removed all the borders, thought… thats ugly, where do I go from here? Everything else came together quickly.

All key buttons appear buttonless, regardless of background color. To do this and not loose your way, the home row needed to be highlighted (I don’t know about you but the home row is the first thing I learned in keyboarding class).Adding page swipe was obvious to me because I had always wanted a keyboard where you could swipe to another page for buttons, instead of tapping buttons. This works most of the time, but I think sometimes you swipe back and forth just as much as touching buttons. Not that this is bad, because the swipe gestures is more familiar than playing “where is the numbers and special key button.”

Xcode Storyboards

At some point I realized I hadn’t created the companion app (for settings configuration), yet I wanted to get submitted to apple really soon. So I created a Storyboard to quickly make the companion app. I used static tables to create all the menu’s. By using Storyboards, I probably had the whole companion app done in a few hours.

Considering this was more than just the interface (saving preferences), I think this was faster than writing it all in code. If not, Storyboards with Autolayout made life alot easier (see Universal Binary! Section).

UIScrollView

When you put UIButtons on a UIScrollView, you get weird behavior (by default). The button needs a delay to be highlighted. To fix that, I created this UIScrollView subclass:

class KeyboardScrollView : UIScrollView {
  override init(frame: CGRect) {
    super.init(frame: frame)
    self.delaysContentTouches = false
    self.showsHorizontalScrollIndicator = false
    self.showsVerticalScrollIndicator = false
    self.pagingEnabled = true
  }

  override func touchesShouldCancelInContentView(view: UIView!) -\> Bool {
    if view.isKindOfClass(UIButton) {
      return true
    }
    return super.touchesShouldCancelInContentView(view)
  }
}

 

Full Access for the Keyboard Extension

I was determined on making a keyboard that did not require Full Access, but this could not be done. Basically the version I had shipped used App Groups to share NSUserDefaults with each other – nothing fancy. To share NSUserDefaults with an App Group, you need have the user enable Full Access to this keyboard. I wanted to use the Settings.bundle with the keyboard extension, but as of Xcode 6.1, I found it was riddled with bugs and will not work.

The only option was to use App Groups (requiring Full Access) or cram a settings controller in the keyboard extension (not requiring Full Access) – which I didn’t have time for. Contrast 1.0.1 requires Full Access to make changes in the companion app. If its not enabled the keyboard works on its default settings. When I find a better way, I will update it! Ideas?

Privacy Statement

All iOS 8 Keyboard apps are required to have their own Privacy Statement. I didn’t know this until I submitted the app for the first time. In order to send out external TestFlight invites (and to submit for review), a privacy statement URL is required. I took a Creative Commons privacy statement, updated it for Contrast and had an attorney review it (just incase). It covers what needs to be covered.Read it here

Universal Binary!

Finally I was ready to submit to Apple. Sweet! But upon first submission, I was rejected.

25.1: Apps hosting extensions must comply with the App Extension Programming Guide Specifically, we found that your Beta App is not a Universal binary.

The problem was that I set the companion app to iPhone target only and you can’t do this. The companion app needs to be set to Universal. Which means your Keyboard (other extension types too) need to work just fine on all device sizes. I had thought that if I set the companion app to iPhone and the extension still loads fine on iPad then I’d be fine. This was ideal since I hadn’t spent a ton of time on the iPad layout and I was hoping it wouldn’t show up for iPad users unless they selected “iPhone apps” in the search.

Luckily the keyboard worked fine on iPad but it looked pretty dumb. Basically it was just a giant iPhone keyboard, as I wasn’t utilizing the extra space at all. I made a compromise here so it was “good enough” to ship. This is where Storyboard and autolayout was a good decision since it took about 10 minutes to make the companion app good on iPad. Otherwise, I updated some font sizes on the iPad and that was it. I’m positive I’ll get bad reviews for this, but I didn’t want to delay even another day. The next big update will be better support for larger device sizes.

Read more about other requirements to App Extensions before you start! I read this thing like 20 times.

Wrapping up

Hope that was interesting. If you are writing a keyboard app, feel free to get in touch! Oh and good luck… you’ll need it. Drop me a line anytime here in the comments or via email.