Execute Your Arbitrary ADB Commands with Appium

      If you’re not a big Android person, you might not know about ADB, the “Android Debug Bridge”. ADB is a powerful tool provided as part of the Android SDK by Google, that allows running all sorts of interesting commands on a connected emulator or device. One of these commands is adb shell, which gives you shell access to the device filesystem (including root access on emulators or rooted devices). adb shell is the perfect tool for solving many problems.

      Appium did not allow running of arbitrary ADB commands. This is because Appium was designed to run in a remote environment, possibly sharing an OS with other services or Appium servers, and potentially many connected Android devices. It would be a huge security hole to give any Appium client the full power of ADB in this context. Recently, the Appium team decided to unlock this functionality behind a special server flag, so that someone running an Appium server could intentionally open up this security hole. This is achieved using –relaxed-security flag. So you can now start up Appium like this to run arbitrary ADB commands,

appium –relaxed-security

      With Appium running in this mode, you have access to a new “mobile:” command called “mobile: shell“. The Appium “mobile:” commands are special commands that can be accessed using executeScript (at least until client libraries make a nicer interface for taking advantage of them). Here’s how a call to “mobile: shell” looks in Java:

driver.executeScript(“mobile: shell”, arg);

arg needs to be a JSONifiable object with two keys:

  • command: a String, the command to be run under adb shell.
  • args: an array of Strings, the arguments passed to the shell command.

      For example, let’s say we want to clear out the pictures on the SD card, and that on our device, these are located at /mnt/sdcard/Pictures. If we were running ADB on our own without Appium, we’d accomplish our goal by running:

adb shell rm -rf /mnt/sdcard/Pictures/*.*

      To translate this to Appium’s “mobile: shell” command, we simply strip off adb shell from the beginning, and we are left with rm -rf /mnt/sdcard/Pictures/*.*

      The first word here is the “command”, and the rest constitute the “args”. So we can construct our object as follows:

List removePicsArgs = Arrays.asList(“-rf”, “/mnt/sdcard/Pictures/.”);
Map removePicsCmd = ImmutableMap.of(“command”, “rm”, “args”, removePicsArgs);
driver.executeScript(“mobile: shell”, removePicsCmd);

      We can also retrieve the result of the ADB call, for example if we wish to verify that the directory is now indeed empty:

List lsArgs = Arrays.asList(“/mnt/sdcard/Pictures/.”);
Map lsCmd = ImmutableMap.of(“command”, “ls”,”args”, lsArgs);
String lsOutput = (String) driver.executeScript(“mobile: shell”, lsCmd);
Assert.assertEquals(“”, lsOutput);

      The output of our command is returned to us as a String which we can do whatever we want with, including making assertions on it.

      In this article, I hope you got the power of ADB through a few simple file system commands. You can actually do many more useful things than delete files with ADB, so go out there and have fun with it in your automation flow.

Reference: Appium Pro

make it perfect!

Android Activities and Intents for Appium Engineers

Android Activities and Intents

    The Activity is a core concept of Android applications and fundamentally shapes application architecture and UI design. Therefore, our testing strategy can benefit from understanding and incorporating activities. In this article, I would like to share some concepts of Android Activity and Intents.

     An Android app is a collection of activities that can be entered and left at will. UI designers think of applications in terms of screens, which is a pretty close analog to activities. An activity provides the developer with a window in which to draw the UI, and each screen of an application typically maps to a single activity. As a user moves from one screen to another, the app launches the next activity from the current one. All activities in an Android app must be declared in the app’s AndroidManifest.xml file. Applications launch their own activities the same as they launch activities in other apps, using the startActivity() method.

     Next, we will discuss Intents. Activities are launched via Intents. There are two types of intents: explicit and implicit. An explicit intent uses the name of the app along with the name of the activity to launch the intended activity. Explicit intents are used by developers for moving between activities within a single app. Activities can be launched on connected devices from the command-line using ADB and the am command (short for Activity Manager). The following is an example of launching the default camera app using an explicit intent. We specify the package name of the camera app and the name of the activity,

adb shell am start -n com.android.camera2/com.android.camera.CaptureActivity

     When developers build their activities to be used by other apps, they label their activities so they may be targeted by implicit intents. As the name implies, an implicit intent doesn’t specify a particular app or activity to launch instead it specifies the sort of thing the user would like to do. When an app launches an activity using an implicit intent the Android operating system looks through all the activities of all the apps on the device (using their manifest files) and finds the activities which declared that they respond to the action (and category) specified in the intent. Next, we will launch the camera app using implicit intents, specifying the IMAGE_CAPTURE action,

adb shell am start -a android.media.action.IMAGE_CAPTURE

We can also launch the camera app directly to video capture,

adb shell am start -a android.media.action.VIDEO_CAMERA

    If multiple applications support the same activity, the user is given a choice as to which activity they would like to handle the intent. This decision is probably familiar to all Android users. For example, if you try to set the wallpaper in your device then it will prompt with different sources to choose the image like from Live Wallpapers, Photos, and Wallpapers. You can use below command to trigger that options,

adb shell am start -a android.intent.action.SET_WALLPAPER

    A data URI can also be specified this is the way we can pass the information along with the intent. We will see an example to open a webpage on the device. This is how deep linking is implemented, the deep links are intents which are matched to activities. Below is the command,

adb shell am start -a android.intent.action.VIEW -d https://journeyofquality.com/

The following URI doesn’t start with https like a web URL does, but Google Maps will recognize it and open the given coordinates,

adb shell am start -a android.intent.action.VIEW -d “geo:10.0077154,76.3374621”

Below is an example to sends some optional text which we would like to share,

adb shell am start -a “android.intent.action.SEND” -e “android.intent.extra.TEXT” “welome to journey of quality” -t “text/plain”

      I believe that now you got some ideas about Android Activities, Intents, and have seen how to launch activities and send intents using ADB. In the Appium Automation flow, by default, Appium parses the AndroidManifest.xml file in the .apk file to find the main activity and package name. Appium then launches the app under test using these parameters. If you would like to launch a different activity in your app, you can use the appPackage and appActivity desired capabilities. Intents can also be described using the capabilities: intentAction, intentCategory, optionalIntentArguments, intentFlags.

   optionalIntentArguments are the extra parameters that can be sent with intents, outlined in the last ADB example about sharing text. intentFlags are a complex set of extra commands which can alter the way activities are launched. They mostly have to do with how the newly launched activity relates to a task.

    Activities can also be launched in the middle of test execution, rather than at the beginning of a session. This can be done using the startActivity command,

driver.startActivity(new Activity(“com.example”, “ActivityName”));

     If you have the .apk file, you can find the manifest by opening any android project in Android Studio and choosing Build > Analyze APK from the top navigation bar. Choose your APK file from the file system and then view the AndroidManifest.xml file. All activities and the intents they respond to will be listed in nodes.

    I hope you enjoyed this article and learned about Activities, Intents and some ADB commands. Try to use the above ADB commands in your automation scripts. You can execute your ADB commands using Runtime.getRuntime().exec(“command”). Enjoy your automation!!!

Reference: Appium Pro

make it perfect!