1. 项目概述
这个蓝牙远程控制项目实现了一套完整的Android手机远程控制解决方案,通过条件编译技术,用同一套代码同时支持控制端和被控端两种模式。控制端可以扫描并连接被控端设备,实现屏幕投射、触控操作和系统快捷控制等功能;被控端则负责接收指令、执行操作并返回屏幕数据。
这种设计最大的优势在于维护一套代码库就能满足两种角色的需求,通过简单的编译开关切换就能生成不同功能的APK。对于开发者来说,这大大减少了代码重复和维护成本;对于用户来说,只需要安装不同模式的APK就能实现设备间的互控。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 工程结构解析
2.1 项目目录结构
项目采用标准的Android Studio工程结构,但有一些值得注意的特殊设计:
code复制BtRemoteControl/
├── app/
│ ├── build.gradle
│ ├── proguard-rules.pro
│ └── src/main/
│ ├── AndroidManifest.xml
│ ├── java/com/bt/
│ │ ├── BuildConfig.java // 条件编译开关
│ │ ├── MainActivity.java // 自动入口
│ │ ├── Protocol.java // 通信协议
│ │ ├── BluetoothManager.java // 蓝牙核心
│ │ ├── client/ // 控制端代码
│ │ │ ├── BluetoothScanActivity.java
│ │ │ └── ControlActivity.java
│ │ └── server/ // 被控端代码
│ │ ├── TargetActivity.java
│ │ ├── AccessibilityControlService.java
│ │ ├── ScreenCaptureService.java
│ │ ├── KeepAliveService.java
│ │ └── BootReceiver.java
│ └── res/
│ ├── layout/
│ │ ├── activity_main.xml
│ │ ├── activity_bluetooth_scan.xml
│ │ ├── activity_control.xml
│ │ └── activity_target.xml
│ └── xml/
│ └── accessibility_config.xml
├── build.gradle
├── settings.gradle
└── gradle.properties
关键设计点:
- 客户端和服务端代码物理分离但共享核心模块
- 通过BuildConfig.java中的SERVER_MODE开关控制编译方向
- 公共蓝牙通信和协议处理代码放在根目录下
- 角色特定的代码分别放在client和server子包中
2.2 条件编译实现原理
条件编译的核心在于BuildConfig.java中的SERVER_MODE标志:
java复制package com.bt;
public class BuildConfig {
// ==============================
// 编译模式
// true = 服务端(被控端)
// false = 客户端(控制端)
// ==============================
public static final boolean SERVER_MODE = false;
}
MainActivity.java会根据这个标志决定启动路径:
java复制public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TextView tvMode = findViewById(R.id.tv_mode);
if (BuildConfig.SERVER_MODE) {
tvMode.setText("模式:被控端(服务端)");
startActivity(new Intent(this, com.bt.server.TargetActivity.class));
} else {
tvMode.setText("模式:控制端(客户端)");
startActivity(new Intent(this, com.bt.client.BluetoothScanActivity.class));
}
finish();
}
}
这种设计的好处是:
- 编译时只需修改一个开关就能生成不同功能的APK
- 避免了维护两套独立代码库的麻烦
- 公共代码更新会自动应用到两端
3. 核心模块实现
3.1 蓝牙通信协议设计
Protocol.java定义了所有通信指令和编解码方法:
java复制public class Protocol {
public static final byte TOUCH = 0x01; // 触控指令
public static final byte SYSTEM_CMD = 0x02; // 系统命令
public static final byte SCREEN_DATA = 0x03; // 屏幕数据
public static final byte HEARTBEAT = 0x04; // 心跳包
// 系统命令子类型
public static final byte SYS_VOL_UP = 1;
public static final byte SYS_VOL_DOWN = 2;
public static final byte SYS_BRIGHT_UP = 3;
public static final byte SYS_BRIGHT_DOWN = 4;
public static final byte SYS_WIFI_TOGGLE = 5;
public static final byte SYS_BT_TOGGLE = 6;
// 触控事件编码
public static byte[] encodeTouch(int action, int x, int y) {
return new byte[]{
TOUCH,
(byte) action,
(byte) (x >> 8),
(byte) (x & 0xFF),
(byte) (y >> 8),
(byte) (y & 0xFF)
};
}
// 系统命令编码
public static byte[] encodeSystemCmd(byte cmd) {
return new byte[]{SYSTEM_CMD, cmd};
}
}
协议设计考虑:
- 使用字节流而非文本协议,更节省带宽
- 每个指令以类型字节开头,便于解析
- 坐标使用16位整数传输(高8位+低8位)
- 心跳包维持连接状态
3.2 蓝牙通信核心实现
BluetoothManager.java封装了所有蓝牙操作:
java复制public class BluetoothManager {
private static final UUID SPP_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
private static BluetoothSocket socket;
private static InputStream in;
private static OutputStream out;
private static String targetMac;
// 服务端:启动监听
public static void startServer() {
new Thread(() -> {
try {
BluetoothServerSocket ss = BluetoothAdapter.getDefaultAdapter()
.listenUsingRfcommWithServiceRecord("SPP", SPP_UUID);
socket = ss.accept();
in = socket.getInputStream();
out = socket.getOutputStream();
startHeartBeat();
} catch (Exception e) {
