FLAG_SECURE:安卓无法抓取页面截屏

2022-03-29 16:36:36 浏览数 (1)

问题

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

代码语言:javascript复制
[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?ntat io.appium.uiautomator2.utils.ScreenshotHelper.takeDeviceScreenshot(ScreenshotHelper.java:131)ntat io.appium.uiautomator2.utils.ScreenshotHelper.takeScreenshot(ScreenshotHelper.java:61)ntat io.appium.uiautomator2.utils.ScreenshotHelper.takeScreenshot(ScreenshotHelper.java:79)ntat io.appium.uiautomator2.handler.CaptureScreenshot.safeHandle(CaptureScreenshot.java:32)ntat io.appium.uiautomator2.handler.request.SafeRequestHandler.handle(SafeRequestHandler.java:41)ntat io.appium.uiautomator2.server.AppiumServlet.handleRequest(AppiumServlet.java:262)ntat io.appium.uiautomator2.server.AppiumServlet.handleHttpRequest(AppiumServlet.java:256)ntat 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() 方法中添加一行代码即可

代码语言:javascript复制
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功能不会去分析你的页面的内容

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

代码语言:javascript复制
Window window = getActivity().getWindow();
window.clearFlags(WindowManager.LayoutParams.FLAG_SECURE);

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

代码语言:javascript复制
driver = app_webdriver.Remote("http://127.0.0.1:4723/wd/hub", desired_caps)
driver.page_source

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

代码语言:javascript复制
<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"/>

提取一下

代码语言:javascript复制
- { desc: "账号",type: "xpath",value: '//*[@class="android.widget.EditText"][1]', name: "username" }
- { desc: "密码",type: "xpath",value: '//*[@class="android.widget.EditText"][2]', name: "password" }

0 人点赞