在使用 Appium Inspector 对安卓-微医生APP登陆页元素获取的时候发现无法获取到内容,Appium报错如下:

[HTTP] --> GET /wd/hub/session/669c743a-cede-43f2-8950-019af660f2f6/screenshot
[HTTP] {}
[MJSONWP (669c743a)] Calling AppiumDriver.getScreenshot() with args: ["669c743a-cede-43f2-8950-019af660f2f6"]
[WD Proxy] Matched '/screenshot' to command name 'getScreenshot'
[WD Proxy] Proxying [GET /screenshot] to [GET http://127.0.0.1:8200/wd/hub/session/fb84ef2a-405f-4983-b2c4-f833ec8b5562/screenshot] with no body
[WD Proxy] Got response with status 500: {"sessionId":"fb84ef2a-405f-4983-b2c4-f833ec8b5562","value":{"error":"unable to capture screen","message":"Failed to capture a screenshot. Does the current view have 'secure' flag set?","stacktrace":"io.appium.uiautomator2.common.exceptions.TakeScreenshotException: Failed to capture a screenshot. Does the current view have 'secure' flag set?\n\tat io.appium.uiautomator2.utils.ScreenshotHelper.takeDeviceScreenshot(ScreenshotHelper.java:131)\n\tat io.appium.uiautomator2.utils.ScreenshotHelper.takeScreenshot(ScreenshotHelper.java:61)\n\tat io.appium.uiautomator2.utils.ScreenshotHelper.takeScreenshot(ScreenshotHelper.java:79)\n\tat io.appium.uiautomator2.handler.CaptureScreenshot.safeHandle(CaptureScreenshot.java:32)\n\tat io.appium.uiautomator2.handler.request.SafeRequestHandler.handle(SafeRequestHandler.java:41)\n\tat io.appium.uiautomator2.server.AppiumServlet.handleRequest(AppiumServlet.java:262)\n\tat io.appium.uiautomator2.server.AppiumServlet.handleHttpRequest(AppiumServlet.java:256)\n\tat io.appium.uia...
[W3C] Matched W3C error code 'unable to capture screen' to UnableToCaptureScreen
[MJSONWP (669c743a)] Encountered internal error running command: io.appium.uiautomator2.common.exceptions.TakeScreenshotException: Failed to capture a screenshot. Does the current view have 'secure' flag set?
[MJSONWP (669c743a)]   at io.appium.uiautomator2.utils.ScreenshotHelper.takeDeviceScreenshot(ScreenshotHelper.java:131)
[MJSONWP (669c743a)]   at io.appium.uiautomator2.utils.ScreenshotHelper.takeScreenshot(ScreenshotHelper.java:61)
[MJSONWP (669c743a)]   at io.appium.uiautomator2.utils.ScreenshotHelper.takeScreenshot(ScreenshotHelper.java:79)
[MJSONWP (669c743a)]   at io.appium.uiautomator2.handler.CaptureScreenshot.safeHandle(CaptureScreenshot.java:32)
[MJSONWP (669c743a)]   at io.appium.uiautomator2.handler.request.SafeRequestHandler.handle(SafeRequestHandler.java:41)
[MJSONWP (669c743a)]   at io.appium.uiautomator2.server.AppiumServlet.handleRequest(AppiumServlet.java:262)
[MJSONWP (669c743a)]   at io.appium.uiautomator2.server.AppiumServlet.handleHttpRequest(AppiumServlet.java:256)
[MJSONWP (669c743a)]   at io.appium.uiautomator2.http.ServerHandler.channelRead(ServerHandler.java:68)
[MJSONWP (669c743a)]   at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:366)
[MJSONWP (669c743a)]   at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:352)
[MJSONWP (669c743a)]   at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:345)
[MJSONWP (669c743a)]   at io.netty.handler.codec.MessageToMessageDecoder.channelRead(MessageToMessageDecoder.java:102)
[MJSONWP (669c743a)]   at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:366)
[MJSONWP (669c743a)]   at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:352)
[MJSONWP (669c743a)]   at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:345)
[MJSONWP (669c743a)]   at io.netty.channel.CombinedChannelDuplexHandler$DelegatingChannelHandlerContext.fireChannelRead(CombinedChannelDuplexHandler.java:435)
[MJSONWP (669c743a)]   at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:293)
[MJSONWP (669c743a)]   at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:267)
[MJSONWP (669c743a)]   at io.netty.channel.CombinedChannelDuplexHandler.channelRead(CombinedChannelDuplexHandler.java:250)
[MJSONWP (669c743a)]   at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:366)
[MJSONWP (669c743a)]   at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:352)
[MJSONWP (669c743a)]   at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:345)
[MJSONWP (669c743a)]   at io.netty.handler.timeout.IdleStateHandler.channelRead(IdleStateHandler.java:266)
[MJSONWP (669c743a)]   at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:366)
[MJSONWP (669c743a)]   at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:352)
[MJSONWP (669c743a)]   at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:345)
[MJSONWP (669c743a)]   at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1294)
[MJSONWP (669c743a)]   at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:366)
[MJSONWP (669c743a)]   at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:352)
[MJSONWP (669c743a)]   at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:911)
[MJSONWP (669c743a)]   at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:131)
[MJSONWP (669c743a)]   at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:611)
[MJSONWP (669c743a)]   at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:552)
[MJSONWP (669c743a)]   at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:466)
[MJSONWP (669c743a)]   at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:438)
[MJSONWP (669c743a)]   at io.netty.util.concurrent.SingleThreadEventExecutor$2.run(SingleThreadEventExecutor.java:140)
[MJSONWP (669c743a)]   at io.netty.util.concurrent.DefaultThreadFactory$DefaultRunnableDecorator.run(DefaultThreadFactory.java:144)
[MJSONWP (669c743a)]   at java.lang.Thread.run(Thread.java:923)
[MJSONWP (669c743a)] 
[HTTP] <-- GET /wd/hub/session/669c743a-cede-43f2-8950-019af660f2f6/screenshot 500 270 ms - 164
[HTTP]

