【鸿蒙】在DevEcoStudio中实现手机端与手表端模拟器通信
前提:需要将手机端与手表端分别部署在两个项目上,因为DevEco Studio 同一项目无法同时运行两种设备类型的模拟器,部署第二个会覆盖第一个。
一、项目架构
| 项目 | 设备类型 | 职责 |
| A | wearable(手表端) | TCP客户端,发送请求 |
| B | phone(手机端) | TCP服务端,接收并处理请求 |
二、关键配置
1.权限配置(项目根目录\entry\src\main\module.json5)
- 手表端:
ohos.permission.INTERNET、ohos.permission.DISTRIBUTED_DATASYNC - 手机端:
ohos.permission.INTERNET
"requestPermissions": [
{
"name": "ohos.permission.INTERNET",
"reason": "$string:internet_reason",
"usedScene": {
"abilities": ["EntryAbility"],
"when": "inuse"
}
},
{
"name": "ohos.permission.DISTRIBUTED_DATASYNC", //仅手表端
"reason": "$string:distributed_reason",
"usedScene": {
"abilities": ["EntryAbility", "WearableAbility"],
"when": "inuse"
}
}
]
其中,"$string:internet_reason"和"$string:distributed_reason"需要分别在各自项目根目录\entry\src\main\resources\base\element\string.json中进行配置:
{
"name": "internet_reason",
"value": "用于与服务器通信,获取设备状态和发送控制指令"
},
{
"name": "distributed_reason",
"value": "分布式权限"
}
2.模拟器代理配置
启动模拟器后右边栏有三根线,点击可以进行“网络”配置

- 手表端模拟器网络代理必须选"无代理"
- 若设置手工代理会导致所有 HTTP 请求走代理服务器,代理不存在则全部失败

三、核心代码
手机端:TCP 服务器
项目根目录\entry\src\main\ets\pages\Index.ets
this.tcpServer = socket.constructTCPSocketServerInstance();
await this.tcpServer.listen({ address: '0.0.0.0', port: 8888, family: 1 });
this.tcpServer.on('connect', (connection) => {
connection.on('message', (recv) => { /* 处理消息 */ });
});
手表端:TCP 客户端
项目根目录\entry\src\main\ets\common\TCPuser.ets:
this.tcpClient = socket.constructTCPSocketInstance();
const phoneIp = '10.0.2.2'; // 宿主机网关地址
await this.tcpClient.connect({ address: { address: phoneIp, port: 8888, family: 1 } });
await this.tcpClient.send({ data });
项目根目录\entry\src\main\ets\pages\Index.ets需要调用TCPuser:
TCPuser()
其中,宿主机网关地址是如何得到的呢?终端执行:
hdc list targets # 查看模拟器设备对应端口
【注:若提示无法识别hdc指令,报错如下图所示,则是因为hdc没有事先配置在环境变量当中,可以看“附录一”先进行hdc配置】

如下图所示,执行指令得到的127.0.0.1:5555/5557分别是手表模拟器、手机模拟器对应的hdc调试端口(主机用来连接模拟器进行部署、日志等操作)

然后在终端执行命令:
hdc -t 127.0.0.1:5557 shell ifconfig #127.0.0.1:5557是上一条指令查到的手机模拟器调试端口
获得127.0.0.1:5557hdc调试端口对应的手机模拟器的ip地址10.0.2.15

