appiumpython python appiumpython 用 uiautomator2 后报错

Appium的实用方法都藏在Client的源码里,我尝试在这里剖析一下Client的源码,第一篇,我们直接从大家最关注的元素查找说起。
注意!对于driver和webelement实例,均有对应的元素查找方法(webelement查找的是下面的子元素),本文讨论的元素查找针对的是driver实例。
源码版本:0.9
mobileby.py
OK,现在假如我们需要自定义一些find方法,比如find_element_by_xxxx,我们该怎么做?我们看到,appium提供了一些扩展的find方法,它有它自己的一套方式,例如ACCESSIBILITY_ID等,要想自定义实现这些方法,appium首先做的就是:自定义一个MobileBy类,这个类从By类中继承,然后添加一些需要的属性,这些属性的value就是一些文本,不用担心他们不起作用,假如你熟悉webdriver的原理,应该会更好地理解。(不知道的同学可以戳这里: 或者)
#!/usr/bin/env python
from selenium.webdriver.common.by import By
class MobileBy(By): #这里显然是一个继承
"""三个扩展属性,清清楚楚地罗列在这里"""
IOS_UIAUTOMATION = '-ios uiautomation'
ANDROID_UIAUTOMATOR = '-android uiautomator'
ACCESSIBILITY_ID = 'accessibility id'
既然他继承自By类,我们直接戳到By类看一下,因为By类中还有一个classmethod下面会用到:
class By(object):
Set of supported locator strategies.
XPATH = "xpath"
LINK_TEXT = "link text"
PARTIAL_LINK_TEXT = "partial link text"
NAME = "name"
TAG_NAME = "tag name"
CLASS_NAME = "class name"
CSS_SELECTOR = "css selector"
@classmethod #好吧,我是一个类方法,下文中会用到我
def is_valid(cls, by): #cls是把类对象本身传进来
for attr in dir(cls):
if by == getattr(cls, attr): #判断是不是可用的查找方式
return True
return False
这个MobileBy类在哪边起作用?我们去跟踪一下,来到这里:
appium的webdriver.py
def find_element_by_ios_uiautomation(self, uia_string):
"""Finds an element by uiautomation in iOS.
- uia_string - The element name in the iOS UIAutomation library
driver.find_element_by_ios_uiautomation('.elements()[1].cells()[2]')
#这里直接访问Appium自己定义的几个类属性
return self.find_element(by=By.IOS_UIAUTOMATION, value=uia_string)
def find_elements_by_ios_uiautomation(self, uia_string):
"""Finds elements by uiautomation in iOS.
- uia_string - The element name in the iOS UIAutomation library
driver.find_elements_by_ios_uiautomation('.elements()[1].cells()[2]')
return self.find_elements(by=By.IOS_UIAUTOMATION, value=uia_string)
def find_element_by_android_uiautomator(self, uia_string):
"""Finds element by uiautomator in Android.
- uia_string - The element name in the Android UIAutomator library
driver.find_element_by_android_uiautomator('.elements()[1].cells()[2]')
return self.find_element(by=By.ANDROID_UIAUTOMATOR, value=uia_string)
def find_elements_by_android_uiautomator(self, uia_string):
"""Finds elements by uiautomator in Android.
- uia_string - The element name in the Android UIAutomator library
driver.find_elements_by_android_uiautomator('.elements()[1].cells()[2]')
return self.find_elements(by=By.ANDROID_UIAUTOMATOR, value=uia_string)
def find_element_by_accessibility_id(self, id):
"""Finds an element by accessibility id.
- id - a string corresponding to a recursive element search using the
Id/Name that the native Accessibility options utilize
driver.find_element_by_accessibility_id()
return self.find_element(by=By.ACCESSIBILITY_ID, value=id)
def find_elements_by_accessibility_id(self, id):
"""Finds elements by accessibility id.
- id - a string corresponding to a recursive element search using the
Id/Name that the native Accessibility options utilize
driver.find_elements_by_accessibility_id()
return self.find_elements(by=By.ACCESSIBILITY_ID, value=id)
所以,我们现在知道了,appium的这些扩展方法都是通过继承webdriver.Remote类来直接扩展的,appium扩展了webdriver.Remote来满足他的需求,我们尝试去追踪一下find_element和find_elements这两个核心方法!
selenium的webdriver.py
OK,我们终于来到实现的主体(核心)部分:find_element,find_elements:
def find_element(self, by=By.ID, value=None):
'Private' method used by the find_element_by_* methods.
Use the corresponding find_element_by_* instead of this.
:rtype: WebElement
if not By.is_valid(by) or not isinstance(value, str):
raise InvalidSelectorException("Invalid locator values passed in")
return self.execute(Command.FIND_ELEMENT,
{'using': by, 'value': value})['value']
def find_elements(self, by=By.ID, value=None):
'Private' method used by the find_elements_by_* methods.
Use the corresponding find_elements_by_* instead of this.
:rtype: list of WebElement
if not By.is_valid(by) or not isinstance(value, str):
raise InvalidSelectorException("Invalid locator values passed in")
return self.execute(Command.FIND_ELEMENTS,
{'using': by, 'value': value})['value']
OK,我们从头到尾再试着理一下:
appium为了实现自己的find查找方式,首先自定义了一个MobileBy类,给这个类对象塞入了它定义的一些扩展属性,这些属性的值会通过webdriver协议推送到server端去识别和执行,为了让这些属性运用到find方法中,appium很好地继承和扩展了webdriver.Remote,然后通过调用driver实例的find_element和find_elements两个核心方法实现元素查找,所以,既然是扩展,appiumdriver实例可以使用seleniumdriver的所有关于元素查找的实例方法,他们的列表我们就可以整理出来了
seleniumdriver
find_element_by_id
find_elements_by_id
find_element_by_name
find_elements_by_name
find_element_by_link_text
find_elements_by_link_text
find_element_by_partial_link_text
find_elements_by_partial_link_text
find_element_by_tag_name
find_elements_by_tag_name
find_element_by_xpath
find_elements_by_xpath
find_element_by_class_name
find_elements_by_class_name
find_element_by_css_selector
find_elements_by_css_selector
appiumdriver
find_element_by_ios_uiautomation
find_elements_by_ios_uiautomation
find_element_by_android_uiautomator
find_elements_by_android_uiautomator
find_element_by_accessibility_id
find_elements_by_accessibility_id
Appium基础篇7-元素定位之by_android_uiautomator
这篇开始陆续介绍各种元素定位方式,如果学习过Selenium的朋友,就很清楚Selenium有八种方式支持元素定位。其实在appium也有多中方式支持元素定位,有些定位方法是共有的,有些定位方式只能在...
Appium基于安卓的各种FindElement的控件定位方法实践和建议
AppiumDriver的各种findElement方法的尝试,尝试的目标应用是SDK自带的Notepad应用。
1. findElementByName
使用Appium进行Android自动化测试 - 通过UI Automator方式查找元素
一. Appium中使用UI Automator查找元素的方法1. 直接使用driver.find_element_by_android_uiautomator(UIAutomator locator...
Appium定位方法之findElementByAndroidUIAutomator
WebElement two =driver.findElementByAndroidUIAutomator(&new UiSelector().className(\&andro...
转载地址: https://blog.csdn.net/liusuihui/article/details/
https://blog.csdn.net/x...
笔记升级到了1.8.0之后 一直在维护web(selenium) 搁浅了一段时间,差不多稳定了 现在开始写appium 现在因该好写 坑都被大佬们填完了,进入主题appium 1.8 支持的格式如下图...
文章为转载,感谢各位前辈的整理和努力
android uiautomator text定位
可能有人不知道为什么说android uiautomator是终极定位,而且android uiaut...
没有更多推荐了,解决 Appium 使用 UiAutomator2 带来的 keyevent 无法识别问题 - 简书
解决 Appium 使用 UiAutomator2 带来的 keyevent 无法识别问题
最近将appium更新到了1.6.5,uiautomator2确实能实现对Android toast内容的断言。但后续发现之前的wd.pressDeviceKey()方法不起作用。
wd@1.3.0添加了press_keycode的路由,修复了这个bug
POST /session/:sessionId/appium/device/press_keycode
Send key event to device (mjsonWire).
pressKeycode(keycode, metastate, cb) -& cb(err)
metastate is optional.
首先分析appium server的日志:
10:10:14:838 - info: [HTTP] --& POST /wd/hub/session/744e508b-3f7c-446b-b75f-ac1/appium/device/keyevent {"keycode":4}
10:10:14:838 - info: [MJSONWP] Driver proxy active, passing request on via HTTP proxy
10:10:14:838 - info: [debug] [JSONWP Proxy] Proxying [POST /wd/hub/session/744e508b-3f7c-446b-b75f-ac1/appium/device/keyevent] to [POST http://localhost:8200/wd/hub/session/ac-409d-a89d-c9ab578af2b4/appium/device/keyevent] with body: {"keycode":4}
10:10:14:947 - error: [MJSONWP] Encountered internal error running command: Error: Could not proxy. Proxy error: Could not proxy command to remote server. Original error: 404 - undefined
at doJwpProxy$ (C:\Users\lichen2\AppData\Local\Programs\appium-desktop\resources\app\node_modules\appium\node_modules\appium-base-driver\lib\mjsonwp\mjsonwp.js:354:13)
at tryCatch (C:\Users\lichen2\AppData\Local\Programs\appium-desktop\resources\app\node_modules\appium\node_modules\babel-runtime\regenerator\runtime.js:67:40)
at GeneratorFunctionPrototype.invoke [as _invoke] (C:\Users\lichen2\AppData\Local\Programs\appium-desktop\resources\app\node_modules\appium\node_modules\babel-runtime\regenerator\runtime.js:315:22)
at GeneratorFunctionPrototype.prototype.(anonymous function) [as throw] (C:\Users\lichen2\AppData\Local\Programs\appium-desktop\resources\app\node_modules\appium\node_modules\babel-runtime\regenerator\runtime.js:100:21)
at GeneratorFunctionPrototype.invoke (C:\Users\lichen2\AppData\Local\Programs\appium-desktop\resources\app\node_modules\appium\node_modules\babel-runtime\regenerator\runtime.js:136:37)
10:10:14:947 - info: [HTTP] &-- POST /wd/hub/session/744e508b-3f7c-446b-b75f-ac1/appium/device/keyevent 500 119 ms - 274
日志显示,Appium server接收到了keyevent的POST请求,但转发出去时: Error: Could not proxy. Proxy error: Could not proxy command to remote server. Original error: 404 - undefined,很明显,404表示设备端的sever没有响应该请求。
出了问题,第一反应是去appium上翻Issue,确实有人提过同样的问题,但作者并没有给出Answer:
于是只能自己翻源码了,因为问题出在appium server发POST到uiautomator2 server时404,所以直接去appium-uiautomator2-server项目里看:
找到文件,该类看上去是注册路由的:
private void registerPostHandler() {
register(postHandler, new NewSession("/wd/hub/session"));
register(postHandler, new FindElement("/wd/hub/session/:sessionId/element"));
register(postHandler, new FindElements("/wd/hub/session/:sessionId/elements"));
register(postHandler, new Click("/wd/hub/session/:sessionId/element/:id/click"));
register(postHandler, new Click("/wd/hub/session/:sessionId/appium/tap"));
register(postHandler, new Clear("/wd/hub/session/:sessionId/element/:id/clear"));
register(postHandler, new RotateScreen("/wd/hub/session/:sessionId/orientation"));
register(postHandler, new RotateScreen("/wd/hub/session/:sessionId/rotation"));
register(postHandler, new PressBack("/wd/hub/session/:sessionId/back"));
register(postHandler, new SendKeysToElement("/wd/hub/session/:sessionId/element/:id/value"));
register(postHandler, new SendKeysToElement("/wd/hub/session/:sessionId/keys"));
register(postHandler, new Swipe("/wd/hub/session/:sessionId/touch/perform"));
register(postHandler, new TouchLongClick("/wd/hub/session/:sessionId/touch/longclick"));
register(postHandler, new OpenNotification("/wd/hub/session/:sessionId/appium/device/open_notifications"));
register(postHandler, new PressKeyCode("/wd/hub/session/:sessionId/appium/device/press_keycode"));
register(postHandler, new LongPressKeyCode("/wd/hub/session/:sessionId/appium/device/long_press_keycode"));
register(postHandler, new Drag("/wd/hub/session/:sessionId/touch/drag"));
register(postHandler, new AppStrings("/wd/hub/session/:sessionId/appium/app/strings"));
register(postHandler, new Flick("/wd/hub/session/:sessionId/touch/flick"));
register(postHandler, new ScrollTo("/wd/hub/session/:sessionId/touch/scroll"));
register(postHandler, new MultiPointerGesture("/wd/hub/session/:sessionId/touch/multi/perform"));
register(postHandler, new TouchDown("/wd/hub/session/:sessionId/touch/down"));
register(postHandler, new TouchUp("/wd/hub/session/:sessionId/touch/up"));
register(postHandler, new TouchMove("/wd/hub/session/:sessionId/touch/move"));
register(postHandler, new UpdateSettings("/wd/hub/session/:sessionId/appium/settings"));
register(postHandler, new NetworkConnection("/wd/hub/session/:sessionId/network_connection"));
发现上面代码里并没有对应wd: POST /session/:sessionId/appium/device/keyevent,只有register(postHandler, new PressKeyCode("/wd/hub/session/:sessionId/appium/device/press_keycode"));
所以,404的原因找到了,笔者也在上面的Issue里给作者提了,希望后面作者能更新下uiautomator2 server。
知道了问题原因,可以想到三种解决方案:
1.修改uiautomator2 server
对appium编译安装uiautomator2 server的过程没深入研究,尝试卸载原手机里的io.appium.uiautomator2.server程序,修改AppiumServlet,并没有起作用,所以这个解决方法我还是等作者吧。。
感谢Carl的提示,原来项目的Readme已经给出编译方法。
AS打开appium-uiautomator2-server项目,完成上面提到的AppiumServelt代码的修改
运行gradle clean assembleServerDebug assembleServerDebugAndroidTest,这里编译可能会遇到一些问题,我遇到的是:app的build.gradle中,配置了对sdk-manager-plugin的依赖,而阿里云的maven库里并没有收录这个项目。解决方法: 将相关配置的代码注释掉
gradle编译成功后,会在/app/build/outputs/apk/下生产两个apk:
1.appium-uiautomator2-server-v0.1.5.APK,执行命令的apk,(GitHub上已经更新到0.1.6)
2.appium-uiautomator2-server-debug-androidTest.apk,用于启动Server的apk
替换设备中的apk,可以手动安装,也可以替换appium下默认的apk。默认apk放在appium-uiautomator2-driver的uiautomator2目录下,替换之。还未结束,查看driver里的代码:
async installServerApk () {
// Installs the apks on to the device or emulator
let apkPackage = await this.getPackageName(apkPath);
// appending .test to apkPackage name to get test apk package name
let testApkPackage = apkPackage + '.test';
let isApkInstalled = await this.adb.isAppInstalled(apkPackage);
let isTestApkInstalled = await this.adb.isAppInstalled(testApkPackage);
if (isApkInstalled || isTestApkInstalled) {
//check server apk versionName
let apkVersion = await this.getAPKVersion(apkPath);
let pkgVersion = await this.getInstalledPackageVersion(apkPackage);
if (apkVersion !== pkgVersion) {
isApkInstalled =
isTestApkInstalled =
await this.adb.uninstallApk(apkPackage);
await this.adb.uninstallApk(testApkPackage);
if (!isApkInstalled) {
await this.signAndInstall(apkPath, apkPackage);
if (!isTestApkInstalled) {
await this.signAndInstall(testApkPath, testApkPackage);
uiautomator2-driver会去校验设备是否已安装以及对版本号进行判断,所以想替换设备里的版本,还需修改你编译apk的version,或者提前删除设备已经安装的。
2.修改wd代码
既然uiautomator2-Server路由中只有press_keycode,没有keyevent,那可以在wd里添加相应的Post方法。
找到你项目中node_modules里wd模块,在/lib/commands.js中添加代码如下:
* pressKeyCode(keycode, metastate, cb) -& cb(err)
* metastate is optional
* @jsonWire POST /session/:sessionId/appium/device/press_keycode
commands.pressKeyCode = function() {
var fargs = utils.varargs(arguments);
var cb = fargs.callback,
keycode = fargs.all[0],
metastate = fargs.all[1];
var data = {keycode: keycode};
if(metastate) { data.metastate = }
this._jsonWireCall({
method: 'POST'
, relPath: '/appium/device/press_keycode'
, data: data
, cb: simpleCallback(cb)
重启项目后,driver就可以调用pressKeyCode方法,appium server会将请求转发到/press_keycode,uiautomator2 server也就可以识别。
3.修改uiautomator2-driver
我们在分析appium-uiautomator2-driver时,发现作者其实是有写keyevent方法的,只不过调用的是adb:
// uiautomator2 doesn't support metastate for keyevents
commands.keyevent = async function (keycode, metastate) {
log.debug(`Ignoring metastate ${metastate}`);
await this.adb.keyevent(keycode);
那么怎么才能让appium直接调用这个方法呢,我们发现uiautomator2-driver的driver.js里有个数组:
// NO_PROXY contains the paths that we never want to proxy to UiAutomator2 server.
Add the list of paths that we never want to proxy to UiAutomator2 server.
// TODO: Need to segregate the paths better way using regular expressions wherever applicable.
// (Not segregating right away because more paths to be added in the NO_PROXY list)
const NO_PROXY = [
['POST', new RegExp('^/session/[^/]+/touch/multi/perform')],
['POST', new RegExp('^/session/[^/]+/touch/perform')],
['POST', new RegExp('^/session/[^/]+/element')],
['POST', new RegExp('^/session/[^/]+/appium/element/[^/]+/value')],
['POST', new RegExp('^/session/[^/]+/appium/element/[^/]+/replace_value')],
['GET', new RegExp('^/session/[^/]+/appium/[^/]+/current_activity')],
['POST', new RegExp('^/session/[^/]+/appium/[^/]+/start_activity')],
['POST', new RegExp('^/session/[^/]+/app/[^/]')],
['POST', new RegExp('^/session/[^/]+/location')],
['GET', new RegExp('^/session/[^/]+/appium/device/system_time')],
['POST', new RegExp('^/session/[^/]+/appium/settings')],
['GET', new RegExp('^/session/[^/]+/appium/settings')],
['POST', new RegExp('^/session/[^/]+/appium/device/app_installed')],
['POST', new RegExp('^/session/[^/]+/appium/device/lock')],
['POST', new RegExp('^/session/[^/]+/appium/app/close')],
['POST', new RegExp('^/session/[^/]+/appium/app/launch')],
['POST', new RegExp('^/session/[^/]+/appium/device/pull_file')],
['POST', new RegExp('^/session/[^/]+/appium/device/push_file')],
['POST', new RegExp('^/session/[^/]+/appium/app/reset')],
['POST', new RegExp('^/session/[^/]+/appium/app/background')],
['POST', new RegExp('^/session/[^/]+/appium/device/toggle_location_services')],
['POST', new RegExp('^/session/[^/]+/appium/device/is_locked')],
['POST', new RegExp('^/session/[^/]+/appium/device/unlock')],
['POST', new RegExp('^/session/[^/]+/appium/app/end_test_coverage')],
['GET', new RegExp('^/session/[^/]+/contexts')],
['POST', new RegExp('^/session/[^/]+/context')],
['GET', new RegExp('^/session/[^/]+/context')],
['POST', new RegExp('^/session/[^/]+/network_connection')],
['GET', new RegExp('^/session/[^/]+/network_connection')],
['POST', new RegExp('^/session/[^/]+/timeouts')],
['GET', new RegExp('^/session/[^/]+/screenshot')],
['GET', new RegExp('^/session/[^/]+/element/[^/]+/attribute')],
['GET', new RegExp('^/session/[^/]+/element/[^/]+/enabled')],
['GET', new RegExp('^/session/[^/]+/element/[^/]+/selected')],
['GET', new RegExp('^/session/[^/]+/element/[^/]+/displayed')],
['GET', new RegExp('^/session/[^/]+/element/[^/]+/name')],
['GET', new RegExp('^/session/(?!.*\/)')],
['POST', new RegExp('^/session/[^/]+/keys')],
['POST', new RegExp('^/session/[^/]+/appium/device/hide_keyboard')],
['POST', new RegExp('^/session/[^/]+/log')],
['POST', new RegExp('^/session/[^/]+/appium/device/remove_app')],
['GET', new RegExp('^/session/[^/]+/appium/device/is_keyboard_shown')]
注释里写了, 该数组维护的是不会转发到uiautomator2的路由,那么,我们只需要在该数组里添加:
['POST', new RegExp('^/session/[^/]+/appium/device/keyevent')]。
p.s,该方法修改的是appium server依赖的appium-uiatumator2-driver,修改后需通过命令行启动appium,桌面程序似乎是带有缓存自制的,直接运行修改的代码不会起作用。
1.contexts contexts(self): Returns the contexts within the current session. 返回当前会话中的上下文,使用后可以识别H5页面的控件 Usage: driver.contexts 用法: driver....
1.contexts(self):Returns the contexts within the current session.返回当前会话中的上下文,使用后可以识别H5页面的控件用法 2. current_context(self):Returns the curren...
在编写UI自动化测试脚本的时候,有时候定位页面元素去操作手机的方法可能会比较麻烦。例如,也许你只是想要一个返回效果,去定位页面返回后还要进行一系列定义、调用点击函数,此时直接使用手机的物理返回键就要方便许多。Appium可利用selenium去操作手机。 先记录自己辛苦百度...
本文章转载于搜狗测试 前几篇Appium的文章讲解了Appium的安装和运行,以及在安装运行过程中的报错及解决方案。从本章起,小编带领大家一起用Appium做一点事情。 要想点击操作一个app,我们需要获取到这个app的控件,定位元素的方法较多,有Appium Inspec...
ADB,即Android debug bridge,它是 Android 开发/测试人员不可替代的强大工具,也是 Android 设备玩家的好玩具。 From:GitHub - mzlogin/awesome-adb: ADB Usage Complete / ADB 用法...
D10 穿越霾海,回到北方的家。 今天的行程就是坐飞机,回家。飞机落地之前就感受到了雾霾的笼罩,什么也看不见,等到能看见点东西的时候,已经看到跑道了。真心佩服飞行员! 小结一下这次的旅行,算是一个交待。按照旅行社的算法,我们这次是十日游。一共坐了四次飞机,算是四飞。没有进店...
是,2017年刚开始,怎么就能判断是成长最大的一年呢?写这个标题,我也在想,但是没有办法掩盖内心这种真实的冲动,当然,我要把它变成现实。 why: 往往发现了问题,就是解决问题的开始。 而真正开始有了目标和执行方案,赋予它自己心动的价值,就会有动力一直行动下去(正面),这份...
也许不言是最好的途径 也许放弃是最好的结果 春花南苑,秋风淋漓 夏云北漂,冬雪畅翰 看一世之红尘,皆空
(-周三 00:52:08) Traditional linear reading is highly inefficient.&>&appium-uiautomator2-server-debug-androidTest.apk
appium-uiautomator2-server-debug-androidTest.apk
上传大小:1.73MB
appium1.6.3安装所需文件,因直接安装不容易下载成功,故提取出来,供需要的朋友下载使用。
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
综合评分:5
{%username%}回复{%com_username%}{%time%}\
/*点击出现回复框*/
$(".respond_btn").on("click", function (e) {
$(this).parents(".rightLi").children(".respond_box").show();
e.stopPropagation();
$(".cancel_res").on("click", function (e) {
$(this).parents(".res_b").siblings(".res_area").val("");
$(this).parents(".respond_box").hide();
e.stopPropagation();
/*删除评论*/
$(".del_comment_c").on("click", function (e) {
var id = $(e.target).attr("id");
$.getJSON('/index.php/comment/do_invalid/' + id,
function (data) {
if (data.succ == 1) {
$(e.target).parents(".conLi").remove();
alert(data.msg);
$(".res_btn").click(function (e) {
var parentWrap = $(this).parents(".respond_box"),
q = parentWrap.find(".form1").serializeArray(),
resStr = $.trim(parentWrap.find(".res_area_r").val());
console.log(q);
//var res_area_r = $.trim($(".res_area_r").val());
if (resStr == '') {
$(".res_text").css({color: "red"});
$.post("/index.php/comment/do_comment_reply/", q,
function (data) {
if (data.succ == 1) {
var $target,
evt = e || window.
$target = $(evt.target || evt.srcElement);
var $dd = $target.parents('dd');
var $wrapReply = $dd.find('.respond_box');
console.log($wrapReply);
//var mess = $(".res_area_r").val();
var mess = resS
var str = str.replace(/{%header%}/g, data.header)
.replace(/{%href%}/g, 'http://' + window.location.host + '/user/' + data.username)
.replace(/{%username%}/g, data.username)
.replace(/{%com_username%}/g, data.com_username)
.replace(/{%time%}/g, data.time)
.replace(/{%id%}/g, data.id)
.replace(/{%mess%}/g, mess);
$dd.after(str);
$(".respond_box").hide();
$(".res_area_r").val("");
$(".res_area").val("");
$wrapReply.hide();
alert(data.msg);
}, "json");
/*删除回复*/
$(".rightLi").on("click", '.del_comment_r', function (e) {
var id = $(e.target).attr("id");
$.getJSON('/index.php/comment/do_comment_del/' + id,
function (data) {
if (data.succ == 1) {
$(e.target).parent().parent().parent().parent().parent().remove();
$(e.target).parents('.res_list').remove()
alert(data.msg);
//填充回复
function KeyP(v) {
var parentWrap = $(v).parents(".respond_box");
parentWrap.find(".res_area_r").val($.trim(parentWrap.find(".res_area").val()));
评论共有4条
可以使用的
这个怎么用呢?
使用appium1.6.3所需文件,不容易下载成功,经常下载失败,现在可以用啦。
综合评分:
积分/C币:3
综合评分:
积分/C币:5
VIP会员动态
热门资源标签
CSDN下载频道资源及相关规则调整公告V11.10
下载频道用户反馈专区
下载频道积分规则调整V1710.18
spring mvc+mybatis+mysql+maven+bootstrap 整合实现增删查改简单实例.zip
资源所需积分/C币
当前拥有积分
当前拥有C币
输入下载码
为了良好体验,不建议使用迅雷下载
appium-uiautomator2-server-debug-androidTest.apk
会员到期时间:
剩余下载个数:
剩余积分:0
为了良好体验,不建议使用迅雷下载
积分不足!
资源所需积分/C币
当前拥有积分
您可以选择
程序员的必选
绿色安全资源
资源所需积分/C币
当前拥有积分
当前拥有C币
为了良好体验,不建议使用迅雷下载
资源所需积分/C币
当前拥有积分
当前拥有C币
为了良好体验,不建议使用迅雷下载
资源所需积分/C币
当前拥有积分
当前拥有C币
您的积分不足,将扣除 10 C币
为了良好体验,不建议使用迅雷下载
无法举报自己的资源
你当前的下载分为234。
你还不是VIP会员
开通VIP会员权限,免积分下载
你下载资源过于频繁,请输入验证码
您因违反CSDN下载频道规则而被锁定帐户,如有疑问,请联络:!
若举报审核通过,可返还被扣除的积分
被举报人:
请选择类型
资源无法下载 ( 404页面、下载失败、资源本身问题)
资源无法使用 (文件损坏、内容缺失、题文不符)
侵犯版权资源 (侵犯公司或个人版权)
虚假资源 (恶意欺诈、刷分资源)
含色情、危害国家安全内容
含广告、木马病毒资源
*投诉人姓名:
*投诉人联系方式:
*版权证明:
*详细原因:
appium-uiautomator2-server-debug-androidTest.apk

我要回帖

更多关于 pythonappium环境搭建 的文章

 

随机推荐