Wednesday, June 1, 2016

EASY TO RECORD SCREEN IN APPIUM FOR ANDROID DEVICES

There is no in-build capability provided by Appium to Record Screen. Here we will try to Record screen in Android device for TestMethod and Save at desired location. We can split this task in below steps.


  1. Start Screen Recording
  2. Stop Screen Recording
  3. Save Screen Recording at desired location
  4. Remove Recorded Screen from device to free memory. [optional step]

1. Start Screen Recording:

This can be achieved using adb shell command “screenrecord”.



adb shell screenrecord /sdcard/demo.mp4


Above command will start screen recording and will save demo.mp4 in sdcard on pressing ctrl+c


2. Stop Screen Recording:

This can be achieved by passing ctrl+c to console window. [or we can kill adb process that was started due to screenrecord command]


3. Save Screen Recording at desired location:
This can be achieved using aadb command “pull”.



adb pull /sdcard/demo.mp4 D:\ScreenRecords


Above command will pull from device and save demo.mp4 file at D:\ScreenRecords.


4. Remove Recording Screen from device:

This can be achieved using adb shell command “rm”.



adb shell rm /sdcard/demo.mp4


Above command will remove demo.mp4 file from device i.e. in /sdcard location.


Now we will do all above steps programmatically in ScreenRecorder.java class . I tried to give comments for each and every steps. Please comment, if it is still not clear.


ScreenRecorder.java


import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;


public class ScreenRecorder {


private static List<String> ADBProcessIDsBeforeScreenRecording = null;
private static List<String> ADBProcessIDsAfterScreenRecording = null;


public static void StartScreenRecording(String CurrentTestMethodName)
throws IOException {


// Storing all ADB process ids before starting Screen Recording.
ADBProcessIDsBeforeScreenRecording = getProcessIDs("adb.exe");


// "Starting Screen Recording for Current TestMethod.
Runtime.getRuntime().exec(
"cmd /c adb shell screenrecord --bit-rate 1000000 //sdcard//"
+ CurrentTestMethodName + ".mp4");


}


public static void StopScreenRecording(String CurrentTestMethodName,
String DirectoryToSaveRecordedScreen,
boolean RemoveRecordedScreenFromDevice) throws IOException,
InterruptedException {


// Storing all ADB process ids after Screen Recording.
ADBProcessIDsAfterScreenRecording = getProcessIDs("adb.exe");


// killing ADB task using process id.
// First we are trying to get ADB process id that is started due to ADB
// screenrecord then killing the same.
for (String id : ADBProcessIDsAfterScreenRecording) {
boolean found = false;
for (String tgtid : ADBProcessIDsBeforeScreenRecording) {
if (tgtid.equals(id)) {
found = true;
break;
}
}
if (!found) {
Runtime.getRuntime().exec("taskkill /F /PID " + id);
break;
}
}


// Sleep time to save the recorded video in Device properly
Thread.sleep(2000);


// Pulling Screen Recording to PC/Machine
Runtime.getRuntime().exec(
"cmd /c adb pull //sdcard//" + CurrentTestMethodName + ".mp4 "
+ DirectoryToSaveRecordedScreen);
// Sleep time to pull video from device to destination directory
Thread.sleep(5000);


if (RemoveRecordedScreenFromDevice) {
// Deleting ScreenRecord from Device
Runtime.getRuntime().exec(
"cmd /c adb shell rm //sdcard//" + CurrentTestMethodName
+ ".mp4");
}


}


//Method to get List of Process Ids using Process Name
static List<String> getProcessIDs(String processName) {
List<String> processIDs = new ArrayList<String>();
try {
String line;
Process p = Runtime.getRuntime().exec("tasklist /v /fo csv");
BufferedReader input = new BufferedReader(new InputStreamReader(
p.getInputStream()));
while ((line = input.readLine()) != null) {
if (!line.trim().equals("")) {
// Pid is after the 1st ", thus it's argument 3 after
// splitting
String currentProcessName = line.split("\"")[1];
// Pid is after the 3rd ", thus it's argument 3 after
// splitting
String currentPID = line.split("\"")[3];
if (currentProcessName.equalsIgnoreCase(processName)) {
processIDs.add(currentPID);
}
}
}
input.close();
} catch (Exception err) {
err.printStackTrace();
}
return processIDs;
}


}


Now ScreenRecorder.java class is ready.
Call
StartScreenRecording(“CurrentTestMethodName”) - To start screen recording
And
StopScreenRecording(“CurrentTestMethodName”,“SomeFolderPath”,true) - To stop screen recording


Best way to use these methods will be - when we will call StartScreenRecording in @BeforeMethod and StopScreenRecording in @AfterMethod. In this way, we will Screen Recording for each TestMethod.


See Below dummy TestClass.java - This is only for representation. It will have compile errors.


TestClass.java


import java.io.IOException;
import java.lang.reflect.Method;


import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;


public class TestClass {
String CurrentTestMethodName="";
@BeforeMethod
public void BeforeMethodFunctionality(Method method) throws IOException{
CurrentTestMethodName=method.getName();
ScreenRecorder.StartScreenRecording(CurrentTestMethodName);
//Code To
//Initialize AppiumDriver/AndroidDriver
//and get Driver object
}
@Test
public void DummyTestMethod(){
Driver.launchApp()
Driver.openNotifications()
Driver.closeApp();
}
@AfterMethod
public void AfterMethodFunctionality() throws IOException, InterruptedException{
//Code To
//Cleanup and Kill Driver object
ScreenRecorder.StopScreenRecording(CurrentTestMethodName, "D:\\ScreenRecords", true);
}


}


Please comment, if this post is helpful.

Happy Automation !!

3 comments:

  1. But it will record Max for 3 min.if test case is more than that how will this work

    ReplyDelete
  2. But it will record Max for 3 min.if test case is more than that how will this work

    ReplyDelete
    Replies
    1. True. as screenrecord commands records for that much time only.
      In this case, I think that one of the below will be solution
      1. can go for recording multiple video
      2. update adb to record for any time duration

      Delete