云真机各功能的实现历程

2021年9月25日 10点热度 0条评论 来源: saii

一. 远程Shell功能

我们一开始实现的shell功能真的可以说是渣渣,通过前端发送对应的命令到服务端,服务端增加相应的 adb -s xxx shell 进行处理,这里就导致了有好几个问题

  1. 没有上下文的操作概念,也就是说想要进入到某个目录下,然后进行拉取的操作会变得非常的困难。
  2. 安全问题 用户完成可以在命令后面带上 管道符来进行操作对真正的服务器的内容。

其实解决这个问题的方式不难,主要是有没有找到相应的第三方库来替我们来解决这个问题,查找了下相关的开源项目的实现如:ws-scrcpy 以及 atxserver2 , 所以我们发现前端有一个非常棒的库

xterm.js 基本上只要创建好与后台的websocket连接以后,后续的所有的通讯都可以交给xterm去搞定了。而java的后台我们则使用 pty4j

二. 扫码功能

这个功能我们是直接抄的岩鼠的界面,当然逻辑是不太清楚对方怎么实现的,不过直接百度一搜索都能够搜索到很多关于 adb push 图片更新相册 文章说明, 不过发现在部分oppo的手机以及一加手机上这个方式并不能够生效。

查看了android的官方开发文档 有如下的一个说明

这个广播已经被废弃在api 29的版本。 所以这种发广播的方式 adb shell am broadcast -a android.intent.action.MEDIA_SCANNER_SCAN_FILE -d file: 可能就不太实用了。

又找到了另外的一篇文章 三种方法,刷新 Android 的 MediaStore!让你保存的图片立即出现在相册里!。 所以我们还是需要通过android代码去更新相册, 考虑到其实appiumSetting这个应用承担了很多这样子的工作,所以我们直接在appiumSetting这个包里面去新增一些逻辑接口了,相应的代码如下

package io.appium.settings.receivers;

import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.media.MediaScannerConnection;
import android.net.Uri;
import android.util.Log;

public class AlbumUpdateReceiver extends BroadcastReceiver implements HasAction { 

    private static final String TAG = AlbumUpdateReceiver.class.getSimpleName();

    private static final String ACTION = "io.appium.settings.album.update";

    private static final String UPDATE_ALBUM_PATH_SETTING_NAME = "album_file_path";

    @Override
    public void onReceive(Context context, Intent intent) { 

        String filePath = "";

        if (intent.hasExtra(UPDATE_ALBUM_PATH_SETTING_NAME)) { 
            try { 
                filePath = intent.getStringExtra(UPDATE_ALBUM_PATH_SETTING_NAME);
            } catch (NumberFormatException e) { 
                e.printStackTrace();
            }
        }

        if (filePath.equals("")) { 
            Log.e(TAG, "update album filePath can not be empth");
            return;
        }

        MediaScannerConnection.scanFile(context,
                new String[] {  filePath }, null,
                new MediaScannerConnection.OnScanCompletedListener() { 
                    @Override
                    public void onScanCompleted(String path, Uri uri) { 
                        Log.i("TAG", "Finished scanning " + path + uri);
                    }
                });
        setResultCode(Activity.RESULT_OK);
    }

    @Override
    public String getAction() { 
        return ACTION;
    }
}

之后我们想要去更新相册的话就可以发送这样子的一个广播包了:

am broadcast -a io.appium.settings.album.update --es album_file_path /sdcard/DCIM/Camera/xxx.jpeg

三. 代理功能

这个功能其实对于测试同学来说是非常需要的一个功能,但是操作起来其实非常的麻烦,因为需要进入到wifi界面来进行设置代理的操作,所以其实需要有个便捷的方式来解决这个事情。

adb 设置代理 和 关闭代理 无需重启 这篇文章给出了完美的解决方案,可以通过adb的方式进行设置以及取消代理

adb shell settings put global http_proxy ip:端口

adb shell settings put global http_proxy :0

四、分辨率切换

其实一开始考虑这个问题的时候,把问题想的复杂了很多,因为总想着是scrcpy是否有方法能够支持动态切换分辨率的方式,结果找了一遍没有发现,所以这个问题一直就有点陷入的无解当中。知道有一天去体验了下 岩鼠 的分辨率切换后,有了一些思路。

上图就是岩鼠在切换分辨率的时候,收到的websocket的数据,这里的pid 我个人的理解其实应该是scrcpy的进程id。 一旦我进行分辨率切换的时候,实际上他的pid也是发生变化的。所以很大的情况是岩鼠在做分辨率切换的时候,将原有的scrcpy的进程结束,重启启动新的scrcpy的程序,同时将分辨率参数设置为将要改变的即可了。

想通了这个逻辑以后这个问题就不难处理了, 这里代码就不做赘述了。

五、优化截图(minicap截图)

其实用过appium的截图的同学都比较清楚,appium的截图是相当的慢, 基本上需要达到秒级以上, 所以我们这里做了一些优化,通过minicap的截图来替换掉原生的appium的截图,如果是minicap截图失败的话,再切换回原生的截图。

LD_LIBRARY_PATH=/data/local/tmp /data/local/tmp/minicap -P 1440x2560@1440x2560/0 -s >  /data/local/tmp/screenhot.png

不过在一次验证中我们发现一台mate20的手机截图,出现了黑边的情况

出现黑边的问题

看情况感觉就是分辨率的问题,因为手机的分辨率我们是通过 wm size 进行获取到的, 结果看到了这样子的结果

HWLYA:/data/local/tmp $ wm size
Physical size: 1440x3120
Override size: 1080x2340

上述的是什么意思呢? 其实代表 手机的物理分辨率是1440x3120 但是实际上设置的是1080x2340。所以我们实际去截图操作的分辨率是1080x2340了。 这里我们暂时的解决方法就是wm size reset 将分辨率做一个重置即可解决问题了。

    原文作者:saii
    原文地址: https://blog.csdn.net/qq744746842/article/details/120479014
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系管理员进行删除。