1.adb devices命令检测连接到PC端的所有设备,获取到已连接到的PC端的设备信息
2.将设备信息 端口 相关信息保存在List集合中 首先要实现能够在Java中执行dos环境下的命令
代码如下:
public class CmdUtil {
public static Logger logger = Logger.getLogger(CmdUtil.class);
/**
- 执行dos环境下命令工具方法
/
public static List execDosCmd(String cmdPara) {
//1、实例化runtime对象,运行时对象
Runtime runtime = Runtime.getRuntime();
//2、通过runtime对象的exec方法去执行dos命令
try {
//exec方法新建一个新得进程,去执行dos命令,返回得是process对象-管理这个进程
//cmd /c 打开窗口需要关闭
Process process = runtime.exec(“cmd /c “+cmdPara);
//IO操作
//得到process对象的输入流
InputStream inputStream = process.getInputStream();
//字节流转换成字符流才能进行读取
InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
//读取里面的内容
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
//读取到的每一行内容
//初始化一个list集合,用于保存命令的结果输出
List list = new ArrayList<>();
String content =””;
while((content=bufferedReader.readLine()) != null) {
//判断Appium启动成功与否
if(content.contains(“Appium REST http interface listener started on”)){
logger.info(“Appium启动成功!!!”);
}
//把输出内容保存到list集合中
list.add(content);
}
//返回给调用者
return list;
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
/*- 用来获取当前连接到PC端的所有设备deviceName
*/
public static List getUdidList(){
//1、执行adb devices命令
List results = execDosCmd(“adb devices”);
//初始化一个List集合,用来保存解析的结果
List udidList = new ArrayList();
for (int i = 0; i < results.size(); i++) {
//3、跳过第一行List of devices attached,以及跳过最后空白行的处理
if(i != 0 && i !=(results.size()-1)){
//4、通过制表符分割字符串emulator-5554 device
String line = results.get(i);
String[] arr = line.split("\t");
//把数组的第一个元素也就是deviceName保存到udidList中
udidList.add(arr[0]);
}
}
//如果当前没有设备链接上PC,没有必要继续执行下去
if(udidList.size() == 0){
//做日志
logger.info(“当前没有设备链接到PC端,请检查”);
System.exit(0);
}
return udidList;
}
}
- 用来获取当前连接到PC端的所有设备deviceName
3.检测端口是否被占用,如果有则杀死进程释放对应端口
public class PortUtil {
public static Logger logger = Logger.getLogger(PortUtil.class);
/**
* 获取端口列表 4723->4725->4727->…
* 8200->8202-8204->…
* @param startPort 起始端口 4723 / 8200
* @param deviceNum 设备的数量
/
public static List getPortList(int startPort,int deviceNum){
//保存所有的端口号的
List portList = new ArrayList();
while(portList.size() != deviceNum){
//端口的检测与释放
if(checkPortIfUsed(startPort)){
logger.info(“端口【”+startPort+"】被占用");
//根据端口号获取进程号,然后再杀死进程
int pid = getPidByPort(startPort);
killProcessByPid(pid);
}
portList.add(startPort);
startPort = startPort + 2;
}
return portList;
}
/*
* 检测端口是否有被占用
/
public static Boolean checkPortIfUsed(int port){
List result = CmdUtil.execDosCmd("netstat -ano | findstr "+port);
if(result.size() == 0){
return false;
}else{
return true;
}
}
/*
* 根据端口得到对应进程的PID
/
public static int getPidByPort(int port){
List result = CmdUtil.execDosCmd(“netstat -ano | findstr “+port);
for (int i = 0; i < result.size(); i++) {
//通过/s进行字符串的分割 获取第一行
String[] content = result.get(0).split(”\s”);
//数组的最后一个元素即为PID
//String类型转换成int
return Integer.parseInt(content[content.length-1]);
}
return 0;//正常退出
}
/*
* 根据pid杀死对应的进程
*/
public static void killProcessByPid(int pid){
List result = CmdUtil.execDosCmd(“taskkill -f -pid “+pid);
if(result.get(0).contains(pid+””)){
logger.info(“杀死进程【”+pid+"】成功");
}
}
}
4.根据收集到的信息启动appium service,测试结束,杀死所有的Appium Server
/**
- 管理Appium服务的工具类,启动/关闭
/
public class AppiumServerUtil {
//初始化log4j日志对象
public static Logger logger = Logger.getLogger(AppiumServerUtil.class);
// Appium main.js的路径
public static final String appiumJsPath = “C:\Users\Pactera\AppData\Local\Programs\Appium\resources\app\node_modules\appium\build\lib\main.js”;
// Appium运行时日志的存储路径
public static final String appiumLogPath = “D:\workspace2\app_test_cxq\log\appium.log”;
//appium监听端口的集合
public static List appiumPortList;
//uiautomator2引擎集合
public static List uiautomator2PortList;
/*-
启动appium服务
-
@author caoqingqing
-
@date 2020年9月24日
*/
public static void startAppiumServer(){
// 1、得到所有的deviceName列表
List udidList = CmdUtil.getUdidList();
// 2、得到Appium监听的端口列表4723 4725 4727…
// 3、组装所有启动Appium服务的命令与参数,类似于node main.js -a 127.0.0.1 -p 4723
appiumPortList = PortUtil.getPortList(4723, udidList.size());
uiautomator2PortList = PortUtil.getPortList(8200, udidList.size());
// 3、组装所有启动Appium服务的命令与参数,类似于node main.js -a 127.0.0.1 -p 4723
// --session-overried
// 由设备的数量去决定启动Appium服务的命令参数有多少条
for (int i = 0; i < udidList.size(); i++) {
// Appium日志地址
String logPath = appiumLogPath + “appium” + i + “.log”;
String command = “node " + appiumJsPath + " -a 127.0.0.1” + " -p " + appiumPortList.get(i) + " --log "
+ logPath + " --session-override";
//4、启动Appium Server
//进程阻塞:第一个Appium起来之后常驻进程运行,运行第二条启动Appium的时候会出现阻塞的问题,整个程序是单进程
//多线程–》每一个Appium Server都是通过单独的线程执行(Java自带的多线程)
new Thread(new Runnable() {
@Override
public void run() {
//启动Appium Server
CmdUtil.execDosCmd(command);
}
}).start();}
}
/** -
测试结束,杀死所有的Appium Server
*/
public static void stopAppiumServer(){
logger.info("=测试结束,关闭所有的Appium Server==");
for (Integer port : appiumPortList) {
int pid = PortUtil.getPidByPort(port);
PortUtil.killProcessByPid(pid);
}
}
}
-
**tips:**由于appium的启动需要依赖于特定的端口,如果参数中的端口(如:4723)被占用,那么appium启动将会失败