Creating custom keyboard for iOS

Marcin Mierzejewski
VESTIONE
6 min readMay 27, 2018

--

Every developer wants to do the best possible job while creating a product. Often, it requires a touch of originality that goes beyond the natural design. Luckily, App Extension allows developers to add custom functionalities beyond normal apps’ boundaries. There are a few types of these extensions, one of them is a custom keyboard.

From iOS 8 onwards, the developers can extend their mobile apps with this feature. System keyboard is great, comfortable and all, but in some cases, the third-party keyboards can speed-up text inputting with features like swiping or prediction of user’s intentions (what kind of sorcery is this?).

When it was introduced, one of my first ideas was to create a simple password manager. Entering complex passwords on a small non-physical keyboard has never been easy or nice. In theory, I just needed to build my custom keyboard and live happily ever after. However, then I learned about certain complications such as…

The custom keyboard limitations…

These limitations can be summarized in one sentence: Custom Keyboard is not allowed to access many things that are normally available to standard apps.

First, concerning my password manager, Apple is worried about user privacy. That is why we cannot use a custom keyboard when interacting with secure fields, so it isn’t possible to create a keyboard with a magic button that will do all this password typing for us.

We can’t draw above the keyboard frame.

Moreover, you cannot draw any elements over the normal keyboard frame. That’s a shame, however, it goes well together with Apple’s Human Interface Design rules, so there’s that. Other than that: we can’t have any access to the microphone and camera through Custom Keyboard, which renders dictation input impossible.

As you may expect, the list goes on and on. You can read more about limitations and good practices in Human Interface Guidelines

…and must-haves

It is mandatory to provide a button to switch to another keyboard or return to the stock keyboard. In the system keyboard, it is that mysterious globe icon button. To not mess with user expectations, habits, and entrenched behaviours, I suggest keeping it that way. All we need to do is addTarget to our keyboard UIInputViewController to method advanceToNextInputMode() with all events (user might tap on this button to fast switch to next or tap a bit longer to see the list of available keyboards).

To use an internet connection user must allow full access to the custom keyboard. It allows the keyboard to share data with containing application. Thanks to that, this application may become a manager application for the keyboard. Thus, it can be used to synchronize user dictionaries or adjust and keep user preferences.

However, the keyboard must be usable at all times without full access, therefore also without an internet connection.

Implementation tips

Just a few code snippets

I don’t want to walk you through step by step, because I’m sure you know how to create xcode projects, add views etc. To start you need to add a new target (File->New->Target->Custom Keyboard Extension) to an existing project. You’ll get an InputViewController subclass which is a keyboard start point — you can add your controls here.

Let’s jump to cool stuff. Examples are in Obj-c, but basically, they don’t have any language-specific quirks and if you are writing in Swift it will be very easy to translate them. I also recommend reading more implementation tips from Krzysztof Pelczar's article.

Handling return key type and keyboard type

If you are creating an app that can be used as the main keyboard, you will need to prepare for different text entry scenarios. For the user’s convenience, you might add “@” button instead of some other button when the user is entering an email address or show only a number pad while editing fields that allow digits only. You can get the current keyboard context(UIKeyboardType) by calling in Your InputViewController:

There is also returnKeyType property in textDocumentProxy for return key type (UIReturnKeyType). It can also give you some insights into the current keyboard context. You may adjust your return button title to match this property:

Dismissing keyboard

There is no method to dismiss the keyboard in UIInputViewController. It’s because the keyboard shouldn’t be responsible for deciding if it is visible or not. This should be left to host (i.e. currently active) application and user gestures on the screen. What we can do to inform that the user finished editing current text field by calling:

This is the action we should bind to the return key. If the user taps a return key on our keyboard while being in safari, the address text field will start loading the given URL and dismiss the keyboard. If it’s an email input it will probably go to the next respective field, most likely a password input. In this context, sending new line character means that the user finished entering text to this field.

Handling orientation changes

We can’t just force the user to use the custom keyboard only in portrait mode. Thus, we also need to prepare the layout for landscape. Like in a normal UIViewController we should handle a rotation event with method:

viewWillTransitionToSize:withTransitionCoordinator:

The first argument is the size, which keyboard view will have (actually we can adjust the height later, so the width is much more helpful). The second one is a coordinator object, it allows us to set up animation that will start alongside other rotation animations.

The next step is to call:

animateAlongsideTransition: completion:

The first argument is a block that is responsible for animating keyboard transition. The last one is a completion callback, which will be executed after all animations.

Handling different screen sizes

Preparing views that look good on every screen is a difficult task. It becomes even more complicated when it needs to be usable as well (Tip: It always should be!).

I do not recommend using a visual interface builder for button placement, because it will take much longer to finish and it will become quite hard to maintain in the long run. Usually, in our projects, we create views in code with layout constraints (Visual Format Language — FTW!). But this time I decided that calculating frame for each keyboard button will be a better solution. It will be calculated only once, it will not need to keep constraints between neighbour views and it allows for a very fast size adjustment.

Piece of code just to show how it’s done:

Handle long tap key repeat

When the user taps a delete button, they expect it will be deleting text until they raise their finger. That’s how it works on the native keyboard and what is yet another one of the entrenched user behaviours. But there is a flaw. As far as I know, there is no gesture recognizer that will be called every given time interval. But we can do a simple trick with UILongPressGestureRecognizer and NSTimer. As result, we receive an event every 150ms while the user keeps their finger on the delete button.

Summary

Creating a custom keyboard is a daring adventure. If you care for your users, you may want to deliver reliable, fast, and innovative text input methods. It may be extremely hard to convince users to use your mobile app custom keyboard over a pre-installed, vanilla one, but if you do convince them, you can feel like a real codeguru. In a way, you just won over Apple engineers and UI/UX designers!

Just one more thing, a reminder of sorts. We need to remember that with great power comes great responsibility — that means we should be very careful when handling user data. If we leak any information about users we won’t be able to gain their trust again and that’s a situation that cannot happen.

--

--