Getting Started with Appium for Android Kotlin on macOS in 10 Minutes

Getting Started with Appium for Android Kotlin on macOS in 10 Minutes

The third article from the Appium Series is going to be about testing Android apps on macOS machine. I am going to show you how to configure your macOS machine to test Android applications – prerequisite installations and setup of emulators. After that, you will find how to start your application on the emulator and perform actions on it.

What Is Appium?

Appium is an open source test automation framework for use with native, hybrid and mobile web apps. It drives iOS, Android, and Windows apps using the WebDriver protocol. It is the “standard” for mobile test automation.

Machine Setup

1. Install Java Development Kit (JDK) version 7 or above

(version 8 recommended in order for UI Automation Viewer to work)

2. Set JAVA_HOME environmental variable to where JDK is installed

Put this in your login script (~/.bash_profile for up to macOS 10.14; ~/.zshrc for macOS 10.15 and above):

export JAVA_HOME="/Library/Java/JavaVirtualMachines/adoptopenjdk-8.jdk/Contents/Home"

(change adoptopenjdk-8.jdk to the installation folder of your JDK)

3. Install the Android Studio 

4. Set the ANDROID_HOME and ANDROID_SDK_ROOT environment variable to match this path

Note: If you haven’t changed the default installation path then you’ll have the Android SDK installed in ~/Library/Android/sdk

Add the following lines to your login script

export ANDROID_HOME="$HOME/Library/Android/sdk"
export ANDROID_SDK_ROOT="$HOME/Library/Android/sdk"

5. Install Node.js

6. Install Appium from the terminal (skip if you install Appium Desktop)

npm install -g appium

7. Install Appium Desktop (optional)

Note: Make sure you have at least 40GB of free disk space. The IDE, simulator and emulator images and associated SDKs are all quite large.

8. Create a virtual device with the Android Device Manager

Install APK to Virtual Device

ADB, Android Debug Bridge, is a command-line utility included with Google’s Android SDK. ADB can control your device over USB from a computer, copy files back and forth, install and uninstall apps, run shell commands, and more.

If you have installed the sdk folder in other directory, replace the path with the directory platform-tools is in.

Add the following lines to your login script

export PATH="$HOME/Library/Android/sdk/platform-tools:$PATH"

First, start the ADB shell using the command – adb shell.

Before automating your app, you may need to expect it and find some info about it. So, you need to install it on your virtual device. To do so, open the command line and execute the following command.

adb install pathToYourApk/yourTestApp.apk

To find the app package and current activity. Open your application on the virtual device and navigate to the desired view. Then open adb shell and use the following command.

dumpsys window windows | grep -E 'mCurrentFocus|mFocusedApp'

Running APK ADB Shell Current Activity on macOS

Start Android App in Emulator

You need to make sure that the Appium server is started and listening on port 4723. 

private lateinit var driver: AndroidDriver<AndroidElement>

@BeforeClass
fun classInit() {
    val testAppUrl = javaClass.classLoader.getResource("ApiDemos.apk")
    val testAppFile = Paths.get((testAppUrl!!).toURI()).toFile()
    val testAppPath = testAppFile.absolutePath
    val desiredCaps = DesiredCapabilities()
    desiredCaps.setCapability(MobileCapabilityType.DEVICE_NAME, "android25-test")
    desiredCaps.setCapability(AndroidMobileCapabilityType.APP_PACKAGE, "com.example.android.apis")
    desiredCaps.setCapability(MobileCapabilityType.PLATFORM_NAME, "Android")
    desiredCaps.setCapability(MobileCapabilityType.PLATFORM_VERSION, "7.1")
    desiredCaps.setCapability(AndroidMobileCapabilityType.APP_ACTIVITY, ".view.Controls1")
    desiredCaps.setCapability(MobileCapabilityType.APP, testAppPath)
    driver = AndroidDriver<AndroidElement>(URL("http://127.0.0.1:4723/wd/hub"), desiredCaps)
    driver.closeApp()
}

@BeforeMethod
fun testInit() {
    driver.launchApp()
    driver.startActivity(Activity("com.example.android.apis", ".view.Controls1"))
}

@AfterMethod
fun testCleanup() {
    driver.closeApp()
}

After the driver is initialised we closed if the app is open. Then before each test, we launch the app and open the desired activity.