FLAG_SECURE

APP出于安全考虑,不希望被用户截屏或者录屏,所以使用FLAG_SECURE来进行处理

禁止截屏的实现方式并不是很难,在需要设置禁止截屏的 Activity 的生命周期 onCreate() 方法中添加一行代码即可

void onCreate() {
  //禁止截屏
  // 方法 1
  getWindow().addFlags(WindowManager.LayoutParams.FLAG_SECURE);
  // 方法 2
  getWindow().setFlags(WindowManager.LayoutParams.FLAG_SECURE, WindowManager.LayoutParams.FLAG_SECURE);
 

设置了这个flag后, 系统会把当前窗口的内容视为安全隐私内容, 系统会阻止这些内容被截屏或者在不安全可靠的场景显示出来.

在Google的过程中, 发现这个flag可以实现以下功能:

  • 阻止屏幕截图

  • 在Recent apps(任务切换界面)中只显示应用名字和图标, 不显示内容

  • Google App的Now on tap功能不会去分析你的页面的内容

代码里面可以通过去除来去除这个防录屏

Window window = getActivity().getWindow();
window.clearFlags(WindowManager.LayoutParams.FLAG_SECURE);

不过在进行自动化测试的时候就不能这样操作了,但其实这个只会影响录屏,而不影响操作,所以我们直接拿到页面元素,就可以通过元素标签,来编写定位信息来操作元素了。

driver = app_webdriver.Remote("http://127.0.0.1:4723/wd/hub", desired_caps)
driver.page_source

通过这个方式就可以拿到账号密码的元素定位

<android.widget.EditText index="0" package="com.greenline.yihuantong"
                         class="android.widget.EditText" text="登录名/手机号"
                         resource-id="com.greenline.yihuantong:id/bc7"
                         checkable="false" checked="false" clickable="true"
                         enabled="true" focusable="true" focused="true"
                         long-clickable="true" password="false"
                         scrollable="false" selected="false"
                         bounds="[66,658][1014,783]" displayed="true"/>
<android.widget.EditText index="2" package="com.greenline.yihuantong"
                         class="android.widget.EditText" text="密码"
                         resource-id="com.greenline.yihuantong:id/bca"
                         checkable="false" checked="false" clickable="true"
                         enabled="true" focusable="true" focused="false"
                         long-clickable="true" password="true"
                         scrollable="false" selected="false"
                         bounds="[66,784][1014,909]" displayed="true"/>
- { desc: "账号",type: "xpath",value: '//*[@class="android.widget.EditText"][1]', name: "username" }
- { desc: "密码",type: "xpath",value: '//*[@class="android.widget.EditText"][2]', name: "password" }
问题在使用Appium Inspector对安卓-微医生APP登陆页元素获取的时候发现无法获取到内容,Appium报错如下:[HTTP]--&gt;GET/wd/hub/sessio...
标记安全错误 样例应用程序可重现android中关于FLAG_SECURE的错误 #重现步骤:##### 1。 启动应用程序##### 2。 看到蓝色的bg活动,单击“进入!” 按钮##### 3。 按下电源按钮(屏幕关闭)##### 4。 再次按电源按钮(屏幕打开)##### 5。 解锁设备(蓝色bg活动正在启动)##### 6。 单击最近的应用程序按钮 ===>显示红色bg活动。 预期的行为:应该显示空白的屏幕截图。 转载自Nexus 5,Android版本5.1.1,内部版本号LMY48M
appium:FLAG_SECURE TakeScreenshotException: Failed to capture a screenshot. Does the current view have ‘secure’ flag set? Appium Desktop 1.13.0 android 真实设备 oppo A7 sdk 8.1.0 android 模拟器 逍遥安卓 ...
FlagSecure-Android 防止Android上的ScreenCasting数据泄漏 Android Lollipop具有一项新功能,该功能允许从第三方应用程序进行屏幕捕获和屏幕共享。 该功能允许第三方应用程序从设备捕获视频并通过网络传输。 但是,通过使用FLAG_SECURE选项,可以保护其敏感屏幕免受第三方屏幕捕获和共享的影响。 但是,如果开发人员希望保护其应用程序的所有屏幕不受第三方屏幕捕获和共享的影响,则需要在每个活动中分别使用此标志。 没有全局方法可以一次为所有屏幕设置此标志。 但是,可以以仅需使用FLAG_SECURE一次的方式设计其应用程序。 下面是代码片段: 定义一个BaseActivity并在该Activity中设置FLAG_SECURE: 公共类BaseActivity扩展了Activity { @Override protected void o
[时间:2017-09] [状态:Open] [关键词:adb, android,系统版本,截屏,screencap] 本文主要是我遇到的android命令行用法的一个简单总结 获取系统版本: adb shell getprop ro.build.version.release 获取系统api版本: adb shell getprop ro.build.version.sdk 获取手机相...
======upgraded testNG to6.9.11=== Exception in thread "main" java.lang.NoClassDefFoundError: org/testng/remote/RemoteArgs at org.testng.RemoteT...
键名 描述 键值 KEYCODE_CALL 拨号键 5 KEYCODE_ENDCALL 挂机键 6 KEYCODE_HOME 按键Home 3 KEYCODE_MENU ...
禁止截屏设置:getWindow().setFlags(LayoutParams.FLAG_SECURE, LayoutParams.FLAG_SECURE); 例子:需要引入包 ionic 开发 修改platforms\android\CordovaLib\src\org\apache\cordova\CordovaActivity.java 文件内容