news 2026/5/28 11:48:22

如何让你的APP吃上鸿蒙PC端红利(二)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
如何让你的APP吃上鸿蒙PC端红利(二)

鸿蒙电脑 Harmony OS 6了,再不入局就晚了

尊贵的鸿蒙电脑用户,付费能力可以说是全球最强,遥遥...

Harmony OS 5的时候不入局是对的,装机少,系统bug多,适配的app也少。

自从升级Harmony OS 6,各方各面都完善起来,市场风向也从

下着玩玩-到了-用户刚需。

很多手机端优秀app的开发者发现,一旦兼容2IN1,(2IN1是华为对PC电脑设备的统称)

运营统计中曾经占比渺小的2IN1设备,

开始节节攀升。

摆在我们开发者面前有几个问题需要解决:

1.不重开发,如何兼容2IN1?(请看系列一)

2.有2IN1的用户通常有华为手机,甚至多数有全家桶,应该为APP加入哪些功能增强竞争力

3.买不起昂贵的PC,该怎么开发、测试

关注我,将在接下来的系列中,用实战中的经验,解决以上三个问题。

第二问:有2IN1的用户通常是全家桶用户,应该如何增强竞争力?

回答:跨设备协同体验

鸿蒙(HarmonyOS)的“一多开发”(一次开发,多端部署)不仅关注单设备内的多形态适配(如手机、平板、2in1),更核心的是支撑跨设备协同体验,包括:

  • 分布式能力
  • 应用接续(Continuity)
  • 碰一碰(NFC/蓝牙快速发现与连接)
  • 鼠标/键盘联动(外设协同)

一、分布式能力:鸿蒙一多的底层基石

划重点,下表一定要逐字看完,欲练神功,必先死记。

技术作用开发接口
分布式软总线(SoftBus)设备自动发现、安全连接、低延时通信@ohos.distributedHardware
deviceManager
分布式数据管理(DistributedDataManager)多设备间数据同步(如剪贴板、配置)@ohos.data.relationalStore
createDistributedTable()
分布式任务调度(DTSEngine)跨设备拉起服务、迁移任务@ohos.ability.featureAbility
startAbility()+want中指定设备

使用场景:

分布式让2IN1设备(2IN1是华为对各种PC设备的统称)能够和手机、平板、手表手环、智慧屏、车机、耳机等一切具有harmony OS 设备进行数据同步。

无论如何,都要让APP具备一些分布式能力,即便APP在之前没有考虑分布式,没关系,升级到分布式没有想象中那么困难。

分布式的三要素:权限、设备、分布式数据

要实现分布式就三步走:

1.获取权限,通过结构主动向用户索要“发现设备”的权限。

2.获取设备表。

3.对每一台设备进行分布式数据的拉取和推送。

权限代码片段:

/** * 1.判断是否已授权,未授权则拉起授权 * @param context * @returns */ async checkPermissions(context:common.UIAbilityContext): Promise<void> { try { let grantStatus1: boolean = await this.checkPermissionGrant('ohos.permission.DISTRIBUTED_DATASYNC') === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED;// 获取同步权限状态。 if (!grantStatus1) { // 申请权限。 this.reqPermissionsFromUser(['ohos.permission.DISTRIBUTED_DATASYNC'], context); } else { // 已经授权,可以继续访问目标操作。 emitter.emit('distributedSuccessFulEvt'); } } catch (e) { // 获取权限失败 emitter.emit('distributedErrorEvt'); throw e as SubError; } } /** * 1.1权限判断 * @param permission * @returns */ private async checkPermissionGrant(permission: Permissions): Promise<abilityAccessCtrl.GrantStatus> { let atManager: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager(); let grantStatus: abilityAccessCtrl.GrantStatus = abilityAccessCtrl.GrantStatus.PERMISSION_DENIED; // 获取应用程序的accessTokenID。 let tokenId: number = 0; try { let bundleInfo: bundleManager.BundleInfo = await bundleManager.getBundleInfoForSelf(bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_APPLICATION); let appInfo: bundleManager.ApplicationInfo = bundleInfo.appInfo; tokenId = appInfo.accessTokenId; } catch (error) { const err: BusinessError = error as BusinessError; console.error(`Failed to get bundle info for self, code: ${err.code}, message: ${err.message}`); } // 校验应用是否被授予权限。 try { grantStatus = await atManager.checkAccessToken(tokenId, permission); } catch (error) { const err: BusinessError = error as BusinessError; console.error(`Failed to check access token, code: ${err.code}, message: ${err.message}`); } return grantStatus; } /** * 1.2拉起授权窗口 * @param permissions * @param context */ private reqPermissionsFromUser(permissions: Array<Permissions>, context: common.UIAbilityContext): void { let atManager: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager(); // requestPermissionsFromUser会判断权限的授权状态来决定是否唤起弹窗。 atManager.requestPermissionsFromUser(context, permissions).then((data) => { let grantStatus: Array<number> = data.authResults; let length: number = grantStatus.length; for (let i = 0; i < length; i++) { if (grantStatus[i] === 0) { // 用户授权,等待其他权限。 } else { // 用户拒绝授权,提示用户必须授权才能访问当前页面的功能,并引导用户到系统设置中打开相应的权限。 let atManager: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager(); atManager.requestPermissionOnSetting(context, ['ohos.permission.DISTRIBUTED_DATASYNC']).then((data: Array<abilityAccessCtrl.GrantStatus>) => { if(data[0] === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED){ console.info(`2次同步授权完成, result: ${data}`); AppStorage.setOrCreate(IS_DATA_SYNC,true); emitter.emit('distributedSuccessFulEvt'); } else { emitter.emit('distributedErrorEvt'); emitter.emit('distributedReject'); //拒绝了权限申请。 console.info(`2次同步授权被拒绝, result: ${data}`); } }).catch((err: BusinessError) => { emitter.emit('distributedErrorEvt'); throw new SubError({code:err.code,message:err.message}); console.error(`requestPermissionOnSetting fail, code: ${err.code}, message: ${err.message}`); }); return; } } // 授权成功。 console.info(`同步授权完成, result: ${data}`); emitter.emit('distributedSuccessFulEvt'); }).catch((err: BusinessError) => { emitter.emit('distributedErrorEvt'); console.error(`Failed to request permissions from user. Code is ${err.code}, message is ${err.message}`); }) }

获取了权限后,先把数据库设置为分布式。

const tables: string[] = [ 'table1', //表1 'table2', //表2 ]; try { //设置表们为分布式。 await store.setDistributedTables(tables); } catch (error) { console.error(`Set distributed tables failed: ${error.code}, ${error.message}`); }

查找设备的代码片段:

searchDevices(): distributedDeviceManager.DeviceBasicInfo[] { // 查询组网内的设备列表 const deviceManager = distributedDeviceManager.createDeviceManager('com.waitpanda.xiexiaoshuo'); try { const deviceList = deviceManager.getAvailableDeviceListSync(); if (!deviceList) { throw new SubError({ code: 998404, message: '没有设备' }); } return deviceList; //设备列表。 } catch (error) { const e = error as SubError; console.error('d2d sync with all devices',e.code,e.message) throw error as SubError; //这个SubError是我自定义的一个错误类,可以直接使用Error } }

推送本地数据到其他设备。这个操作一定是你使用insert、update、delete等数据库写操作后进行。

// 构造用于同步分布式表的谓词对象 const predicates = new relationalStore.RdbPredicates(DB_CONSTANTS.TABLE1); predicates.inDevices(deviceList); try { const result = await store.sync(relationalStore.SyncMode.SYNC_MODE_PUSH, predicates); // 获取同步结果 for (let i = 0; i < result.length; i++) { const deviceId = result[i][0]; const syncResult = result[i][1]; if (syncResult === 0) { console.info('rdbDataSync', `device:${deviceId} table:${table} sync success`); } else { // 有些设备没有你的APP,它会报错。 console.error('rdbDataSync', `device:${deviceId} table:${table} sync failed, status:${syncResult}`); } } } catch (e){ console.error('pushToAllDevice同步失败'); }

关于分布式数据库(键值对、关系型、用户首选项)的不同:键值对分布式可以各设备之间相互读写,关系型则只能读其他设备,不能写。这个特性一定搞明白。

二、应用接续(Continuity):任务无缝流转

场景示例

  • 手机上写邮件 → 点击“接续到2IN1” → 2IN1继续编辑
  • 车机导航 → 到家后自动接续到手表步行导航

注意的是,这里要用到一个叫“分布式数据对象”的东西,它和分布式数据库中读出来的内容不是同一个东西,它是个独立的东西。

这个叫分布式数据对象的,主要作用是,将现在内存中进行了一半的内容记下来,另一台设备从这个分布式数据对象中把内容读出,继续进行操作。

除了分布式数据对象,还有个重要的东西叫SessionId,本端将生成的sessionId通过want传递到远端,供远端激活同步使用。

三、碰一碰(Tap to Share / Tap to Connect)

技术原理

  • 基于NFC + 蓝牙/WiFi P2P快速建立连接;
  • 触发系统级原子化服务(Atomic Service)FA 拉起

优势:无需用户打开 App,符合鸿蒙“服务找人”理念。

实战理解

将分享、截图、应用接续打包成碰一碰,主打让用户在人前装*,人后实用。这个功能很能提升用户使用率,有条件一定上一个。

四、鼠标联动(外设协同)

适用场景

  • 电脑连接蓝牙鼠标 → 应用需显示 hover 效果、右键菜单;
  • PC 模式下支持快捷键(Ctrl+C/V);
  • 多屏联动(鼠标能在手机、平板、电脑三者的屏幕上无缝移动)。

实战理解

只需要把图片、文本、列表等设置成能拖入拖出的方式复制、拷贝,就能让你的APP具备鼠标联动功能。这是全家桶用户高频使用的功能,性价比极高的功能。

五、整体架构建议:如何在一多工程中集成这些能力?

1Project/ 2├── common/ # 公共逻辑(含分布式工具类) 3│ └── DistributedHelper.ts 4├── features/ 5│ ├── continuity/ # 应用接续模块 6│ ├── nfc-share/ # 碰一碰分享 7│ └── input-enhance/ # 鼠标/键盘增强 8├── products/ 9│ ├── phone/ # 手机端:简化接续入口 10│ ├── tablet/ # 平板端:常驻侧边栏 + 分栏 + 鼠标支持 11│ └── pc/ # PC端:快捷键 + 右键菜单 12└── module.json5 # 声明分布式权限、NFC、外设能力

六、总结:鸿蒙一多 × 分布式 = 全场景体验

表格

特色能力技术方案一多开发要点
分布式软总线 + 分布式数据/任务一套逻辑,多设备协同执行
应用接续ContinuationRegisterManager状态序列化 + 目标设备UI适配
碰一碰NFC + 原子化服务/卡片无感触发,服务直达
鼠标联动PointerEvent + 快捷键大屏设备增强交互,小屏忽略

🔥核心思想
“一多”不仅是适配不同屏幕,更是构建“以人为中心的超级终端”
你的应用不再属于某一台设备,而是运行在用户所有的鸿蒙设备组成的“分布式网络”中。

这正是鸿蒙生态对开发者的最大红利。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/14 15:54:17

Sambert显存优化实战:8GB GPU流畅运行大模型技巧

Sambert显存优化实战&#xff1a;8GB GPU流畅运行大模型技巧 1. 开箱即用的多情感中文语音合成体验 你有没有试过在一台只有8GB显存的GPU设备上&#xff0c;跑起一个能说多种情绪、声音自然得像真人的中文语音合成模型&#xff1f;不是“能跑就行”&#xff0c;而是真正流畅、…

作者头像 李华
网站建设 2026/5/21 18:50:01

从零开始学I2C时序:操作指南与信号分析

以下是对您提供的博文《从零开始学IC时序&#xff1a;操作指南与信号分析——嵌入式总线通信的工程化解析》进行 深度润色与结构重构后的终稿 。本次优化严格遵循您的全部要求&#xff1a; ✅ 彻底去除AI痕迹&#xff0c;语言自然、专业、有“人味”——像一位在一线调过上百…

作者头像 李华
网站建设 2026/5/1 8:05:06

智能小车中L298N散热问题解决方案深度剖析

以下是对您提供的博文《智能小车中L298N散热问题解决方案深度剖析》的 全面润色与专业重构版本 。本次优化严格遵循您的全部要求: ✅ 彻底去除AI痕迹,语言自然、老练、有工程师口吻 ✅ 摒弃模板化标题(如“引言”“总结”),全文以逻辑流驱动,层层递进 ✅ 所有技术点…

作者头像 李华
网站建设 2026/5/27 14:10:30

麦橘超然部署成本大降:免订阅式AI绘图解决方案

麦橘超然部署成本大降&#xff1a;免订阅式AI绘图解决方案 你是不是也遇到过这些问题&#xff1a;想用最新AI绘图模型&#xff0c;却卡在显卡显存不够、部署流程复杂、服务器费用太高&#xff1f;或者试用几个在线平台后发现——不是要充会员&#xff0c;就是生成张图就扣好几…

作者头像 李华
网站建设 2026/5/22 5:48:32

Qwen3-Embedding-4B模型升级:从v2迁移至v3详细步骤

Qwen3-Embedding-4B模型升级&#xff1a;从v2迁移至v3详细步骤 1. Qwen3-Embedding-4B是什么&#xff1a;不只是“更大”&#xff0c;而是更懂语义 Qwen3-Embedding-4B不是简单地把老版本参数翻倍的“加量不加价”产品&#xff0c;它是Qwen家族在向量化技术上的一次系统性跃迁…

作者头像 李华
网站建设 2026/5/27 14:57:33

FSMN-VAD断点续传?大文件处理稳定性优化方案

FSMN-VAD断点续传&#xff1f;大文件处理稳定性优化方案 1. 为什么大文件语音检测总卡住、崩溃或漏检&#xff1f; 你有没有遇到过这样的情况&#xff1a;上传一个30分钟的会议录音&#xff0c;点击“开始端点检测”后&#xff0c;界面卡在转圈&#xff0c;等了两分钟突然弹出…

作者头像 李华