Android 通过腾讯OCR来查找UiAutomator不能识别的控件

论坛 期权论坛 编程之家     
选择匿名的用户   2021-6-2 15:52   1829   0

最近开发了总有同事抱怨UiAutomator有些界面的空间无法识别,以至于部分功能自动化脚本开发被Block,对此我研究了腾讯之前发布的一个adbui库,这个库是python版的,其中有一个通过ocr的方式来解决UIA开发过程中控件不能识别的问题,于是就想把这个功能移植到UIA的公共库里面。

【注意事项】

1. 该接口需要发送http请求和腾讯的云服务器进行通信,因此,使用该接口时,需保证数据流量或者Wi-Fi连接。

2. 该接口容易受到网速等不可逆因素影响,导致响应速度变慢,所以不适合大规模使用。

3. 该接口如果使用数据流量,会产生一定程度上流量费用。

长话短说,上代码.

首先生成签名工具类:

public class TencentSign {
    /**
     * 生成 Authorization 签名字段
     *
     * @param appId
     * @param secretId
     * @param secretKey
     * @param expired
     * @return
     * @throws Exception
     */
    public static String appSign(long appId, String secretId, String secretKey,
                                 long expired) throws Exception {
        long now = System.currentTimeMillis() / 1000;
        int rdm = Math.abs(new Random().nextInt());
        String plainText = String.format("a=%d&k=%s&e=%d&t=%d&r=%d&u=%s&f=", appId,
                secretId, expired, now, rdm, "xx");
        byte[] hmacDigest = HmacSha1(plainText, secretKey);
        byte[] signContent = new byte[hmacDigest.length + plainText.getBytes().length];
        System.arraycopy(hmacDigest, 0, signContent, 0, hmacDigest.length);
        System.arraycopy(plainText.getBytes(), 0, signContent, hmacDigest.length,
                plainText.getBytes().length);
        return Base64Encode(signContent);
    }

    /**
     * 生成 base64 编码
     *
     * @param binaryData
     * @return
     */
    public static String Base64Encode(byte[] binaryData) {
        return Base64.encodeToString(binaryData, Base64.NO_WRAP);
    }

    /**
     * 生成 hmacsha1 签名
     *
     * @param binaryData
     * @param key
     * @return
     * @throws Exception
     */
    public static byte[] HmacSha1(byte[] binaryData, String  key) throws Exception {
        Mac mac = Mac.getInstance("HmacSHA1");
        SecretKeySpec secretKey = new SecretKeySpec(key.getBytes(), "HmacSHA1");
        mac.init(secretKey);
        byte[] HmacSha1Digest = mac.doFinal(binaryData);
        return HmacSha1Digest;
    }

    /**
     * 生成 hmacsha1 签名
     *
     * @param plainText
     * @param key
     * @return
     * @throws Exception
     */
    public static byte[] HmacSha1(String plainText, String key) throws Exception {
        return HmacSha1(plainText.getBytes(), key);
    }
}

Http发送请求,根据adbui python库中定义的header以及data的格式。


public class HttpUtils {
   
    /**
     * post方式请求服务器(https协议)
     *
     * @param url
     *            请求地址
     * @param content
     *            参数
     * @return
     * @throws NoSuchAlgorithmException
     * @throws KeyManagementException
     * @throws IOException
     */
    public static String post(String url, String sign, String content)
            throws NoSuchAlgorithmException, KeyManagementException, IOException {
        URL console = new URL(url);
        HttpURLConnection conn = (HttpURLConnection) console.openConnection();
        conn.setDoInput(true);
        conn.setDoOutput(true);
        conn.setRequestMethod("POST");
        conn.setUseCaches(false);
        conn.setInstanceFollowRedirects(true);
        //根据adbui python库填写的Header参数
        conn.addRequestProperty("Content-Type", "text/json");
        conn.setRequestProperty("Authorization", sign);
        conn.connect();
        DataOutputStream out = new DataOutputStream(conn.getOutputStream());
        out.write(content.getBytes("UTF-8"));
        out.flush();
        out.close();
        if (conn.getResponseCode() != HttpURLConnection.HTTP_OK)
            throw new RuntimeException("Request url failed ...");
        BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream(),"UTF-8"));
        String result = "";
        String getLine;
        while ((getLine = in.readLine()) != null)
            result += getLine;
        in.close();
        return result;
    }

}

