Creating custom keyboard extensions for iOS apps offers a powerful way to deliver specialized input experiences that go far beyond the system keyboard. From niche vocabularies for medical or legal fields to expressive emoji keyboards, swipe‑based typing, and even game‑specific controllers, a well‑crafted keyboard extension can significantly boost user engagement and retention. This guide provides an authoritative, production‑ready walkthrough of building, testing, and publishing iOS keyboard extensions using Swift and Xcode.

Understanding iOS Keyboard Extensions

A keyboard extension is a type of app extension that runs within the system keyboard interface. Users switch between the default keyboard and your custom one through the globe icon or a dedicated keyboard picker. Unlike a standalone app, a keyboard extension operates in a sandboxed environment with limited access to network resources, file systems, and the host app’s data. It must implement the UIInputViewController subclass, which manages the keyboard view and handles input events.

The extension’s lifecycle is closely tied to the host app. It is initialized when the keyboard appears and deallocated when dismissed, so state persistence must be handled via shared App Groups or UserDefaults with suite identifiers. Apple provides detailed documentation on the keyboard extension architecture, including required capabilities and the Info.plist keys that declare supported input modes (e.g., full access for network access or autocorrection).

Setting Up a Keyboard Extension Target in Xcode

  1. Create a new target inside your existing iOS app project (or a new single‑view project) by navigating to File > New > Target and selecting “Keyboard Extension” under the Application Extensions section.
  2. Configure the Info.plist for the extension. The key NSExtension must contain NSExtensionPrincipalClass pointing to your KeyboardViewController subclass, and NSExtensionAttributes must include IsASCIICapablePreferred and PrefersRightToLeft as needed. If your keyboard provides any custom input modes (e.g., number pad or emoji), add them under InputModes.
  3. Set the deployment target to match your app’s minimum iOS version (iOS 10.0 or later recommended). Keyboard extensions are supported from iOS 8 onward, but newer features like swipe‑to‑type and haptic feedback require iOS 13+.
  4. Enable “Full Access” only if your keyboard requires network access, file sharing, or the ability to provide custom autocorrect. This is an opt‑in switch in Settings > Keyboard > Your Keyboard, and you must prompt users to enable it. Without full access, the extension cannot use URLSession or access shared containers.

Designing the Keyboard Layout

Programmatic UI vs. Storyboard

While you can use a storyboard for the keyboard view, programmatic layout with UIStackView or Auto Layout is more flexible and easier to maintain. Keyboard extensions must respond to system‑initiated size changes (e.g., orientation, floating keyboard, slide‑over) and accommodate the safe area at the bottom for devices without a Home button.

Create a grid of UIButton objects arranged in rows. Use custom subclasses to handle touch events (touch down, drag, release) and to provide visual feedback. For example:

class KeyboardButton: UIButton {
    override var isHighlighted: Bool {
        didSet {
            backgroundColor = isHighlighted ? .lightGray : .darkGray
        }
    }
}

Use UIStackView with distribution: .fillEqually to evenly space keys in a row. Avoid hard‑coded width values; instead, use multipliers and constraints to adapt to the current keyboard width. For non‑service keys (e.g., Shift, Backspace, Globe), use smaller fixed widths (e.g., widthAnchor constraint(equalToConstant: 40)).

Supporting Multiple Interface Orientations

Your keyboard layout should adjust when the device rotates. Override viewWillTransition(to:with:) in KeyboardViewController and recalculate the layout. For landscape orientations, you may want to present a narrower row of number keys or a tab bar for toggling between keyboard modes. Consider using a parent UIStackView with a distribution: .fill and nested horizontal stacks for each row.

Implementing Input Handling

Every keyboard extension must conform to the UIInputViewController class. The primary mechanism for inserting text is the textDocumentProxy property, which returns an object conforming to UIKeyInput and UITextInputTraits. Use the proxy’s insertText(_:), deleteBackward(), and replace(_:withText:) methods to manipulate the currently focused text field.

Handling Shift and Caps Lock

Maintain an internal shiftState enum (off, on, locked) and toggle it when the Shift button is tapped. When the shift is active, uppercase letters should be inserted; otherwise, lowercase. For caps lock detection, listen for UITextInputCurrentInputModeDidChange notifications? Actually, caps lock is usually implemented as a double‑tap or long‑press on Shift. Use a timer to differentiate single tap from double tap.

Example approach for Shift handling:

var shiftEnabled = false

@objc func shiftTapped() {
    shiftEnabled.toggle()
    updateShiftAppearance()
}

func keyTapped(_ sender: UIButton) {
    guard let letter = sender.titleLabel?.text else { return }
    let textToInsert = shiftEnabled ? letter.uppercased() : letter.lowercased()
    textDocumentProxy.insertText(textToInsert)
}

Custom Autocorrection and Word Suggestions

Autocorrection in keyboard extensions is limited without full access. With full access, you can use UILexicon (which provides contact names and common words from the system lexicon) or build your own dictionary. To show suggestions above the keyboard, add a UIScrollView or horizontal stack of UIButton objects and populate them based on the current word being typed.

For a more sophisticated system, consider using the KeyboardKit open‑source library, which provides pre‑built autocomplete, autocorrect, and swipe‑to‑type functionality.

Adding Advanced Features

Swipe‑to‑Type (Gestures)

Starting from iOS 13, you can support swipe gestures over the keyboard. Use a UIPanGestureRecognizer attached to the main keyboard view. Track the finger’s path across a virtual grid of keys and insert characters when the path changes direction or when the finger lifts. This requires a precise key‑hit‑testing algorithm – for each touch position, determine the nearest key center and insert that character.

