问题
I have UI tests which testing login functionality (and uses it to test other stuff), but sometimes when focus is changed from one field to another - the keyboard hides, and although the cursor is blinking in the field, I getting error on field.typeText
- no focused fields to fill
.
Somehow I realized, that clicking on a Hardware -> Keyboard -> toggle software keyboard
makes keyboard to persist on the screen, so test is works well. But I need to make it working on any testing device, on any developer machine, so I want to set this option programmatically without annoying "if test fails, go to … and set … by hand" in readme of the project.
Is it possible?
回答1:
The simulator's .plist file changed to add support for multiple simulators. The ConnectHardwareKeyboard boolean is now nested underneath the device's UDID. Luckily this UDID is also stored in the plist file. You can add this code using 'run script' under your UITest target's build phases.
Xcode 9 answer:
#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
Or you can use this other code to affect all simulators:
/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:
Prior to Xcode 9, you can work around this by disabling the hardware keyboard in Simulator.app which will cause the software keyboard to always be present. Eg:
defaults write com.apple.iphonesimulator ConnectHardwareKeyboard -bool NO
回答3:
Tested in Xcode 10.3 & Xcode 11. The snippet below needs to be located in the app target (not the test bundle) — for instance, in AppDelegate.swift. It will disable any hardware keyboards from automatically connecting by setting any UIKeyboardInputMode
's automaticHardwareLayout
properties to nil
.
🔥 Does not depend on the settings of the Simulator.
📌 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
Or 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
回答4:
Following Brooks great answer, this will work for all simulators:
/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
回答5:
Tested with Xcode 10.1 I tried different approaches but none of them solve how to get the simulator 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
You can also verify these changes.
Find your simulator UDID: (More here: 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})"
Run one of these commands and find your changes based on the UDID from above:
defaults read com.apple.iphonesimulator
#OR
open ~/Library/Preferences/com.apple.iphonesimulator.plist
回答6:
For Xcode 10.2, none of these solutions work for me, the plist
is changed correctly but keyboard is till hidden. I have to use oascript to press Ctrl + Shift + K on Simulator if the keyboard is not displayed. It's not beauty but it's the only workaround that works.
tell application "Simulator" to activate
tell application "System Events"
keystroke "K" using {command down, shift down}
end tell
来源:https://stackoverflow.com/questions/38010494/is-it-possible-to-toggle-software-keyboard-via-the-code-in-ui-test