Showing the system Emoji keyboard by default on iOS 13
Asked Answered
T

4

21

Solution

Here is a full solution/work around for this issue, please up vote Blld's answer as well because this was the vital bit of info needed!

Alternative titles to aid search

  • Showing the Emoji keyboard as default for a UIKeyInput object (in iOS 13)
  • Force iOS 13 to show the Emoji keyboard
  • Setting the UITextInputMode.primaryLanguage to emoji
  • Programatically set the keyboard to emoji

Prior to returning the UITextInputMode with primaryLanguage that equaled "emoji" would default to showing the Emoji Keyboard (see image below).

Emoji keyboard screen shot

Example code for returning the "emoji" UITextInputMode.

//
//  ViewController.swift
//  Keyboard Info
//
//  Created by Richard Stelling on 30/09/2019.
//  Copyright © 2019 Richard Stelling. All rights reserved.
//

import UIKit

class TestButton: UIButton, UIKeyInput {

    var hasText: Bool = true

    func insertText(_ text: String) { print("\(text)") }

    func deleteBackward() {}


    override var canBecomeFirstResponder: Bool { return true }

    override var canResignFirstResponder: Bool { return true }

    override var textInputMode: UITextInputMode? {
        for mode in UITextInputMode.activeInputModes {
            if mode.primaryLanguage == "emoji" {
                return mode
            }
        }
        return nil
    }
}

Running this code on iOS 12 will set the keyboard to the system Emoji Keyboard, but on iOS 13 it has no affect.

Is this a known bug? Is there a workaround?

Updates

  • Requested by @Navillus, the full list of "active input modes" is; "en-GB", "emoji"
  • Tested and confirmed on; 13.0, 13.1, 13.1.1, 13.1.2 and 13.2 (seed 1)
Thrombin answered 30/9, 2019 at 12:33 Comment(4)
Funny thing: I was able to run this code successfully on simulator, but not on device. iOS 13 for both. Now I'm intrigued.Hilaire
Worked for me in a simulator too. @rjstelling What is the full list of activeInputModes on your device? You can check with this: print(UITextInputMode.activeInputModes.map({ (m) -> String in return m.primaryLanguage ?? "" }))Crudden
@Crudden - answers in the question, its "en-GB" and "emoji"Thrombin
This is now fixed in iOS 13.4/Xcode 11.4Khano
T
10

NB: Make sure you have the Emoji keyboard enabled.

This seems to be an iOS 13 bug, the work around (for devices, this does not affect the Simulator) is to override the textInputContextIdentifier property and return a non-nil value.

//
//  ViewController.swift
//  Keyboard Info
//
//  Created by Richard Stelling on 30/09/2019.
//  Copyright © 2019 Richard Stelling. All rights reserved.
//

import UIKit

class TestButton: UIButton, UIKeyInput {

    var hasText: Bool = true

    override var textInputContextIdentifier: String? { "" } // return non-nil to show the Emoji keyboard ¯\_(ツ)_/¯ 

    func insertText(_ text: String) { print("\(text)") }

    func deleteBackward() {}

    override var canBecomeFirstResponder: Bool { return true }

    override var canResignFirstResponder: Bool { return true }

    override var textInputMode: UITextInputMode? {
        for mode in UITextInputMode.activeInputModes {
            if mode.primaryLanguage == "emoji" {
                return mode
            }
        }
        return nil
    }
}

Thanks to blld for his answer.

Thrombin answered 24/10, 2019 at 14:22 Comment(3)
I am having same type of issue in showing english decimal pad. My app's language is in arabic and I want my text field to show english decimal pad. I have done the above mentioned steps by overriding these vars and methods. In textInputMode, I return "en-US" mode only, but still it shows arabic decimal pad in iOS 13.Shiite
I can confirm that this doesn't seem to work anymore for iOS 13.2...Whooper
@JayLee Make sure you have the Emoji keyboard enabledThrombin
A
10

I filed a radar on this for iOS 13 because I have a bilingual Japanese/English app. Some fields are Japanese and some English so obviously it makes sense to present the right keyboard type to the user instead of making them flip back and forth 20 times.

There was a workaround for this, and that was that after the UIKit calls 'textInputMode', in the main thread you could do this:

// has to be done after the textInputMode method is called
if #available(iOS 13, *) {
    textField.keyboardType = textField.keyboardType
} 

This forces the keyboard to reload after answering with the textInputMode that you wanted. I informed them of the bug, and the workaround to get correct behavior.

So in iOS 13.1 the bug was not fixed, however they blocked my workaround.

Nice. I won't report any bugs to them again. Rather if I find a workaround I will just use it.

So it seems like they now are silently disabling this feature. And it is a feature, this is literally the purpose of this method call, to find out what input mode should be presented to the user.

