如何使用 Appium 在移动应用程序中获取烤面包机消息的文本

How to get text of a toaster message in mobile app using Appium

我正在尝试在 Android 移动应用程序中验证烤面包机消息,但无法获取烤面包机消息的文本,因为它没有显示在 uiautomatorviewer 中。 得到一些信息,在 OCR 的帮助下,可以完成截屏并从该截屏中获取文本 谁能帮助我在 Appium 项目中使用 java 逐步完成此操作?

在 Appium 论坛上关注此讨论:https://discuss.appium.io/t/verifying-toast/3676

验证烤面包机的基本步骤是:

  1. 执行操作以触发 toast 消息出现在屏幕上
  2. 截图 x 次
  3. 提高所有屏幕截图的分辨率
  4. 使用 tessearct OCR 检测 toast 消息。

参考this repo使用Java OCR库(见底部):

import org.bytedeco.javacpp.*;
import static org.bytedeco.javacpp.lept.*;
import static org.bytedeco.javacpp.tesseract.*;

public class BasicExample {
    public static void main(String[] args) {
        BytePointer outText;

        TessBaseAPI api = new TessBaseAPI();
        // Initialize tesseract-ocr with English, without specifying tessdata path
        if (api.Init(null, "eng") != 0) {
            System.err.println("Could not initialize tesseract.");
            System.exit(1);
        }

        // Open input image with leptonica library
        PIX image = pixRead(args.length > 0 ? args[0] : "/usr/src/tesseract/testing/phototest.tif");
        api.SetImage(image);
        // Get OCR result
        outText = api.GetUTF8Text();
        System.out.println("OCR output:\n" + outText.getString());

        // Destroy used object and release memory
        api.End();
        outText.deallocate();
        pixDestroy(image);
    }
}

您可以按照以下链接中的信息在您的机器上安装 Tesseract:

对于Mac:http://emop.tamu.edu/Installing-Tesseract-Mac

Windows:http://emop.tamu.edu/Installing-Tesseract-Windows8

在您的机器上安装 TessEract 后,您需要在您的项目中添加 TessEract Java 库的依赖项。如果您为此使用 Maven,添加以下依赖项将起作用:

    <dependency>
        <groupId>org.bytedeco.javacpp-presets</groupId>
        <artifactId>tesseract</artifactId>
        <version>3.04-1.1</version>
    </dependency>

另外,Ivan 提到的'Step 3' 不需要遵循。

如果您使用 'TestNG',TessEract API 只需初始化一次,而不是每次都初始化它,根据您的框架,您可以在 'BeforeTest' 或 'BeforeSuite' 或 'BeforeClass' 方法,并相应地关闭 'AfterTest' 或 'AfterSuite' 或 'AfterClass' 方法中的 API。

下面是我为实现它而编写的代码。

import static org.bytedeco.javacpp.lept.pixDestroy;
import static org.bytedeco.javacpp.lept.pixRead;
import java.io.File;
import java.io.IOException;
import org.apache.commons.io.FileUtils;
import org.bytedeco.javacpp.lept.PIX;
import org.bytedeco.javacpp.tesseract.TessBaseAPI;
import org.openqa.selenium.OutputType;
import org.openqa.selenium.TakesScreenshot;
import org.testng.annotations.AfterSuite;
import org.testng.annotations.BeforeSuite;

    public class BaseTest {
    
    static TessBaseAPI api = new TessBaseAPI();
    
    @BeforeSuite
        public void beforeSuit() throws IOException {
    
            File screenshotsDirec = new File("target/screenshots");
    
            if (screenshotsDirec.exists())
                FileUtils.forceDelete(screenshotsDirec);
    
            FileUtils.forceMkdir(screenshotsDirec);
    
            System.out.println("Initializing TessEract library");
    
            if (api.Init("/opt/local/share", "eng") != 0) {
                System.err.println("Could not initialize tesseract.");
            }
    
        }
    
    public synchronized boolean verifyToastMessage(String msg)
                throws IOException {
            TakesScreenshot takeScreenshot = ((TakesScreenshot) driver);
    
            File[] screenshots = new File[5];
    
            for (int i = 0; i < screenshots.length; i++) {
                screenshots[i] = takeScreenshot.getScreenshotAs(OutputType.FILE);
            }
    
            String outText;
    
            Boolean isMsgContains = false;
    
            for (int i = 0; i < screenshots.length; i++) {
                PIX image = pixRead(screenshots[i].getAbsolutePath());
                api.SetImage(image);
                outText = api.GetUTF8Text().getString().replaceAll("\s", "");
                System.out.println(outText);
                isMsgContains = outText.contains(msg);
                pixDestroy(image);
                if (isMsgContains) {
                    break;
                }
            }
    
            return isMsgContains;
    
        }
    
    @AfterSuite()
        public void afterTest() {
    
            try {
                api.close();
            } catch (Exception e) {
                api.End();
                e.printStackTrace();
            }
    
        }
    }

我还想补充一点,以这种方式编写测试来读取和验证 Toast 消息并不是很可靠,因为在我的一个测试中,这段代码成功捕获了 Toast 消息,而在另一个测试中却未能捕获到 Toast 消息toast 消息,因为屏幕截图的捕获在 toast 消息消失时开始。这就是我试图非常高效地编写这段代码的原因。然而,这也达不到目的。