Как узнать текущую клавиатуру, используемую на iOS8?

Вы можете получить список клавиатур, установленных на устройстве iOS, используя:

NSUserDefaults *userDeafaults = [NSUserDefaults standardUserDefaults];
NSDictionary * userDefaultsDict = [userDeafaults dictionaryRepresentation];
NSLog(@"%@", userDefaultsDict);

Это дает что-то в консоли, например:

{
    ...
    AppleKeyboards =     (
        "[email protected]=US;sw=QWERTY",
        "[email protected]=Spanish - ISO;sw=QWERTY-Spanish",
        "[email protected]=Emoji",
        "com.swiftkey.SwiftKeyApp.Keyboard"
    );
    AppleKeyboardsExpanded = 1;
    ...
}

Это говорит мне, что на устройстве установлены испанские, Emoji и SwiftKey, но он ничего не говорит о том, что будет использоваться, когда клавиатура подходит.

Есть ли способ рассказать?

Ответ 1

Для этого нет общедоступного API, но я нашел для вас решение, которое требует очень мало "API серых областей" (я определяю API как "серая область", если API обычно не отображается, но может быть скрыт с помощью мало что не работает).

iOS имеет следующий класс: UITextInputMode

Этот класс дает вам все методы ввода, которые пользователь может использовать. Использование следующего запроса даст вам используемое в настоящее время значение только при открытой клавиатуре:

UITextInputMode* inputMode = [[[UITextInputMode activeInputModes] filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"isDisplayed = YES"]] lastObject];

Чтобы получить отображаемое имя расширения (или обычной клавиатуры Apple), используйте:

[inputMode valueForKey:@"displayName"]

или

[inputMode valueForKey:@"extendedDisplayName"]

Это работает только тогда, когда клавиатура видна. Таким образом, вам придется самостоятельно контролировать изменение режима ввода, используя

[[NSNotificationCenter defaultCenter] addObserverForName:UITextInputCurrentInputModeDidChangeNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note)
 {
     dispatch_async(dispatch_get_main_queue(), ^{
         NSLog(@"%@", [[[[UITextInputMode activeInputModes] filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"isDisplayed = YES"]] lastObject] valueForKey:@"extendedDisplayName"]);
     });
 }];

Нам действительно нужно отложить получение текущего режима ввода, поскольку уведомление отправляется до того, как внутренняя реализация клавиатуры обновила систему с новым значением. Получение его на следующей runloop хорошо работает.

Ответ 2

Ответ на Leo Natan велик, но я хотел бы что-то добавить к нему. Фактически вы можете получить текущий режим ввода в любое время, а не только когда клавиатура открыта, например:

UITextView *textView = [[UITextView alloc] init];
UITextInputMode *inputMode = textView.textInputMode;

Обратите внимание, что для клавиатуры Emoji textView.textInputMode есть nil по умолчанию.

Кроме того, в дополнение к displayName и extendedDisplayName есть другие ключи, которые вы можете получить, например identifier, normalizedIdentifier (iOS 8+), hardwareLayout,... См. полный API здесь:

https://github.com/nst/iOS-Runtime-Headers/blob/master/Frameworks/UIKit.framework/UIKeyboardInputMode.h

Теперь я не уверен, что использование любого из них более рискованно, чем displayName для утверждения App Store...

Ответ 3

@Leo Ответ Natan классный, но он может вернуться nil, когда клавиатура не отображается.

Итак, здесь я использую строку, чтобы найти свойство UIKeyboardInputMode.

Я могу сказать, что это может узнать текущую клавиатуру, потому что она исходит от Apple Private API.

Код здесь:

+ (BOOL)isTheCustomKeyboard
{
    UITextInputMode* inputMode = [UITextInputMode currentInputMode];
    if ([inputMode respondsToSelector:NSSelectorFromString(@"identifier")])
    {
        NSString* indentifier = [inputMode performSelector:NSSelectorFromString(@"identifier")];
        if ([indentifier isEqualToString: YOUR_APP_ID])
        {
            return YES;
        }
    }
   return NO;
}

И еще:

+ (BOOL)isContaintCustomKeyboard
{
    NSArray * inputModes = [UITextInputMode activeInputModes];
    for (id inputModel in inputModes)
    {
        if ([inputModel respondsToSelector:NSSelectorFromString(@"identifier")])
        {
            NSString* indentifier = [inputModel performSelector:NSSelectorFromString(@"identifier")];
            if ([indentifier isEqualToString: YOUR_APP_ID])
            {
                return YES;
            }
        }
    }
    return NO;
}

На самом деле мы также можем использовать displayName или identifier и многое другое.

Ответ 4

у меня работает Swift 5.0

 NotificationCenter.default.addObserver(self, selector: #selector(keyBoardChanged(_:)), name:UITextInputMode.currentInputModeDidChangeNotification, object: nil)

  @objc func keyBoardChanged(_ notification: NSNotification){
    if let identifier = textField.textInputMode?.perform(NSSelectorFromString("identifier"))?.takeUnretainedValue() as? String{
        if identifier == "YOUR APP IDENTIFIER"{
            //Do Whatever you required :) 
        }
    }
 }