获取UI控件位置的的实现,实现过程中在base64编码那块入坑多次

public class TencentOCR {


    public static List getUisByOcr(String text) throws Exception {
        Common.takeScreenshot("ocrshot");
        StringBuffer path = new StringBuffer(Environment.getExternalStorageDirectory().getPath());
        path.append("/screenshot/ocrshot.png");
        String result = getTextFromImage(path.toString());
        JSONObject ocrResult = new JSONObject(result);
        List<UI> uis = new ArrayList();
        JSONArray items = ocrResult.getJSONArray("items");
        for (int i = 0; i < items.length(); i++) {
            int sameCount = 0;
            JSONObject item = items.getJSONObject(i);
            String itemString = item.getString("itemstring");
            if (itemString.contains(text)) {
//                print("itemString-->" + itemString);
                JSONObject itemcoord = item.getJSONObject("itemcoord");
                UI ui = new UI(itemcoord.getInt("x"), itemcoord.getInt("y"),
                        itemcoord.getInt("x") + itemcoord.getInt("width"),
                        itemcoord.getInt("y") + itemcoord.getInt("height"),
                        itemcoord.getInt("width"), itemcoord.getInt("height"));
                uis.add(ui);
            }
        }
        return uis;
    }
    /**
     * 查找指定text的UI位置
     *
     * @param text 需要查找的text
     * @return 返回UI位置
     */
    public static UI getUiByOcr(String text) throws Exception {
        List<UI> uilist = getUisByOcr(text);
        if(!uilist.isEmpty())
            return uilist.get(0);
        return null;
    }

    public static UI getUiByOcr(String text, int index) throws Exception {
        List<UI> uilist = getUisByOcr(text);
        if(!uilist.isEmpty())
            return uilist.get(index);
        return null;
    }

    /**
     * 识别图中文字信息
     *
     * @param imagePath 图片路径
     * @return 返回ocr识别结果
     */
    public static String getTextFromImage(String imagePath) throws Exception {
        if (TextUtils.isEmpty(imagePath))
            return null;
        long expired = System.currentTimeMillis() / 1000 + 2592000;
        //得到Authorization
        String sign = TencentSign.appSign(YouTuHttpContants.APP_ID,
                YouTuHttpContants.SECRET_ID,
                YouTuHttpContants.SECRET_KEY,
                expired);
        String image = image2Base64(imagePath);
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("app_id", String.valueOf(YouTuHttpContants.APP_ID));
        jsonObject.put("session_id", "");
        jsonObject.put("image", image);
        String result = HttpUtils.post(YouTuHttpContants.OCR_URL, sign,
                jsonObject.toString());
        return result;
    }

    /**
     * 将图中进行base64格式编码
     *
     * @param imagePath 图片路径
     * @return
     */
    public static String image2Base64(String imagePath) {

        InputStream is = null;
        byte[] data = null;
        String result = null;
        try {
            is = new FileInputStream(imagePath);
            data = new byte[is.available()];
            is.read(data);
            result = Base64.encodeToString(data, Base64.DEFAULT);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (is != null) {
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return result;
    }

    public static class UI {

        private int x1;
        private int y1;
        private int x2;
        private int y2;
        private int width;
        private int height;
        private String text;

        public UI(int x1, int y1, int x2, int y2, int width, int height) {
            this.x1 = x1;
            this.y1 = y1;
            this.x2 = x2;
            this.y2 = y2;
            this.width = width;
            this.height = height;
            this.text = null;
        }

        public void setText(String text) {
            this.text = text;
        }

        public String getText() {
            return text;
        }

        public void click() {
            int x = x1 + width / 2;
            int y = y1 + height / 2;
            mDevice.click(x, y);
        }
    }
}

分享到 :
0 人收藏
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

积分:3875789
帖子:775174
精华:0
期权论坛 期权论坛
发布
内容

下载期权论坛手机APP