Android设备使用USB数据线与Pc端通信开发日记

         最近公司给了一个任务,需要开发一个安卓自动化测试工具,使用USB数据线连接pc端和设备,配合pc端软件一键验证设备功能是否正常。

        为什么要开发这样的一个软件,主要是公司设备大量生产出来以后,要测试设备功能(设备电压、串口通信、拍照、SIM卡通信等功能),手动一个一个功能测试浪费时间,所以就需要实现自动化测试。和同事商量了下,使用adb forward转发tcp端口进行设备和计算机之间的通信。

熟悉安卓开发的都知道ADB 是Android SDK自带最常用且功能强大的工具,它的主要功能:

安装、卸载应用:adb install app.apk,adb uninstall com.example.app
设备重启、恢复出厂设置:adb reboot,adb reboot recovery
查看日志:adb logcat
文件传输:adb push local_file remote_file,adb pull remote_file local_file
端口转发:adb forward tcp:8001 tcp:8001

在 Android 开发中,ADB (Android Debug Bridge) 的 adb forward 命令允许在开发计算机和连接的 Android 设备之间建立端口转发,从而实现服务端和客户端之间的通信。

adb forward 命令的基本语法是:

adb forward <local> <remote>

  • <local>: 开发计算机上的端口

  • <remote>: Android 设备上的端口

常见用途

1. TCP 端口转发

最常见的用法是将本地端口转发到设备端口:

adb forward tcp:8001 tcp:8001

这会将计算机的 8001 端口转发到设备的 8001 端口。

2、查看和移除转发
  • 查看所有活跃的转发:

    adb forward --list
  • 移除特定转发:

    adb forward --remove tcp:8001
  • 移除所有转发:

    adb forward --remove-all

言归正传,看看代码实现。计算机作为客户端,使用java实现,设备Android端作为服务端

Java服务端和Android客户端通信

