从API版本26.0.0开始,新增碰一碰能力,提供顶端触碰方式,实现设备间的快速连接并进行数据交互。
在日常使用中,用户经常需要在两台设备之间快速传输数据或协同操作。例如,在聚会时想要交换名片、在游戏中想要邀请好友加入、在购物时想要分享商品信息等。传统的方式通常需要通过蓝牙配对、扫码添加好友等繁琐步骤,操作复杂且耗时。
碰一碰提供了一种简单直观的解决方案:用户只需将两台设备轻轻一碰,即可快速建立连接并进行数据传输。这种方式无需复杂的配对过程,操作简单自然,大大提升了用户体验。
碰一碰基于设备的近场通信能力,通过顶端碰的方式触发连接建立。当两台设备相碰时会自动识别并建立连接,然后通过回调机制通知应用。应用可以通过Connection对象发送消息,并通过回调接收消息。
设备需要打开WLAN和蓝牙开关。
需要申请权限ohos.permission.KNOCK_COLLABORATION,该能力受限开放。权限申请方式请参见申请使用受限权限。
碰一碰关键接口如下表所示。具体API说明详见接口文档。
| 接口名 | 描述 |
|---|---|
| onServiceInteraction(config: CollaborationConfig, callbacks: ServiceInteractionCallback): void | 注册碰一碰回调方法。 |
| offServiceInteraction(config: CollaborationConfig, callbacks?: ServiceInteractionCallback): void | 取消注册碰一碰回调方法。 |
| Connection.sendMessage(data: ArrayBuffer): Promise<void> | 向连接中的对端设备传递信息。使用Promise异步回调。 |
| Connection.disconnect(): Promise<void> | 断开与对端设备的连接。使用Promise异步回调。 |
导入serviceInteraction模块以及其他必要的工具模块。
- import { serviceInteraction } from '@kit.ServiceCollaborationKit';
- import { hilog } from '@kit.PerformanceAnalysisKit';
- import { util } from '@kit.ArkTS';
创建CollaborationConfig对象,配置触发类型、窗口ID等参数。
- const config: serviceInteraction.CollaborationConfig = {
- triggerType: serviceInteraction.TriggerType.KNOCK,
- windowId: 1, // 此处示例传入1,具体开发场景可通过this.getUIContext().getWindowId(); 来获取windowId。
- appLinking: 'https://example.com/app',
- timeOut: 10 // 可选,默认值为20秒
- };
通过onServiceInteraction接口注册回调方法,处理设备连接、断连、消息接收等事件。
- const callback: serviceInteraction.ServiceInteractionCallback = {
- onDeviceConnect: (connection: serviceInteraction.Connection) => {
- // 设备连接成功
- hilog.info(0, 'MEMOMOCK', '设备连接成功,connectId: ' + connection.connectId);
- },
- onDeviceDisconnect: (connection: serviceInteraction.Connection, retCode: number) => {
- // 设备断开连接
- hilog.info(0, 'MEMOMOCK', '设备断开连接,connectId: ' + connection.connectId + ',retCode: ' + retCode);
- },
- onMessageReceive: (connection: serviceInteraction.Connection, data: ArrayBuffer) => {
- // 收到对端消息
- hilog.info(0, 'MEMOMOCK', '收到消息,connectId: ' + connection.connectId);
- },
- onConnectFail: (retCode: number) => {
- // 连接失败
- hilog.error(0, 'MEMOMOCK', '连接失败,retCode: ' + retCode);
- }
- };
-
- try {
- serviceInteraction.onServiceInteraction(config, callback);
- hilog.info(0, 'MEMOMOCK', '注册成功');
- } catch (error) {
- hilog.error(0, 'MEMOMOCK', '注册失败,message:' + error.message);
- }
通过Connection对象的sendMessage方法向对端设备发送消息。
- // 发送消息
- const message: string = 'Hello from device A';
- const textEncoder: util.TextEncoder = new util.TextEncoder();
- const uint8Array = new Uint8Array(textEncoder.encodeInto(message).length);
- textEncoder.encodeIntoUint8Array(message, uint8Array);
-
- try {
- connection.sendMessage(uint8Array.buffer).then(() => {
- hilog.info(0, 'MEMOMOCK', '消息发送成功');
- }).catch((error: Error) => {
- hilog.error(0, 'MEMOMOCK', '消息发送失败: ' + error.message);
- });
- } catch (error) {
- hilog.error(0, 'MEMOMOCK', '发送失败,message:' + error.message);
- }
通过Connection对象的disconnect方法断开与对端设备的连接。
- try {
- connection.disconnect().then(() => {
- hilog.info(0, 'MEMOMOCK', '断开连接成功');
- }).catch((error: Error) => {
- hilog.error(0, 'MEMOMOCK', '断开连接失败: ' + error.message);
- });
- } catch (error) {
- hilog.error(0, 'MEMOMOCK', '断开失败,message:' + error.message);
- }
通过offServiceInteraction接口取消注册回调方法,停止接收回调事件。
- // 取消注册回调
- try {
- serviceInteraction.offServiceInteraction(config);
- hilog.info(0, 'MEMOMOCK', '取消注册成功');
- } catch (error) {
- hilog.error(0, 'MEMOMOCK', '取消注册失败,message:' + error.message);
- }
开发完成后,可以通过以下步骤验证功能:
以下示例展示了如何使用碰一碰功能实现双端设备交互的场景,包括消息发送和接收功能。
- import { serviceInteraction } from '@kit.ServiceCollaborationKit';
- import { hilog } from '@kit.PerformanceAnalysisKit';
- import { util } from '@kit.ArkTS';
-
- /**
- * 连接信息封装
- */
- interface ConnectionInfo {
- connection: serviceInteraction.Connection;
- deviceName: string;
- }
-
- /**
- * 核心流程:
- * 1. 注册监听:只注册一次onServiceInteraction
- * 2. 处理回调:每次设备相碰会触发回调,返回新的Connection
- * 3. 多Connection处理:使用connectionList管理多个连接,每个连接独立设置回调
- */
- @Entry
- @Component
- struct LuckyCardExchangePage {
- @State connectionStatus: string = '未连接';
- @State connectionList: ConnectionInfo[] = [];
- @State windowId: number = 0;
- private appLinking: string = 'https://example.com/luckycard/exchange';
- @State sendMessage: string = '';
- @State receivedMessage: string = '';
-
- aboutToAppear() {
- this.windowId = this.getUIContext().getWindowId() as number;
- this.registerServiceInteraction();
- }
-
- aboutToDisappear() {
- this.unregisterServiceInteraction();
- this.disconnectAll();
- }
-
- /**
- * 注册碰一碰监听
- */
- private registerServiceInteraction(): void {
- const config: serviceInteraction.CollaborationConfig = {
- triggerType: serviceInteraction.TriggerType.KNOCK,
- windowId: this.windowId,
- appLinking: this.appLinking
- };
-
- const callback: serviceInteraction.ServiceInteractionCallback = {
- onDeviceConnect: (connection: serviceInteraction.Connection) => {
- this.addConnection(connection);
- },
- onDeviceDisconnect: (connection: serviceInteraction.Connection, retCode: number) => {
- this.onDisconnected(connection, retCode);
- },
- onMessageReceive: (connection: serviceInteraction.Connection, data: ArrayBuffer) => {
- this.onMessageReceived(connection, data);
- },
- onConnectFail: (retCode: number) => {
- hilog.info(0, 'MEMOMOCK', '连接失败, 错误码是:' + retCode);
- },
- };
-
- try {
- serviceInteraction.onServiceInteraction(config, callback);
- } catch (error) {
- hilog.error(0, 'MEMOMOCK', '注册失败,message:' + error.message);
- }
- hilog.info(0, 'MEMOMOCK', '已注册服务交互监听');
- }
-
- /**
- * 取消注册监听
- */
- private unregisterServiceInteraction(): void {
- const config: serviceInteraction.CollaborationConfig = {
- triggerType: serviceInteraction.TriggerType.KNOCK,
- windowId: this.windowId,
- appLinking: this.appLinking
- };
-
- try {
- serviceInteraction.offServiceInteraction(config);
- } catch (error) {
- hilog.error(0, 'MEMOMOCK', '取消注册失败,message:' + error.message);
- }
- hilog.info(0, 'MEMOMOCK', '已取消服务交互监听');
- }
-
- /**
- * 添加新连接
- */
- private addConnection(connection: serviceInteraction.Connection): void {
- // 检查是否已存在相同connectId的连接
- const exists = this.connectionList.some(
- item => item.connection.connectId === connection.connectId
- );
-
- if (exists) {
- hilog.info(0, 'MEMOMOCK', '连接已存在,connectId: ' + connection.connectId);
- return;
- }
-
- // 创建新的连接信息
- const connectionInfo: ConnectionInfo = {
- connection: connection,
- deviceName: '设备' + (this.connectionList.length + 1)
- };
- // 添加到连接列表
- this.connectionList.push(connectionInfo);
- this.updateConnectionStatus();
-
- hilog.info(0, 'MEMOMOCK', '新连接成功,connectId: ' + connection.connectId +
- ',当前连接数: ' + this.connectionList.length);
- }
-
- /**
- * 处理断开连接
- */
- private onDisconnected(connection: serviceInteraction.Connection, retCode: number): void {
- const index = this.connectionList.findIndex(
- item => item.connection.connectId === connection.connectId
- );
-
- if (index > -1) {
- this.connectionList.splice(index, 1);
- hilog.info(0, 'MEMOMOCK', '连接已断开,connectId: ' + connection.connectId + ',retCode: ' + retCode);
- }
-
- this.updateConnectionStatus();
- }
-
- /**
- * 处理消息接收
- */
- private onMessageReceived(connection: serviceInteraction.Connection, data: ArrayBuffer): void {
- const connectionInfo = this.connectionList.find(
- item => item.connection === connection
- );
-
- const deviceName = connectionInfo ? connectionInfo.deviceName : '未知设备';
- hilog.info(0, 'MEMOMOCK', '收到消息,设备: ' + deviceName + ',connectId: ' + connection.connectId);
-
- // 解码消息内容
- const decoder = util.TextDecoder.create('utf-8');
- const str = decoder.decodeToString(new Uint8Array(data));
- hilog.info(0, 'MEMOMOCK', 'data: ' + data + ',str: ' + str);
-
- // 保存接收到的消息
- this.receivedMessage = str;
- }
-
- /**
- * 发送消息
- */
- private sendToAllDevices(): void {
- if (this.connectionList.length === 0) {
- hilog.warn(0, 'MEMOMOCK', '没有已连接的设备');
- return;
- }
-
- this.connectionList.forEach((connection) => {
- let textEncoder: util.TextEncoder = new util.TextEncoder();
- let uint8Array = new Uint8Array(textEncoder.encodeInto(this.sendMessage).length);
- textEncoder.encodeIntoUint8Array(this.sendMessage, uint8Array);
- try {
- connection.connection.sendMessage(uint8Array.buffer);
- } catch (error) {
- hilog.error(0, 'MEMOMOCK', '发送失败,message:' + error.message);
- }
- });
- }
-
- /**
- * 断开所有连接
- */
- private disconnectAll(): void {
- this.connectionList.forEach((connection) => {
- try {
- connection.connection.disconnect();
- } catch (error) {
- hilog.error(0, 'MEMOMOCK', '断开失败,message:' + error.message);
- }
- });
- this.connectionList = [];
- this.updateConnectionStatus();
- }
-
- /**
- * 更新连接状态
- */
- private updateConnectionStatus(): void {
- this.connectionStatus = this.connectionList.length > 0
- ? '已连接 ' + this.connectionList.length + ' 台设备'
- : '未连接';
- }
-
- build() {
- Column() {
- Text('碰一碰协同')
- .fontSize(24)
- .fontWeight(FontWeight.Bold)
- .margin({ top: 40, bottom: 20 })
-
- Text('连接状态: ' + this.connectionStatus)
- .fontSize(16)
- .margin({ bottom: 20 })
-
- if (this.connectionList.length > 0) {
- Text('已连接设备:')
- .fontSize(14)
- .margin({ bottom: 10 })
-
- ForEach(this.connectionList, (item: ConnectionInfo) => {
- Text(item.deviceName + ' (ID: ' + item.connection.connectId + ')')
- .fontSize(14)
- .margin({ bottom: 5 })
- })
- }
-
- Text('使用说明: 将两台设备相碰即可建立连接')
- .fontSize(12)
- .fontColor(Color.Gray)
- .margin({ top: 20 })
-
- if (this.connectionList.length > 0) {
- TextInput()
- .margin({ top: 20, bottom: 20 })
- .onChange((value) => {
- this.sendMessage = value;
- })
-
- Button('给已连接设备发送消息')
- .onClick(() => {
- this.sendToAllDevices();
- })
-
- Button('断连')
- .margin({ top: 10 })
- .onClick(() => {
- this.disconnectAll();
- })
- }
-
- if (this.receivedMessage != '' && this.connectionList.length > 0) {
- TextArea({
- text: this.receivedMessage
- })
- .margin({ top: 20, bottom: 20 })
- }
- }
- .width('100%')
- .height('100%')
- .padding(20)
- }
- }
合作咨询
我们的专家服务团队将竭诚为您提供专业的合作咨询服务
解决方案
精准高效的一站式服务支持,助力开发者商业成功