Start Appium Service with Code

Instead of starting Appium server manually, we can start it from code.

appiumLocalService = AppiumServiceBuilder().usingAnyFreePort().build()
appiumLocalService.start()

Get Path to Test App

The apk file is copied from the Resources folder to the compiled binaries. This is how we get the path.

val testAppUrl = javaClass.classLoader.getResource("ApiDemos.apk")
val testAppFile = Paths.get((testAppUrl!!).toURI()).toFile()
val testAppPath = testAppFile.absolutePath

Initialize Appium Options

val testAppUrl = javaClass.classLoader.getResource("ApiDemos.apk")
val testAppFile = Paths.get((testAppUrl!!).toURI()).toFile()
val testAppPath = testAppFile.absolutePath
val desiredCaps = DesiredCapabilities()
desiredCaps.setCapability(MobileCapabilityType.DEVICE_NAME, "android25-test")
desiredCaps.setCapability(AndroidMobileCapabilityType.APP_PACKAGE, "com.example.android.apis")
desiredCaps.setCapability(MobileCapabilityType.PLATFORM_NAME, "Android")
desiredCaps.setCapability(MobileCapabilityType.PLATFORM_VERSION, "7.1")
desiredCaps.setCapability(AndroidMobileCapabilityType.APP_ACTIVITY, ".view.Controls1")
desiredCaps.setCapability(MobileCapabilityType.APP, testAppPath)

Find Android Locators

Using the UI Automator Viewer, you can find the elements you are looking for. The UI Automator Viewer tool provides a convenient GUI to scan and analyze the UI components currently displayed on an Android device. You can use this tool to inspect the layout hierarchy and view the properties of UI components that are visible on the foreground of the device. This information lets you create more fine-grained tests using UI Automator, for example by creating a UI selector that matches a specific visible property. The UI Automator Viewer tool is located in the /tools/bin directory.

NOTE: The tool’s UI has problems with macOS’s system dark theme so if you’re a dark theme user, you may have to switch to light theme while using it. There’s a problem with some controls not showing or the UI not refreshing, the fix is to resize the window of the tool to force the UI to refresh. On my machine, I’m getting an “Error obtaining UI hierarchy” which prevents the hierarchy view to render on the right.

UI Automator Viewer macOS

Find Android Locators with Appium Desktop

Appium provides you with a neat tool that allows you to find the elements you’re looking for. With Appium Desktop you can find any item and its locators by either clicking the element on the screenshot image or locating it in the source tree.

After launching Appium Desktop and starting a session, you can locate any element in the source. 

Appium Desktop Screen Inspector Android

Locating Elements with Appium

  • By ID

    val button = driver.findElementById("com.example.android.apis:id/button")
    ```
    
-   #### By Class
    
```kotlin
    val checkBox = driver.findElementByClassName("android.widget.CheckBox")
    ```
    
-   #### By XPath
    
```kotlin
    val secondButton = driver.findElementByXPath("//*[@resource-id='com.example.android.apis:id/button']")
    ```
    
-   #### By AndroidUIAutomator
    
```kotlin
    AndroidElement thirdButton = driver.findElementByAndroidUIAutomator("new UiSelector().textContains(\"BUTTO\");");
    ```
    

### Locate Elements using AndroidDriver

```kotlin
@Test
fun locatingElementsTest() {
    val button = driver.findElementById("com.example.android.apis:id/button")
    button.click()
    val checkBox = driver.findElementByClassName("android.widget.CheckBox")
    checkBox.click()
    val secondButton =
        driver.findElementByXPath("//*[@resource-id='com.example.android.apis:id/button']")
    secondButton.click()
    val thirdButton =
        driver.findElementByAndroidUIAutomator("new UiSelector().textContains(" BUTTO ");")
    thirdButton.click()
}

You just need to call the f****indElementBy methods of the AndroidDriver to locate the elements.

Locate Elements inside Parent

@Test
fun locatingElementsInsideAnotherElementTest() {
    val mainElement = driver.findElementById("android:id/content")
    val button = mainElement.findElementById("com.example.android.apis:id/button")
    button.click()
    val checkBox = mainElement.findElementByClassName("android.widget.CheckBox")
    checkBox.click()
    val secondButton =
        mainElement.findElementByXPath("//*[@resource-id='com.example.android.apis:id/button']")
    secondButton.click()
    val thirdButton =
        mainElement.findElementByAndroidUIAutomator("new UiSelector().textContains(\"BUTTO\");")
    thirdButton.click()
}