Java客户端代码
   public static void main(String[] args) {
        // 先设置ADB端口转发
        if (!setupForward(8001, 8001)) {
            System.err.println("无法建立ADB端口转发");
            return;
        }

        // 连接到转发端口
        try (Socket socket = new Socket("localhost", 8001);
             PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
             BufferedReader in = new BufferedReader(
                     new InputStreamReader(socket.getInputStream()));
             BufferedReader stdIn = new BufferedReader(
                     new InputStreamReader(System.in))) {

            System.out.println("已连接到Android服务端,输入消息开始通信...");

            String userInput;
            while ((userInput = stdIn.readLine()) != null) {
                out.println(userInput);
                System.out.println("服务端回应: " + in.readLine());
                // TODO 实现自己的业务逻辑

            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // 移除端口转发
            try {
                removeForward(8001);
            } catch (AdbException e) {
                throw new RuntimeException(e);
            }
        }
    }


    /**
     * 设置端口转发(增强版)
     */
    public static boolean setupForward(int localPort, int remotePort) {
        try {
            String result = executeAdbCommand(
                    String.format("forward tcp:%d tcp:%d", localPort, remotePort), 5);
            System.out.println("ADB Forward Result: " + result);
            return true;
        } catch (Exception e) {
            System.err.println("设置端口转发失败: " + e.getMessage());
            return false;
        }
    }



    /**
     * 执行ADB命令
     */
    public static String executeAdbCommand(String... commands) throws AdbException {
        List<String> commandList = new ArrayList<>();
        commandList.add("adb");
        commandList.addAll(Arrays.asList(commands));

        try {
            ProcessBuilder pb = new ProcessBuilder(commandList)
                    .redirectErrorStream(true);

            Process process = pb.start();

            // 使用Future和ExecutorService实现超时控制
            ExecutorService executor = Executors.newSingleThreadExecutor();
            Future<String> future = executor.submit(() -> {
                try (BufferedReader reader = new BufferedReader(
                        new InputStreamReader(process.getInputStream()))) {
                    StringBuilder output = new StringBuilder();
                    String line;
                    while ((line = reader.readLine()) != null) {
                        output.append(line).append("\n");
                    }
                    return output.toString();
                }
            });

            try {
                return future.get(DEFAULT_TIMEOUT, TimeUnit.SECONDS);
            } catch (TimeoutException e) {
                process.destroy();
                throw new AdbException("ADB命令执行超时");
            } finally {
                executor.shutdownNow();
                if (process.isAlive()) {
                    process.destroy();
                }
            }
        } catch (IOException | InterruptedException | ExecutionException e) {
            throw new AdbException("执行ADB命令失败: " + e.getMessage());
        }
    }



    /**
     * 移除端口转发
     */
    public static void removeForward(int localPort) throws AdbException {
        executeAdbCommand("forward", "--remove", "tcp:" + localPort);
    }

    /**
     * 检查设备连接状态
     *
     */
    public static boolean isDeviceConnected() {
        try {
            String output = executeAdbCommand("devices");
            return output != null && output.contains("\tdevice");
        } catch (AdbException e) {
            return false;
        }
    }

    public static class AdbException extends Exception {
        public AdbException(String message) {
            super(message);
        }
    }

Android服务端代码

 private String TAG = TcpServerHelper.class.getSimpleName();
    public static boolean tcpIsSendSuccess = false;
    public static boolean available = true;
    public static int dataAreaLength = 0;
    private int port;//端口
    private long lastReConnectTime = 0;//上一次重连时间
    private ConcurrentHashMap<String, ClientHandler> connectedClients;
    private boolean isRunning;
    private ServerSocket serverSocket;

    public TcpServerHelper(int port) {
        this.port = port;
        tcpConnect(port);
    }

    public void tcpConnect(int port) {
        this.port = port;
        connectedClients = new ConcurrentHashMap<>();
        start();
    }

    

    public void reConnect() {
        if ((System.currentTimeMillis() - lastReConnectTime) > 1000 * 5 && !tcpIsSendSuccess) {//上一次重连间隔应大于10秒
            UIUtils.runOnUIThread(new Runnable() {
                @Override
                public void run() {
                    PhoneUtil.wakeUpAndUnlock();
                }
            });
            try {
                stop();
                Thread.sleep(2000);
                start();
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }

        }
    }


   
    public void closeConnect() {
        LogUtils.e(TAG, "关闭连接");
        stop();
    }

  
    public boolean sendData(byte[] data) {
        ThreadManager.getThreadPool().execute(new Runnable() {
            @Override
            public void run() {
                try {
                    for (ClientHandler client : connectedClients.values()) {
                        // 这里可以根据需求向特定设备发送数据
                        if (client.isConnected()) {//客户端是连接状态
                            client.sendMessage(data);
                        }
                    }
                } catch (Exception e) {
                    LogUtils.e("发送失败" + e.getMessage());
                    tcpIsSendSuccess = false;
                    reConnect();
                    e.printStackTrace();

                }
            }
        });
        return true;
    }

 

    public void start() {
        isRunning = true;
        ThreadManager.getThreadPool().execute(new Runnable() {
            @Override
            public void run() {
                try {
                    serverSocket = new ServerSocket(port);
                    Log.d(TAG, "Server started on port " + port);
                    while (isRunning) {
                        Socket clientSocket = serverSocket.accept();
                        String clientId = clientSocket.getInetAddress().getHostAddress() + ":" + clientSocket.getPort();
                        Log.d(TAG, "New client connected: " + clientId);
                        ClientHandler clientHandler = new ClientHandler(clientSocket, clientId);
                        connectedClients.put(clientId, clientHandler);
                        ThreadManager.getThreadPool().execute(clientHandler);
                    }
                } catch (IOException e) {
                    if (isRunning) {
                        Log.d(TAG, "Server error: " + e.getMessage());
                    }
                }
            }
        });
    }

    public void stop() {
        isRunning = false;
        try {
            if (null != connectedClients) {
                // 关闭所有客户端连接
                for (ClientHandler client : connectedClients.values()) {
                    client.close();
                }
                connectedClients.clear();
            }
            if (null != serverSocket && !serverSocket.isClosed()) {
                serverSocket.close();
            }
            Log.d(TAG, "Server stopped");
        } catch (IOException e) {
            Log.d(TAG, "Error stopping server: " + e.getMessage());
        }
    }


    /**
     * 客户端管理线程
     */
    private class ClientHandler implements Runnable {
        private final Socket socket;
        private final String clientId;
        private boolean connected;
        private InputStream inputStream;

        public ClientHandler(Socket socket, String clientId) {
            this.socket = socket;
            this.clientId = clientId;
            this.connected = true;
        }

        public boolean isConnected() {
            return connected;
        }

        public void sendMessage(byte[] data) {
            try {
                if (connected) {
                    socket.getOutputStream().write(data);
                    socket.getOutputStream().flush();
                }
            } catch (IOException e) {
                Log.e(TAG, "Error sending to " + clientId + ": " + e.getMessage());
                close();
            }
        }

        @Override
        public void run() {

            try {
                while (connected) {
                    LogUtils.e("开启tcp线程");
                    if (null == inputStream) {
                        inputStream = socket.getInputStream();
                    }
                    int testCount = 0;
                    //TODO 读取数据业务逻辑

                }
            } catch (IOException e) {
                Log.e(TAG, "Client " + clientId + " error: " + e.getMessage());
            } finally {
                if (null != inputStream) {
                    try {
                        inputStream.close();
                        inputStream = null;
                    } catch (IOException ignored) {
                    }
                }
                close();
            }
        }

        public void close() {
            connected = false;
            try {
                if (socket != null && !socket.isClosed()) {
                    socket.close();
                }
                connectedClients.remove(clientId);
                Log.d(TAG, "Client disconnected: " + clientId);
            } catch (IOException e) {
                Log.e(TAG, "Error closing client " + clientId + ": " + e.getMessage());
            }
        }
    }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值