It still works ok though if you have another language and want to select English.

So if my user sets Japanese as the keyboard selection then I can force an English keyboard up. Just not the other way around. Any attempts to get a Japanese input mode end up in an English keyboard.

EDIT:

There is another path that you can work around this, but it involves discovery and use of internal API which is not straightforward. You'd have to essentially find the functions used to manage the results of hitting the globe button. If you do that you're essentially simulating the user's taps and it has wide ranging effects, that is, the keyboard will be changed for other apps too. So it's not recommended, 100% it will fail App Store submission. I don't want to post it because of the results of my last workaround.

I think it's not possible to understand Apple very easily. All I know is that:

  1. the API is not functioning as published
  2. it was reported and they did not fix the bug
  3. since the time of reporting they broke (intentionally or not) the workaround

So future workarounds should be hoarded until their intentions are clear and/or they fix this bug (which is what they should do). Simply revoking part of the API without publishing the change is a major bug.

Aerobic answered 3/10, 2019 at 1:28 Comment(2)
Thanks for this! It has helped me understand this a bit more. I doubt they purposely blocked your workaround, this feels more like a bug to me. If they wanted to remove the feature they could of deprecated it.Thrombin
"Never attribute to malice that which is adequately explained by stupidity."Thrombin
B
10

You need to set textinputcontextidentifier on the textField so that iOS knows where to save the custom textInputMode

It isn't written in the doc but it works.

ref: https://developer.apple.com/documentation/uikit/uiresponder/1621091-textinputcontextidentifier

Byrle answered 24/10, 2019 at 8:45 Comment(2)
This worked for me on iOS 13. Just returning "emoji" or "" for textInputContextIdentifier in my custom UITextField shows the Emoji keyboard (when combined with the textInputMode override in the question). Thanks for the tip on the hidden docs. 👍Thant
Doesn't work when we want to enforce english decimal pad for a UITextField when app's localization is in Arabic.Shiite
T
10

NB: Make sure you have the Emoji keyboard enabled.

This seems to be an iOS 13 bug, the work around (for devices, this does not affect the Simulator) is to override the textInputContextIdentifier property and return a non-nil value.

//
//  ViewController.swift
//  Keyboard Info
//
//  Created by Richard Stelling on 30/09/2019.
//  Copyright © 2019 Richard Stelling. All rights reserved.
//

import UIKit

class TestButton: UIButton, UIKeyInput {

    var hasText: Bool = true

    override var textInputContextIdentifier: String? { "" } // return non-nil to show the Emoji keyboard ¯\_(ツ)_/¯ 

    func insertText(_ text: String) { print("\(text)") }

    func deleteBackward() {}

    override var canBecomeFirstResponder: Bool { return true }

    override var canResignFirstResponder: Bool { return true }

    override var textInputMode: UITextInputMode? {
        for mode in UITextInputMode.activeInputModes {
            if mode.primaryLanguage == "emoji" {
                return mode
            }
        }
        return nil
    }
}

Thanks to blld for his answer.

Thrombin answered 24/10, 2019 at 14:22 Comment(3)
I am having same type of issue in showing english decimal pad. My app's language is in arabic and I want my text field to show english decimal pad. I have done the above mentioned steps by overriding these vars and methods. In textInputMode, I return "en-US" mode only, but still it shows arabic decimal pad in iOS 13.Shiite
I can confirm that this doesn't seem to work anymore for iOS 13.2...Whooper
@JayLee Make sure you have the Emoji keyboard enabledThrombin
M
1

do Simply

class EmojiTextField: UITextField {

   // required for iOS 13
   override var textInputContextIdentifier: String? { "" } // return non-nil to show the Emoji keyboard ¯\_(ツ)_/¯ 

    override var textInputMode: UITextInputMode? {
        for mode in UITextInputMode.activeInputModes {
            if mode.primaryLanguage == "emoji" {
                return mode
            }
        }
        return nil
    }

override init(frame: CGRect) {
        super.init(frame: frame)

        commonInit()
    }

    required init?(coder: NSCoder) {
        super.init(coder: coder)

         commonInit()
    }

    func commonInit() {
        NotificationCenter.default.addObserver(self,
                                               selector: #selector(inputModeDidChange),
                                               name: UITextInputMode.currentInputModeDidChangeNotification,
                                               object: nil)
    }

    @objc func inputModeDidChange(_ notification: Notification) {
        guard isFirstResponder else {
            return
        }

        DispatchQueue.main.async { [weak self] in
            self?.reloadInputViews()
        }
    }
}
Mariettamariette answered 25/8, 2021 at 6:10 Comment(1)
for me the accepted answer did not work with UIButton, UITextField did work wellChristiachristian

© 2022 - 2024 — McMap. All rights reserved.