Mobile Development 10 min read

Running UiAutomator on macOS: Full‑Path Fixes and Common Pitfalls

When using UiAutomator on macOS you must prepend the full path to the Android command and adjust slash handling, otherwise you encounter "Cannot run program" errors; this guide shows the errors, the required fixes, and provides a complete Java helper class for automated testing.

FunTester
FunTester
FunTester
Running UiAutomator on macOS: Full‑Path Fixes and Common Pitfalls

Background

The author, a macOS beginner, discovered that running UiAutomator on macOS differs significantly from the Windows environment. The main issues are missing full paths for the android command and incorrect slash handling.

Error Messages

Without a full path the execution fails with:

Cannot run program "android": error=2, No such file or directory

When an incorrect absolute path is used the error is:

Cannot run program "/Users/dahaohaozai/android-sdk-macosx/toos/android": error=2, No such file or directory

Solution Overview

Both problems are solved by:

Adding the complete path to the Android SDK tools before invoking the command.

Normalising path separators (using forward slashes consistently).

The author provides a ready‑to‑use Java helper class that automates the whole workflow: creating a test project, modifying the build file, building with Ant, pushing the JAR to the device, and running the test.

Helper Class Source Code

package source;
import java.io.*;
/**
 * @author  ··-·尘
 * @E-mail:[email protected]
 * @version Created: 2017‑08‑18 10:53:24
 * @alter Modified: 2017‑10‑23 10:19:34 – Test helper class
 */
public class UiAutomatorHelper extends Common {
    private static String android_id = "1"; // androidId, no need to pass as argument
    private static String jar_name = "";   // jar name
    private static String test_class = ""; // package.ClassName
    private static String test_name = "";  // method name
    private static String workspace_path;    // automatically obtained workspace directory

    public UiAutomatorHelper() {
        output("Welcome to the custom debug class!");
    }

    /** Constructor with parameters */
    public UiAutomatorHelper(String jarName, String testClass, String testName) {
        output("Welcome to the custom debug class!");
        workspace_path = getWorkSpase();
        jar_name = jarName;
        test_class = testClass;
        test_name = testName;
        runUiautomator();
        output(Common.LINE + "---FINISH DEBUG----" + Common.LINE);
    }

    // Execution steps
    private void runUiautomator() {
        creatBuildXml();
        modfileBuild();
        buildWithAnt();
        pushTestJar(workspace_path + "/bin/" + jar_name + ".jar");
        runTest(jar_name, test_class + "#" + test_name);
    }

    // Create build.xml
    public void creatBuildXml() {
        execCmd(ANDROID_PATH + "android create uitest-project -n " + jar_name + " -t " + android_id + " -p " + workspace_path);
    }

    // Modify build.xml content
    public void modfileBuild() {
        StringBuffer stringBuffer = new StringBuffer();
        try {
            File file = new File("build.xml");
            if (file.isFile() && file.exists()) {
                BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(new FileInputStream(file)));
                String lineTxt;
                while ((lineTxt = bufferedReader.readLine()) != null) {
                    if (lineTxt.matches(".*help.*")) {
                        lineTxt = lineTxt.replaceAll("help", "build");
                    }
                    stringBuffer.append(lineTxt + "\t
");
                }
                bufferedReader.close();
                writerText("build.xml", stringBuffer.toString());
            } else {
                System.out.println("File not found");
            }
        } catch (Exception e) {
            System.out.println("Error reading file");
            e.printStackTrace();
        }
    }

    // Build with Ant
    public void buildWithAnt() {
        execCmd(ANT_PATH + "ant");
    }

    // Push jar to device
    public void pushTestJar(String localPath) {
        String pushCmd = ADB_PATH + "adb push " + localPath + " /data/local/tmp/";
        execCmd(pushCmd);
    }

    // Run test method
    public void runTest(String jarName, String testName) {
        String runCmd = ADB_PATH + "adb shell uiautomator runtest ";
        String testCmd = jarName + ".jar --nohup -c " + testName;
        execCmd(runCmd + testCmd);
    }

    // Get workspace directory
    public String getWorkSpase() {
        File directory = new File("");
        return directory.getAbsolutePath();
    }

    // Execute a command line
    public void execCmd(String cmd) {
        try {
            Process p = Runtime.getRuntime().exec(cmd);
            BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream()));
            String line;
            while ((line = reader.readLine()) != null) {
                System.out.println(line);
                saveToFile(line, "runlog.log", false);
            }
            reader.close();
            BufferedReader errorReader = new BufferedReader(new InputStreamReader(p.getErrorStream()));
            String errLine;
            while ((errLine = errorReader.readLine()) != null) {
                System.out.println(errLine);
                saveToFile(errLine, "runlog.log", false);
            }
            errorReader.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    // Write text to a file (overwrite)
    public void writerText(String path, String content) {
        File dirFile = new File(path);
        if (!dirFile.exists()) {
            dirFile.mkdir();
        }
        try {
            BufferedWriter bw1 = new BufferedWriter(new FileWriter(path));
            bw1.write(content);
            bw1.flush();
            bw1.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    // Append a line to a log file
    public void saveToFile(String text, String path, boolean isClose) {
        File file = new File("runlog.log");
        try {
            FileOutputStream outputStream = new FileOutputStream(file, true);
            OutputStreamWriter outWriter = new OutputStreamWriter(outputStream);
            BufferedWriter bf = new BufferedWriter(outWriter);
            bf.append(text);
            bf.newLine();
            bf.flush();
            if (isClose) {
                bf.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Key Takeaways

Always use the absolute path to the Android SDK tools when invoking UiAutomator on macOS.

Normalize path separators to avoid "slash" errors.

The provided UiAutomatorHelper class automates project creation, build file modification, Ant compilation, JAR deployment, and test execution.

All command execution results and errors are logged to runlog.log for later analysis.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

javaAndroidautomationtestingmacOSUIAutomator
FunTester
Written by

FunTester

10k followers, 1k articles | completely useless

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.