四、端口转发
两个模拟器网络互相隔离,无法直接通信,必须通过主机端口转发桥接
hdc -t 127.0.0.1:5557 fport tcp:8888 tcp:8888
含义:主机 8888 端口 → 手机模拟器(5557) 的 8888 端口
手表模拟器访问 10.0.2.2(模拟器视角的宿主机网关)→ 流量到达主机 8888 → 转发到手机模拟器 8888。
五、IP地址说明
| 地址 | 含义 |
| 本机地址 | 主机IP,模拟器内不可用 |
| 10.0.2.15 | 模拟器自身IP |
| 10.0.2.2 | 模拟器访问宿主机的网关地址 |
| 127.0.0.1:5555/5557 | hdc调试端口,与TCP8888无关 |
六、完整启动流程
- 启动手机模拟器 + 手表模拟器
- 部署手机端项目 → 手机模拟器
- 部署手表端项目 → 手表模拟器
- 执行
hdc -t 127.0.0.1:5557 fport tcp:8888 tcp:8888 - 手表端发送消息 → 手机端收到消息
七、示意代码
注:需要预先按照“二、关键配置”配置好module.json5
说明:以下示意代码省略了我项目中的一些页面代码,所以直接复制粘贴是无法运行的,仅供参考,了解如何进行使用
手表端 项目根目录\entry\src\main\ets\common\TCPuser.ets(然后在pages\Index.ets中调用)
// products/wearable/src/main/ets/common/VoiceAssistant/VoiceAssistant.ets
import promptAction from '@ohos.promptAction';
import socket from '@ohos.net.socket';
@Component
export struct VoiceAssistant {
@State offsetX: number = 0;
@State offsetY: number = 0;
private startX: number = 0;
private startY: number = 0;
private panOption: PanGestureOptions = new PanGestureOptions({ direction: PanDirection.All });
private tcpClient: socket.TCPSocket | null = null;
private isConnected: boolean = false;
aboutToAppear() {
this.loadOffset();
this.connectToPhone();
}
async connectToPhone() {
try {
this.tcpClient = socket.constructTCPSocketInstance();
// 通过 hdc fport 转发后,连接宿主机网关地址
const phoneIp = '10.0.2.2';
await this.tcpClient.connect({ address: { address: phoneIp, port: 8888, family: 1 } });
this.isConnected = true;
console.info('已连接手机');
} catch (err) {
console.error('连接失败', JSON.stringify(err));
promptAction.showToast({ message: '连接手机失败' });
}
}
async sendHello() {
if (!this.isConnected) {
promptAction.showToast({ message: '未连接手机' });
return;
}
const data = this.stringToArrayBuffer('Hello World');
try {
await this.tcpClient!.send({ data });
promptAction.showToast({ message: '已发送 Hello World' });
} catch (err) {
promptAction.showToast({ message: '发送失败' });
}
}
stringToArrayBuffer(str: string): ArrayBuffer {
const buf = new ArrayBuffer(str.length);
const view = new Uint8Array(buf);
for (let i = 0; i < str.length; i++) {
view[i] = str.charCodeAt(i);
}
return buf;
}
// ... 拖拽逻辑保持不变 ...
loadOffset() { /* 原有代码 */ }
saveOffset() { /* 原有代码 */ }
build() {
Column() {
Text('🐱')
.fontSize(48)
}
.width(70)
.height(70)
.backgroundColor('#4A90E2')
.borderRadius(35)
.justifyContent(FlexAlign.Center)
.alignItems(HorizontalAlign.Center)
.shadow({ radius: 8, color: '#00000040' })
.offset({ x: this.offsetX, y: this.offsetY })
.gesture(
PanGesture(this.panOption)
.onActionStart((event: GestureEvent) => {
this.startX = event.offsetX;
this.startY = event.offsetY;
})
.onActionUpdate((event: GestureEvent) => {
this.offsetX = this.offsetX + (event.offsetX - this.startX);
this.offsetY = this.offsetY + (event.offsetY - this.startY);
this.startX = event.offsetX;
this.startY = event.offsetY;
})
.onActionEnd(() => {
this.saveOffset();
})
)
.onClick(() => {
this.sendHello(); // 点击小猫直接发送 Hello World
})
}
}
手机端 项目根目录\entry\src\main\ets\pages\Index.ets
import socket from '@ohos.net.socket';
import promptAction from '@ohos.promptAction';
interface MessageEvent {
message: ArrayBuffer;
}
@Entry
@Component
struct Index {
private tcpServer: socket.TCPSocketServer | null = null;
@State log: string = '服务端未启动';
aboutToAppear() {
this.startServer();
}
async startServer() {
try {
this.tcpServer = socket.constructTCPSocketServerInstance();
await this.tcpServer.listen({ address: '0.0.0.0', port: 8888, family: 1 });
this.log = '服务端已启动,监听8888端口';
this.tcpServer.on('connect', (connection: socket.TCPSocketConnection) => {
this.log += `\n客户端已连接`;
connection.on('message', (recv: MessageEvent) => {
const msg = this.arrayBufferToString(recv.message);
this.log += `\n收到: ${msg}`;
promptAction.showToast({ message: `收到: ${msg}` });
});
});
} catch (err) {
this.log = `启动失败: ${JSON.stringify(err)}`;
console.error('服务端错误', err);
}
}
arrayBufferToString(buf: ArrayBuffer): string {
return String.fromCharCode(...new Uint8Array(buf));
}
build() {
Column() {
Text('手机服务端').fontSize(24).margin(20);
Scroll() {
Text(this.log).fontSize(16).padding(10).width('100%').textAlign(TextAlign.Start);
}
.height('80%')
.backgroundColor('#F5F5F5')
.margin(10)
}
.width('100%')
.height('100%')
}
}
手表端发送Hello World

手机端接收

附录一、配置hdc环境变量
1. 找到 hdc.exe 的路径,通常在 DevEco Studio 安装目录下(默认安装在C盘):
比如我的hdc放在E:\Huawei\DevEco Studio\sdk\default\openharmony\toolchains\
2.将该路径添加到系统环境变量 PATH 中。
注:环境变量修改后需要重启终端才能生效,不需要重启计算机。
3.重新打开终端,即可使用 hdc 命令。
更多推荐



所有评论(0)