是否可以通过 UI 测试中的代码 "toggle software keyboard"?

Is it possible to "toggle software keyboard" via the code in UI test?

我有 UI 测试登录功能(并用它来测试其他东西),但有时当焦点从一个字段更改到另一个字段时 - 键盘隐藏,虽然光标在该字段,我在 field.typeText - no focused fields to fill.

上出错

我不知何故意识到,单击 Hardware -> Keyboard -> toggle software keyboard 会使键盘持续显示在屏幕上,因此测试运行良好。但我需要让它在任何测试设备、任何开发人员机器上工作,所以我想以编程方式设置此选项,而不烦人 "if test fails, go to … and set … by hand" 在项目的自述文件中。

可能吗?

在 Xcode 9 之前,您可以通过在 Simulator.app 中禁用硬件键盘来解决此问题,这将导致软件键盘始终存在。例如:

defaults write com.apple.iphonesimulator ConnectHardwareKeyboard -bool NO

模拟器的 .plist 文件已更改以添加对多个模拟器的支持。 ConnectHardwareKeyboard 布尔值现在嵌套在设备的 UDID 下。幸运的是,这个 UDID 也存储在 plist 文件中。您可以在 UITest 目标的构建阶段下使用 'run script' 添加此代码。

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  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

根据 Brooks 的精彩回答,这将适用于所有模拟器:

/usr/libexec/PlistBuddy -c "Print :DevicePreferences" ~/Library/Preferences/com.apple.iphonesimulator.plist | perl -lne 'print  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

测试 Xcode 10.1 我尝试了不同的方法,但其中 none 解决了如何获取模拟器 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

对于 Xcode 10.2,这些解决方案中的 none 对我有用,plist 已正确更改但键盘一直隐藏。如果未显示键盘,我必须使用 oascript 在模拟器上按 Ctrl + Shift + K。这不是美,但它是唯一有效的解决方法。

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

已在 Xcode 10.3 和 Xcode 11 中测试。下面的代码片段需要位于应用程序目标中(不是测试包)——因为例如,在 AppDelegate.swift 中。它将通过将任何 UIKeyboardInputModeautomaticHardwareLayout 属性设置为 nil.

来禁用任何硬件键盘自动连接

Does not depend on the settings of the Simulator.

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

或Objective-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

受上面 real_kappa_guy s 的启发,我通过检查键盘是否启用然后 运行 苹果脚本发送键盘快捷键,设法在不重启模拟器的情况下做到这一点Cmd-shift-k(需要加入预测试动作):

if test `/usr/libexec/PlistBuddy -c "Print DevicePreferences:${TARGET_DEVICE_IDENTIFIER}:ConnectHardwareKeyboard" ~/Library/Preferences/com.apple.iphonesimulator.plist` == true; then 
osascript <<EOD
  tell application "Simulator" to activate
  tell application "System Events"
      keystroke "K" using {command down, shift down}
  end tell
EOD
fi