You have similar f****indElementBy methods on element level so that you can find elements inside other elements.

Gesture Actions in Appium

To perform any touch actions, we use the special TouchAction class. You can use it to do a series of steps simultaneously.

Swipe

@Test
fun swipeTest() {
    class PlatformTouchAction(performsTouchActions: PerformsTouchActions) :
        TouchAction<PlatformTouchAction>(performsTouchActions)
    driver.startActivity(Activity("com.example.android.apis", ".graphics.FingerPaint"))
    val touchAction = PlatformTouchAction(driver)
    val element = driver.findElementById("android:id/content")
    val point = element.location
    val size = element.size
    touchAction
        .press(PointOption.point(point.x + 5, point.y + 5))
        .waitAction(WaitOptions.waitOptions(Duration.ofMillis(200)))
        .moveTo(PointOption.point(point.x + size.width - 5, point.y + size.height - 5))
        .release()
        .perform()
}

MoveTo

@Test
fun moveToTest() {
    class PlatformTouchAction(performsTouchActions: PerformsTouchActions) :
        TouchAction<PlatformTouchAction>(performsTouchActions)
    val touchAction = PlatformTouchAction(driver)
    val element = driver.findElementById("android:id/content")
    val point = element.location
    touchAction.moveTo(PointOption.point(point)).perform()
}

Tap

@Test
fun tapTest() {
    class PlatformTouchAction(performsTouchActions: PerformsTouchActions) :
        TouchAction<PlatformTouchAction>(performsTouchActions)
    val touchAction = PlatformTouchAction(driver)
    val element = driver.findElementById("android:id/content")
    val point = element.location
    touchAction
        .tap(TapOptions.tapOptions().withPosition(PointOption.point(point)).withTapsCount(2))
        .perform()
}

Related Articles

Java, Web Automation Java

30 Advanced WebDriver Tips and Tricks Java Code

This is the next article from the WebDriver Series where I will share with you 30 advanced tips and tricks using Java code. I wrote similar articles separated i

30 Advanced WebDriver Tips and Tricks Java Code

Java, Mobile Automation Java

Getting Started with Appium for Android Java on Windows in 10 Minutes

This is the first article from the new series dedicated to the mobile testing using Appium test automation framework. Here, I am going to show you how to config

Getting Started with Appium for Android Java on Windows in 10 Minutes

AutomationTools, Free Tools, Java

Quick Guide Bitbucket Pipelines on Running Selenium Java Tests

In this article from the series Automation Tools, I am going to guide you on how you can set up a Bitbucket Pipelines job for a Selenium Java project, run your

Quick Guide Bitbucket Pipelines on Running Selenium Java Tests

AutomationTools, Free Tools, Java

Quick Guide GitHub Actions on Running Selenium Java Tests

In this article from the series Automation Tools, I am going to guide you on how you can set up a GitHub Actions job for a Selenium Java project, run your Selen

Quick Guide GitHub Actions on Running Selenium Java Tests

Java, Kotlin, Mobile Automation Java

Getting Started with Appium for Android Kotlin on Windows in 10 Minutes

This is the first article from the new series dedicated to the mobile testing using Appium test automation framework. Here, I am going to show you how to config

Getting Started with Appium for Android Kotlin on Windows in 10 Minutes

Design Architecture Java, Design Patterns Java, Java

Advanced Strategy Design Pattern in Automated Testing Java Code

In this part of the Design Pattern Series, I’m going to extend my ideas about the application of the Strategy Design Pattern in automation tests. In my previous

Advanced Strategy Design Pattern in Automated Testing Java Code
Anton Angelov

About the author

Anton Angelov is Managing Director, Co-Founder, and Chief Test Automation Architect at Automate The Planet — a boutique consulting firm specializing in AI-augmented test automation strategy, implementation, and enablement. He is the creator of BELLATRIX, a cross-platform framework for web, mobile, desktop, and API testing, and the author of 8 bestselling books on test automation. A speaker at 60+ international conferences and researcher in AI-driven testing and LLM-based automation, he has been recognized as QA of the Decade and Webit Changemaker 2025.