Можно ли "переключать программную клавиатуру" через код в тесте UI?

У меня есть тесты пользовательского интерфейса, которые проверяют функциональность входа в систему (и используют его для тестирования других вещей), но иногда, когда фокус изменяется из одного поля в другое - клавиатура скрывается, и хотя курсор мигает в поле, я получаю ошибку на field.typeText - no focused fields to fill.

Как-то я понял, что нажатие на Hardware -> Keyboard -> toggle software keyboard делает клавиатуру устойчивой на экране, поэтому тест работает хорошо. Но мне нужно заставить его работать на любом тестовом устройстве на любой машине разработчика, поэтому я хочу установить эту опцию программно, не раздражая "если тест не сработает, перейдите в... и установите... вручную" в readme проекта.

Возможно ли это?

Ответ 1

Файл симулятора .plist изменен, чтобы добавить поддержку нескольких симуляторов. Логическое значение ConnectHardwareKeyboard теперь вложено в UDID устройства. К счастью, этот UDID также хранится в файле plist. Вы можете добавить этот код, используя 'run script' на ваших целевых этапах сборки UITest.

Xcode 9 ответ:

#grab the UDID from the plist
UDID=$(defaults read com.apple.iphonesimulator CurrentDeviceUDID)

#overwrite the existing value with false
#OR if the plist doesn't have that value add it in
/usr/libexec/PlistBuddy -c "Set :DevicePreferences:$UDID:ConnectHardwareKeyboard 
false" ~/Library/Preferences/com.apple.iphonesimulator.plist 
|| 
/usr/libexec/PlistBuddy -c  "Add :DevicePreferences:$UDID:ConnectHardwareKeyboard
bool false" ~/Library/Preferences/com.apple.iphonesimulator.plist

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

/usr/libexec/PlistBuddy -c "Print :DevicePreferences" ~/Library/Preferences/com.apple.iphonesimulator.plist | perl -lne 'print $1 if /^    (\S*) =/' | while read -r a; do /usr/libexec/PlistBuddy -c "Set :DevicePreferences:$a:ConnectHardwareKeyboard
false" ~/Library/Preferences/com.apple.iphonesimulator.plist || /usr/libexec/PlistBuddy -c  "Add :DevicePreferences:$a:ConnectHardwareKeyboard
bool false" ~/Library/Preferences/com.apple.iphonesimulator.plist; done

Ответ 2

До Xcode 9 вы можете обойти это, отключив аппаратную клавиатуру в Simulator.app, что приведет к тому, что программная клавиатура будет всегда присутствовать. Например:

defaults write com.apple.iphonesimulator ConnectHardwareKeyboard -bool NO

Ответ 3

После Брукса отличный ответ, это будет работать для всех симуляторов:

/usr/libexec/PlistBuddy -c "Print :DevicePreferences" ~/Library/Preferences/com.apple.iphonesimulator.plist | perl -lne 'print $1 if /^    (\S*) =/' | while read -r a; do /usr/libexec/PlistBuddy -c "Set :DevicePreferences:$a:ConnectHardwareKeyboard
false" ~/Library/Preferences/com.apple.iphonesimulator.plist || /usr/libexec/PlistBuddy -c  "Add :DevicePreferences:$a:ConnectHardwareKeyboard
bool false" ~/Library/Preferences/com.apple.iphonesimulator.plist; done

Ответ 4

Протестировано в Xcode 10.3 & Xcode 11. Приведенный ниже фрагмент кода должен находиться в целевом приложении (, а не в тестовом комплекте) - например, в AppDelegate.swift. Он отключит автоматическое подключение любых аппаратных клавиатур, установив для любых свойств UIKeyboardInputMode automaticHardwareLayout значение nil.

🔥 Не зависит от настроек симулятора.

📌 Note: This appears fixed in Simulator 11.0 (Xcode 11).

#if targetEnvironment(simulator)
// Disable hardware keyboards.
let setHardwareLayout = NSSelectorFromString("setHardwareLayout:")
UITextInputMode.activeInputModes
    // Filter 'UIKeyboardInputMode's.
    .filter({ $0.responds(to: setHardwareLayout) })
    .forEach { $0.perform(setHardwareLayout, with: nil) }
#endif

Или цель-c:

#if TARGET_IPHONE_SIMULATOR
SEL setHardwareLayout = NSSelectorFromString(@"setHardwareLayout:");
for (UITextInputMode *inputMode in [UITextInputMode activeInputModes]) {
    if ([inputMode respondsToSelector:setHardwareLayout]) {
        // Note: 'performSelector:withObject:' will complain, so we have to use some black magic.
        ((void (*)(id, SEL, id))[inputMode methodForSelector:setHardwareLayout])(inputMode, setHardwareLayout, NULL);
    }
}
#endif

Ответ 5

Протестировано с Xcode 10.1 Я пробовал разные подходы, но ни один из них не решает, как получить UDID симулятора

#Find the UDID of the booted simulator
#And use PlistBuddy to change the flag to true or false
#Set the variable useHardwareKeyboard with the desired result
#Relaunch the simulator
useHardwareKeyboard=false
export UDID=$(xcrun simctl list devices | grep "(Booted)" | grep -E -o -i "([0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12})")
/usr/libexec/PlistBuddy -c "Set :DevicePreferences:$UDID:ConnectHardwareKeyboard ${useHardwareKeyboard}" ~/Library/Preferences/com.apple.iphonesimulator.plist
xcrun simctl shutdown $UDID
xcrun simctl boot $UDID

Вы также можете проверить эти изменения.

Найдите свой UDID симулятора: (Подробнее здесь: https://nshipster.com/simctl/)

xcrun simctl list devices | grep "(Booted)" | grep -E -o -i "([0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12})"

Запустите одну из этих команд и найдите изменения на основе UDID сверху:

defaults read com.apple.iphonesimulator
#OR
open ~/Library/Preferences/com.apple.iphonesimulator.plist

Ответ 6

Для xcode 10.2 ни одно из этих решений не работает для меня, plist изменен правильно, но клавиатура пока скрыта. Я должен использовать oascript, чтобы нажать Ctrl + Shift + K на симуляторе, если клавиатура не отображается. Это не красота, но это единственный обходной путь, который работает.

tell application "Simulator" to activate
tell application "System Events"
    keystroke "K" using {command down, shift down}
end tell