Example skeleton:

let panGesture = UIPanGestureRecognizer(target: self, action: #selector(handlePan(_:)))
view.addGestureRecognizer(panGesture)

var currentTouchKey: String?

@objc func handlePan(_ gesture: UIPanGestureRecognizer) {
    let location = gesture.location(in: view)
    guard let key = key(for: location) else { return }
    if key != currentTouchKey {
        textDocumentProxy.insertText(key)
        currentTouchKey = key
    }
    if gesture.state == .ended {
        currentTouchKey = nil
    }
}

Haptic Feedback

Keyboard extensions can use UIImpactFeedbackGenerator or UISelectionFeedbackGenerator to provide tactile responses for key presses. This improves the typing experience. Because haptics may affect battery life, allow users to toggle them in a settings bundle. Use NSHipster’s guide to integrate feedback generators properly.

Emoji and Symbol Keyboards

Create a second mode for emojis or symbols. Implement a tab bar at the bottom of the keyboard (similar to the system emoji keyboard) that toggles between different keyboard views. Use addChild and removeFromParent to swap out the entire keyboard panel, or use a UIPageViewController for swiping between modes.

Managing State and Preferences

To persist settings like keyboard theme, haptic feedback on/off, or user‑defined shortcuts, use UserDefaults with an App Group suite identifier. This allows the main app to read and write preferences that the extension can access. To set up App Groups:

  1. In your main app target’s Signing & Capabilities, add App Groups and create a group (e.g., group.com.example.myapp).
  2. Do the same for the keyboard extension target.
  3. Instantiate UserDefaults(suiteName: "group.com.example.myapp") in both targets.

For a settings bundle accessible from the iOS Settings app, add a Settings.bundle to the main app target. The keyboard extension cannot host its own Settings screen; users must open the host app or use a URL scheme to configure the keyboard.

Ensuring Performance and Security

Memory Management

Keyboard extensions have a low memory limit (around 50 MB). Avoid storing large image assets or complex view hierarchies. Use lazy loading for secondary keyboard panels and clear cached data after use. Instruments’ Memory Graph tool is essential for profiling the extension in the simulator.

Privacy Considerations

Without full access, your keyboard extension cannot log keystrokes, access the network, or use the pasteboard. With full access, you must disclose in your privacy policy exactly what data you collect and how it is used. Apple reviews extensions for privacy compliance, and misleading users can result in rejection. Never transmit keystrokes to a remote server without explicit consent and a clear justification.

Use the UIPasteboard only when the user explicitly triggers a paste operation (e.g., a dedicated paste button). Random clipboard access is forbidden.

Testing and Debugging

Testing a keyboard extension requires running it from a host app (like Safari or Messages) in the simulator or on a device. In Xcode, select your extension scheme and choose a host app. Use cmd+R to build and run; the keyboard will appear when a text field is focused.

Common pitfalls:

  • Extension not appearing: Ensure the extension is correctly added in Settings > General > Keyboard > Keyboards. Also verify the Info.plist includes IsASCIICapablePreferred set to true if you want the keyboard to be available for password fields.
  • Auto Layout issues: Use the view debugger to inspect constraints. Keyboard views often have a fixed height (216 pt in portrait on iPhone, 162 pt in landscape). Override viewWillAppear(_:) to set an explicit height constraint.
  • Orientation changes: Test both portrait and landscape, as well as the floating keyboard on iPad. Use trait collection change callbacks.
  • Memory warnings: Respond to didReceiveMemoryWarning by releasing cached views and images.

For automated testing, use XCUITest but note that keyboard extensions are not directly testable via UI tests. Instead, you can create a test host app with text fields and exercise the extension manually or via unit tests for the logic layer.

Publishing and Distribution

Keyboard extensions are submitted as part of an iOS app. When uploading to App Connect, ensure the extension bundle is included in the archive. During review, Apple evaluates the extension’s functionality and privacy practices. Common rejection reasons include:

  • Misleading functionality (e.g., promising voice input but not delivering).
  • Lack of a privacy policy if full access is required.
  • Implementing a keyboard that simply duplicates the system keyboard without added value.

Once approved, users enable the keyboard from Settings > General > Keyboard > Keyboards > Add New Keyboard. You can also guide users via a deep link to that settings pane using UIApplication.openSettingsURLString (though extensions cannot open URLs directly – the host app must handle this).

Monetization Strategies

Because keyboard extensions cannot display iAds or use StoreKit directly (no in‑app purchases within the extension), monetization is typically handled through the host app:

  • Paid app: Charge for the entire app that includes the keyboard.
  • Freemium: Offer a free basic keyboard and unlock advanced themes or autocorrect via an in‑app purchase in the host app, then sync the purchase via App Groups.
  • Subscription: Provide premium features (cloud sync of custom dictionaries, analytics) using a subscription model managed by the host app.

Always ensure that the extension reads entitlement status from shared preferences, not directly from StoreKit.

Conclusion

Building custom keyboard extensions for iOS apps is a challenging but rewarding endeavor. By mastering the UIInputViewController lifecycle, designing adaptive layouts, implementing robust input handling, and respecting Apple’s privacy guidelines, you can create a keyboard that feels both native and innovative. With the addition of advanced features like swipe typing, haptic feedback, and autocomplete, your keyboard extension can become a compelling productivity tool that users rely on daily.

Start with a simple numeric or emoji keyboard, then gradually add complexity. Use the Apple developer documentation as your primary reference, and explore open‑source projects like KeyboardKit to accelerate development. With careful testing and a focus on performance, you can deliver a keyboard extension that stands out in the App Store.