appium无法使用send_keys时的解决办法
用appium做手机app自动化时,对于有的输入框是无法用send_keys方法的。报错信息类似"io.appium.uiautomator2.common.exceptions.InvalidElementStateException: Cannot set the element. Did you interact with the correct element"
E io.appium.uiautomator2.common.exceptions.InvalidElementStateException: Cannot set the element to 'xxx'. Did you interact with the correct element?
E at io.appium.uiautomator2.handler.SendKeysToElement.setText(SendKeysToElement.java:87)
E at io.appium.uiautomator2.handler.SendKeysToElement.safeHandle(SendKeysToElement.java:115)
E at io.appium.uiautomator2.handler.request.SafeRequestHandler.handle(SafeRequestHandler.java:59)
E at io.appium.uiautomator2.server.AppiumServlet.handleRequest(AppiumServlet.java:259)
E at io.appium.uiautomator2.server.AppiumServlet.handleHttpRequest(AppiumServlet.java:253)
E at io.appium.uiautomator2.http.ServerHandler.channelRead(ServerHandler.java:77)
E at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:366)
E at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:352)
E at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:345)
E at io.netty.handler.codec.MessageToMessageDecoder.channelRead(MessageToMessageDecoder.java:102)
E at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:366)
E at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:352)
E at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:345)
E at io.netty.channel.CombinedChannelDuplexHandler$DelegatingChannelHandlerContext.fireChannelRead(CombinedChannelDuplexHandler.java:435)
E at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:293)
E at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:267)
E at io.netty.channel.CombinedChannelDuplexHandler.channelRead(CombinedChannelDuplexHandler.java:250)
E at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:366)
E at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:352)
E at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:345)
E at io.netty.handler.timeout.IdleStateHandler.channelRead(IdleStateHandler.java:266)
E at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:366)
E at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:352)
E at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:345)
E at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1294)
E at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:366)
E at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:352)
E at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:911)
E at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:131)
E at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:611)
E at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:552)
E at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:466)
E at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:438)
E at io.netty.util.concurrent.SingleThreadEventExecutor$2.run(SingleThreadEventExecutor.java:140)
E at io.netty.util.concurrent.DefaultThreadFactory$DefaultRunnableDecorator.run(DefaultThreadFactory.java:144)
E at java.lang.Thread.run(Thread.java:1012) (conftest.py:147)
错误原因未明确,有的说是该输入框有额外的输入校验,有的说不允许键盘外的行为。
不过表现就在于常规的send_keys方法不起作用,反而导致了异常退出。
这个时候可以换做press_keycode来完成输入行为。但keycode需要对应到编码,于是做了一个对应的字典。类似如下。需要注意的是,大写字母和小写字母并不是不同的编码值,如果需要输入大写字母A,则是小写字母a加上shift键,比如driver.press_keycode(29, 59)
class TextField
......
def input(self, value, **kwargs):
......
try:
el.send_keys(value)
except Exception as e:
if str(e).find("InvalidElementStateException") > 0:
for v in str(value):
if v.isalpha() and v.isupper():
self.driver.press_keycode(self.keycodes_mapping(v), 59)
else:
self.driver.press_keycode(self.keycodes_mapping(v))
@staticmethod
def keycodes_mapping(value):
mapping = {"0": 7, "1": 8, "2": 9, "3": 10, "4": 11, "5": 12, "6": 13, "7": 14, "8": 15, "9": 16,
"a": 29, "b": 30, "c": 31, "d": 32, "e": 33, "f": 34, "g": 35, "h": 36, "i": 37, "j": 38, "k": 39,
"l": 40, "m": 41, "n": 42, "o": 43, "p": 44, "q": 45, "r": 46, "s": 47, "t": 48, "u": 49, "v": 50,
"w": 51, "x": 52, "y": 53, "z": 54, "@": 77, "=": 70, ",": 55, "-": 69, "+": 81, "#": 18, " ": 62,
";": 74, "*": 17, ".": 56}
return mapping[value]