【HarmonyOS 6】UIAbility跨设备连接详解(分布式软总线运用)
【HarmonyOS 6】UIAbility跨设备连接详解(分布式软总线运用)
一、前言
我对于分布式软总线相当的亲切。2022年搞开源鸿蒙的时候,就经常和分布式软总线打交道。在HarmonyOS中,UIAbility跨设备连接,其实就是对底层开源鸿蒙,分布式软总线的能力封装。
二、首先理解跨设备链接的步骤

首先由Distributed Service Kit提供该能力的封装。
在进行跨设备链接之前,我们要对设备进行互信操作。这个在鸿蒙里叫做分布式设备管理,包含了设备的发现,配对,可信查询,解除配对等。详情可参见我之前写的文章:【HarmonyOS 5】鸿蒙分布式协同应用开发详解
进行完上面的可信操作,我们才能对于设备间的链接通信做处理。
三、专有名词理解:
DMS(Distributedsched Management Service):
分布式组件管理框架,相当于跨设备协同的“中间人”,负责管理组件和建立连接
UIAbility:
应用的界面交互核心,管生命周期、用户交互和界面渲染,跨设备协同本质就是两台设备的UIAbility在“对话”
四、环境准备步骤
工欲善其事,先把环境搭好:
1、硬件:两台能登录华为账号的设备(A和B),需要支持API 18
2、开发工具:DevEco Studio 4.1及以上,public-SDK更新到API 18+
3、设备连接:用USB线把两台设备连到PC,打开蓝牙让设备互相识别组网
4、验证组网:PC端执行shell命令,显示“remote device num = 1”就是组网成功
hdc shell
hidumper -s 4700 -a "buscenter -l remote_device_info"
也可通过前置步骤的分布式设备管理,来验证设备的可信。
五、源码步骤拆解:

1、 导入核心模块
首先要导入分布式服务相关的Kit,不管是发起端还是接收端都需要:
import { abilityConnectionManager, distributedDeviceManager } from '@kit.DistributedServiceKit';
import { common, AbilityConstant, UIAbility, Want } from '@kit.AbilityKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
2、 发现目标设备(设备A侧)
设备A要先找到设备B的networkId,作为连接的关键参数:
let dmClass: distributedDeviceManager.DeviceManager;
// 初始化设备管理实例
function initDmClass(): void {
try {
dmClass = distributedDeviceManager.createDeviceManager('com.example.remotephotodemo');
} catch (err) {
hilog.error(0x0000, 'testTag', '创建设备管理实例失败: ' + JSON.stringify(err));
}
}
// 获取设备B的networkId
function getRemoteDeviceId(): string | undefined {
initDmClass();
if (!dmClass) return undefined;
hilog.info(0x0000, 'testTag', '开始查找远程设备');
const deviceList = dmClass.getAvailableDeviceListSync();
if (!deviceList || deviceList.length === 0) {
hilog.info(0x0000, 'testTag', '未找到可用设备');
return undefined;
}
// 这里取第一个设备,实际开发可做设备选择列表
return deviceList[0].networkId;
}
3、创建会话并连接(两端操作不同)
设备A(发起端):创建会话+发起连接
@StorageLink('sessionId') sessionId: number = -1;
// 配置设备B的协同信息
const peerInfo: abilityConnectionManager.PeerInfo = {
deviceId: getRemoteDeviceId()!, // 设备B的networkId
bundleName: 'com.example.remotephotodemo', // 必须和设备B应用一致
moduleName: 'entry',
abilityName: 'EntryAbility',
serviceName: 'collabTest' // 自定义服务名,两端要一致
};
// 连接配置
const connectOptions: abilityConnectionManager.ConnectOptions = {
needSendData: true,
startOptions: abilityConnectionManager.StartOptionParams.START_IN_FOREGROUND,
parameters: { "newKey1": "value1" }
};
// 发起连接
async function connectRemoteAbility() {
const context = this.getUIContext().getHostContext();
try {
// 创建会话,获取sessionId
this.sessionId = abilityConnectionManager.createAbilityConnectionSession(
"collabTest",
context,
peerInfo,
connectOptions
);
hilog.info(0x0000, 'testTag', `创建会话成功,sessionId: ${this.sessionId}`);
// 发起连接(会拉起设备B的应用)
const connectResult = await abilityConnectionManager.connect(this.sessionId);
if (!connectResult.isConnected) {
hilog.info(0x0000, 'testTag', '连接失败');
return;
}
hilog.info(0x0000, 'testTag', '连接成功');
} catch (error) {
hilog.error(0x0000, 'testTag', `连接异常: ${JSON.stringify(error)}`);
}
}
设备B(接收端):被拉起后接受连接
设备A发起连接后,设备B的应用会被协同拉起,触发onCollaborate生命周期函数:
export default class EntryAbility extends UIAbility {
onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
hilog.info(0x0000, 'testTag', '应用启动');
}
// 协同拉起时触发
onCollaborate(wantParam: Record<string, Object>): AbilityConstant.CollaborateResult {
hilog.info(0x0000, 'testTag', '收到协同请求');
const collabParam = wantParam["ohos.extra.param.key.supportCollaborateIndex"] as Record<string, Object>;
this.handleCollaborate(collabParam);
return 0;
}
// 处理协同连接
private async handleCollaborate(collabParam: Record<string, Object>) {
const sessionId = this.createSessionFromParam(collabParam);
if (sessionId === -1) {
hilog.error(0x0000, 'testTag', '会话创建失败');
return;
}
// 获取协同token,必须传入acceptConnect
const collabToken = collabParam["ohos.dms.collabToken"] as string;
try {
await abilityConnectionManager.acceptConnect(sessionId, collabToken);
hilog.info(0x0000, 'testTag', '接受连接成功');
AppStorage.setOrCreate('sessionId', sessionId);
} catch (error) {
hilog.error(0x0000, 'testTag', `接受连接失败: ${JSON.stringify(error)}`);
}
}
// 从协同参数创建会话
private createSessionFromParam(collabParam: Record<string, Object>): number {
let sessionId = -1;
const peerInfo = collabParam["PeerInfo"] as abilityConnectionManager.PeerInfo;
const connectOptions = collabParam["ConnectOption"] as abilityConnectionManager.ConnectOptions;
if (!peerInfo || !connectOptions) return sessionId;
// 配置数据传输能力
connectOptions.needSendData = true;
connectOptions.needSendStream = true;
try {
sessionId = abilityConnectionManager.createAbilityConnectionSession(
"collabTest",
this.context,
peerInfo,
connectOptions
);
} catch (error) {
hilog.error(0x0000, 'testTag', `创建会话失败: ${JSON.stringify(error)}`);
}
return sessionId;
}
}
4、 注册事件监听(两端都要加)
连接成功后,通过监听事件获取连接状态和消息:
function registerEventListeners(sessionId: number) {
// 监听连接成功事件
abilityConnectionManager.on("connect", sessionId, (callbackInfo) => {
hilog.info(0x0000, 'testTag', `会话${callbackInfo.sessionId}连接成功`);
});
// 监听断开连接事件
abilityConnectionManager.on("disconnect", sessionId, (callbackInfo) => {
hilog.info(0x0000, 'testTag', `会话${callbackInfo.sessionId}已断开`);
});
// 监听接收消息事件
abilityConnectionManager.on("receiveMessage", sessionId, (callbackInfo) => {
hilog.info(0x0000, 'testTag', `收到消息: ${callbackInfo.message}, 会话ID: ${callbackInfo.sessionId}`);
// 这里可以处理业务逻辑,比如更新UI显示消息
});
}
5、 发送消息(两端都可发)
连接成功后,用sendMessage发送文本信息:
async function sendTestMessage(sessionId: number) {
try {
await abilityConnectionManager.sendMessage(sessionId, "这是来自设备A的测试消息");
hilog.info(0x0000, 'testTag', '消息发送成功');
} catch (error) {
hilog.error(0x0000, 'testTag', `消息发送失败: ${JSON.stringify(error)}`);
}
}
6、 结束协同(关键!避免资源泄露)
业务完成后一定要断开连接或销毁会话:
function endCollaboration(sessionId: number) {
if (sessionId === -1) {
hilog.info(0x0000, 'testTag', '无效的会话ID');
return;
}
// 短期还需协同:只断开连接,保留sessionId
abilityConnectionManager.disconnect(sessionId);
hilog.info(0x0000, 'testTag', '已断开连接');
// 长期不用:销毁会话(自动断开连接)
abilityConnectionManager.destroyAbilityConnectionSession(sessionId);
hilog.info(0x0000, 'testTag', '已销毁会话');
}
五、注意事项:
- 仅支持API 18及以上版本,且设备必须登录相同华为账号
- 只有相同bundleName的UIAbility才能协同(比如都是“com.example.remotephotodemo”)
- 协同结束后一定要及时关闭,锁屏或退后台5秒未申请长时任务,协同会被系统强制结束
- 传输隐私数据时,记得加弹框提醒用户(系统不审查传输内容)
更多推荐



所有评论(0)