标签 设备发现 下的文章

在这里插入图片描述

摘要

随着智能终端越来越多,应用早就不再只运行在一台设备上。手机、平板、智慧屏、手表之间的协作,已经成了很常见的需求。在这种背景下,多设备任务该怎么分、分到哪台设备执行,就成了开发中绕不开的问题。

在鸿蒙系统中,这个问题并不是靠开发者“手动指定设备”来解决的,而是通过 设备能力感知 + 分布式调度机制 来完成。开发者更多关心的是:
这个任务适合干什么,而不是非要在哪台设备干。

本文会结合鸿蒙系统的分布式能力,介绍多设备任务分配的整体思路,并通过可运行的 Demo 代码,把这个过程完整跑一遍,最后再结合几个真实场景,聊聊它在实际项目中该怎么用。

引言

如果放在以前,一个应用基本只跑在一台手机上,最多考虑前后台切换。但现在不一样了:

  • 手机在你手里
  • 平板在桌子上
  • 智慧屏在客厅
  • 手表戴在手上

用户希望的是:
设备不同,但体验是连着的。

鸿蒙系统的分布式能力,正是为这种场景设计的。它不是简单的“跨设备通信”,而是把 任务、数据、能力 都变成可以在多设备之间流动的资源。

而多设备任务分配,本质上就是一句话:

把合适的任务,交给合适的设备去做。

鸿蒙多设备任务分配的整体思路

先发现设备,再谈分配

在鸿蒙系统中,只要设备在同一个分布式网络里,系统就能自动发现它们。
开发者不需要自己维护“设备表”,也不用关心设备什么时候上线、下线。

系统会帮你感知这些信息:

  • 设备类型(手机、平板、智慧屏)
  • 基本性能情况
  • 是否可信
  • 当前是否可用

你只需要在合适的时机拿到设备列表即可。

任务一定要能拆

多设备任务分配的前提是:
你的业务本身是能拆开的。

比如:

  • 页面展示是一块
  • 数据采集是一块
  • 计算处理是一块

如果一个任务从头到尾全写死在一个 Ability 里,那基本就没法分配了。

系统负责“怎么选设备”

在鸿蒙里,真正“选哪台设备执行”的逻辑,大部分是系统完成的:

  • 当前设备忙不忙
  • 网络情况好不好
  • 设备能力是否匹配
  • 是否更适合本地执行

开发者更多是通过 Ability 启动方式、Service 类型、数据同步方式 来间接影响分配结果。

核心实现方式一:跨设备启动 Ability

适合什么场景

这种方式最常见,适合:

  • 页面展示
  • 功能模块整体迁移
  • 用户可感知的交互任务

比如:
手机负责控制,平板负责显示大屏内容。

Demo:在平板上启动远程 Ability

import distributedDeviceManager from '@ohos.distributedDeviceManager';
import featureAbility from '@ohos.ability.featureAbility';

const BUNDLE_NAME = 'com.example.distributeddemo';

let deviceManager = distributedDeviceManager.createDeviceManager(BUNDLE_NAME);

function startRemotePage() {
  let devices = deviceManager.getTrustedDeviceListSync();

  devices.forEach(device => {
    if (device.deviceType === 2) { // 假设 2 表示平板
      let want = {
        bundleName: BUNDLE_NAME,
        abilityName: 'RemotePageAbility',
        deviceId: device.deviceId
      };
      featureAbility.startAbility(want);
    }
  });
}

代码说明

  • createDeviceManager:创建设备管理器
  • getTrustedDeviceListSync:获取可信设备列表
  • deviceType:用于简单区分设备类型
  • startAbility:指定 deviceId 后,Ability 会在远端设备启动

整个过程不需要你关心远端设备的进程、生命周期,系统会处理。

核心实现方式二:分布式 Service 执行任务

适合什么场景

这种方式更适合:

  • 计算密集型任务
  • 后台处理
  • 不需要 UI 的逻辑

比如:
手机采集数据,交给性能更强的设备做分析。

Demo:连接远端计算 Service

import featureAbility from '@ohos.ability.featureAbility';

function connectRemoteService(remoteDeviceId: string) {
  let want = {
    bundleName: 'com.example.distributeddemo',
    abilityName: 'ComputeServiceAbility',
    deviceId: remoteDeviceId
  };

  featureAbility.connectAbility(want, {
    onConnect(elementName, remote) {
      console.log('远程 Service 已连接');
      remote.sendMessage({
        command: 'startCompute',
        data: [1, 2, 3, 4]
      });
    },
    onDisconnect() {
      console.log('远程 Service 已断开');
    }
  });
}

代码说明

  • Service 在远端设备运行
  • 本地通过 IPC 的方式和远端通信
  • 计算逻辑完全在远端执行
  • 本地只负责发请求、收结果

这种方式非常适合“重计算、轻交互”的任务。

典型应用场景分析与示例

场景一:手机 + 平板的学习展示系统

场景说明

  • 手机负责控制、翻页
  • 平板负责展示课件内容

实现思路

  • 手机发现平板
  • 在平板启动展示 Ability
  • 通过分布式数据同步当前页码
import distributedData from '@ohos.data.distributedData';

async function syncPage(page: number) {
  let kvManager = distributedData.createKVManager();
  let store = await kvManager.getKVStore('pageStore');
  await store.put('current_page', page);
}

平板端监听数据变化,自动刷新页面。

场景二:多设备健康数据分析

场景说明

  • 手表采集心率
  • 手机做基础处理
  • 平板做数据可视化

实现思路

  • 手表同步原始数据
  • 手机过滤、预处理
  • 平板负责展示图表

核心在于:
任务不是“复制”,而是“分工”。

场景三:家庭智慧屏协同控制

场景说明

  • 手机是遥控器
  • 智慧屏负责 UI 展示
  • 计算逻辑放在智慧屏

实现思路

  • 手机只负责发指令
  • 智慧屏 Service 处理业务逻辑
  • 结果同步回手机

这种模式下,手机压力很小,体验反而更流畅。

常见问题 QA

Q1:我能不能指定“一定要某台设备执行”?

不推荐。
鸿蒙的设计思想是 声明需求,而不是指定设备
你可以通过能力需求去“引导”,但不建议写死。

Q2:设备突然下线怎么办?

系统会通知连接断开,
你需要做的只有一件事:
支持本地降级执行或重试。

Q3:分布式任务一定比本地慢吗?

不一定。
当任务本身就不适合本地执行时,
分布式反而更快、更省电。

总结

在鸿蒙系统中,多设备任务分配并不是一套复杂、难以理解的机制,它的核心思想其实很简单:

  • 把任务拆清楚
  • 描述好任务需求
  • 把调度交给系统

只要你在设计阶段考虑好“哪些任务适合分出去”,鸿蒙的分布式能力就能自然地帮你把事情做好。

一句话总结就是:

多设备任务分配,不是设备协作有多复杂,而是你有没有把任务设计清楚。

在这里插入图片描述

摘要

随着智能终端越来越多,应用早就不再只运行在一台设备上。手机、平板、智慧屏、手表之间的协作,已经成了很常见的需求。在这种背景下,多设备任务该怎么分、分到哪台设备执行,就成了开发中绕不开的问题。

在鸿蒙系统中,这个问题并不是靠开发者“手动指定设备”来解决的,而是通过 设备能力感知 + 分布式调度机制 来完成。开发者更多关心的是:
这个任务适合干什么,而不是非要在哪台设备干。

本文会结合鸿蒙系统的分布式能力,介绍多设备任务分配的整体思路,并通过可运行的 Demo 代码,把这个过程完整跑一遍,最后再结合几个真实场景,聊聊它在实际项目中该怎么用。

引言

如果放在以前,一个应用基本只跑在一台手机上,最多考虑前后台切换。但现在不一样了:

  • 手机在你手里
  • 平板在桌子上
  • 智慧屏在客厅
  • 手表戴在手上

用户希望的是:
设备不同,但体验是连着的。

鸿蒙系统的分布式能力,正是为这种场景设计的。它不是简单的“跨设备通信”,而是把 任务、数据、能力 都变成可以在多设备之间流动的资源。

而多设备任务分配,本质上就是一句话:

把合适的任务,交给合适的设备去做。

鸿蒙多设备任务分配的整体思路

先发现设备,再谈分配

在鸿蒙系统中,只要设备在同一个分布式网络里,系统就能自动发现它们。
开发者不需要自己维护“设备表”,也不用关心设备什么时候上线、下线。

系统会帮你感知这些信息:

  • 设备类型(手机、平板、智慧屏)
  • 基本性能情况
  • 是否可信
  • 当前是否可用

你只需要在合适的时机拿到设备列表即可。

任务一定要能拆

多设备任务分配的前提是:
你的业务本身是能拆开的。

比如:

  • 页面展示是一块
  • 数据采集是一块
  • 计算处理是一块

如果一个任务从头到尾全写死在一个 Ability 里,那基本就没法分配了。

系统负责“怎么选设备”

在鸿蒙里,真正“选哪台设备执行”的逻辑,大部分是系统完成的:

  • 当前设备忙不忙
  • 网络情况好不好
  • 设备能力是否匹配
  • 是否更适合本地执行

开发者更多是通过 Ability 启动方式、Service 类型、数据同步方式 来间接影响分配结果。

核心实现方式一:跨设备启动 Ability

适合什么场景

这种方式最常见,适合:

  • 页面展示
  • 功能模块整体迁移
  • 用户可感知的交互任务

比如:
手机负责控制,平板负责显示大屏内容。

Demo:在平板上启动远程 Ability

import distributedDeviceManager from '@ohos.distributedDeviceManager';
import featureAbility from '@ohos.ability.featureAbility';

const BUNDLE_NAME = 'com.example.distributeddemo';

let deviceManager = distributedDeviceManager.createDeviceManager(BUNDLE_NAME);

function startRemotePage() {
  let devices = deviceManager.getTrustedDeviceListSync();

  devices.forEach(device => {
    if (device.deviceType === 2) { // 假设 2 表示平板
      let want = {
        bundleName: BUNDLE_NAME,
        abilityName: 'RemotePageAbility',
        deviceId: device.deviceId
      };
      featureAbility.startAbility(want);
    }
  });
}

代码说明

  • createDeviceManager:创建设备管理器
  • getTrustedDeviceListSync:获取可信设备列表
  • deviceType:用于简单区分设备类型
  • startAbility:指定 deviceId 后,Ability 会在远端设备启动

整个过程不需要你关心远端设备的进程、生命周期,系统会处理。

核心实现方式二:分布式 Service 执行任务

适合什么场景

这种方式更适合:

  • 计算密集型任务
  • 后台处理
  • 不需要 UI 的逻辑

比如:
手机采集数据,交给性能更强的设备做分析。

Demo:连接远端计算 Service

import featureAbility from '@ohos.ability.featureAbility';

function connectRemoteService(remoteDeviceId: string) {
  let want = {
    bundleName: 'com.example.distributeddemo',
    abilityName: 'ComputeServiceAbility',
    deviceId: remoteDeviceId
  };

  featureAbility.connectAbility(want, {
    onConnect(elementName, remote) {
      console.log('远程 Service 已连接');
      remote.sendMessage({
        command: 'startCompute',
        data: [1, 2, 3, 4]
      });
    },
    onDisconnect() {
      console.log('远程 Service 已断开');
    }
  });
}

代码说明

  • Service 在远端设备运行
  • 本地通过 IPC 的方式和远端通信
  • 计算逻辑完全在远端执行
  • 本地只负责发请求、收结果

这种方式非常适合“重计算、轻交互”的任务。

典型应用场景分析与示例

场景一:手机 + 平板的学习展示系统

场景说明

  • 手机负责控制、翻页
  • 平板负责展示课件内容

实现思路

  • 手机发现平板
  • 在平板启动展示 Ability
  • 通过分布式数据同步当前页码
import distributedData from '@ohos.data.distributedData';

async function syncPage(page: number) {
  let kvManager = distributedData.createKVManager();
  let store = await kvManager.getKVStore('pageStore');
  await store.put('current_page', page);
}

平板端监听数据变化,自动刷新页面。

场景二:多设备健康数据分析

场景说明

  • 手表采集心率
  • 手机做基础处理
  • 平板做数据可视化

实现思路

  • 手表同步原始数据
  • 手机过滤、预处理
  • 平板负责展示图表

核心在于:
任务不是“复制”,而是“分工”。

场景三:家庭智慧屏协同控制

场景说明

  • 手机是遥控器
  • 智慧屏负责 UI 展示
  • 计算逻辑放在智慧屏

实现思路

  • 手机只负责发指令
  • 智慧屏 Service 处理业务逻辑
  • 结果同步回手机

这种模式下,手机压力很小,体验反而更流畅。

常见问题 QA

Q1:我能不能指定“一定要某台设备执行”?

不推荐。
鸿蒙的设计思想是 声明需求,而不是指定设备
你可以通过能力需求去“引导”,但不建议写死。

Q2:设备突然下线怎么办?

系统会通知连接断开,
你需要做的只有一件事:
支持本地降级执行或重试。

Q3:分布式任务一定比本地慢吗?

不一定。
当任务本身就不适合本地执行时,
分布式反而更快、更省电。

总结

在鸿蒙系统中,多设备任务分配并不是一套复杂、难以理解的机制,它的核心思想其实很简单:

  • 把任务拆清楚
  • 描述好任务需求
  • 把调度交给系统

只要你在设计阶段考虑好“哪些任务适合分出去”,鸿蒙的分布式能力就能自然地帮你把事情做好。

一句话总结就是:

多设备任务分配,不是设备协作有多复杂,而是你有没有把任务设计清楚。

为什么要做这个玩意儿

不知道大家有没有遇到过这种问题,用 LocalSend 时两台设备在现实中相距很近,也在同一个专用网络中,但因为接入的子网不同导致两台设备没法相互发现,不过可以手动添加 IP 来指定设备进行文件传输(比如咱实验室中的一台计算机连接的是有线网,但是我笔记本连接的是 WiFi,就没法互相发现,这台计算机和我的笔记本其实都在校园网中)。

  • 但是这两种接入方式分配的都是动态 IP 来着,可能过一段时间就变了。

LocalSend 协议 可以看到在发现设备时用的是 UDP 组播,而其他 REST API 用的是单播的 HTTP (S)。咱自己搜索了一下发现,校园网涉及到了 VLAN 和子网划分,不同 VLAN 对应了不同子网,组播被隔离在各个子网中,而单播则有三层设备的规则来跨子网进行传输,于是就有了上述的这种情况(无法组播发现设备,但是可以通过指定 IP 进行单播)。

用 Wireshark 抓包也能看到,组播包中 TTL=1,是无法被转发的。

正好最近学了 Go,就想熟悉一下这个语言,简单写个交换桥梁来解决这个问题,于是 LocalSend Switch 这个小工具就诞生了~

解决思路其实很简单,在每台有 LocalSend 的客户端上都启动 LocalSend Switch,捕获其发出的 UDP 组播包,取出其中的客户端信息通过单播进行转发 (转发途径的 Switch 节点可以是内网或者外网中有静态 IP 的节点),客户端信息最终会转发到其他的终端 Switch 节点手里,这些 Switch 节点会请求客户端信息中的地址和端口,通过 REST API 来代替 LocalSend 进行响应和注册。

组播捕获

客户端信息

客户端信息

客户端信息

注册 LocalSend D

LocalSend A

A

B

C

D

LocalSend D

比如上面这个例子就是 A, B, C, D 为四台主机上的 Switch 节点。其中 A 和 D 在允许单播的大局域网中,它们所在的主机有 LocalSend 客户端在运行;B 和 C 节点则纯担当转发角色,它们最好有静态 IP
A 捕获组播包后拆出其中的客户端信息进行转发,转发途径 B, C 节点最终到 D,D 于是向 LocalSend A 发出 LocalSend D 客户端的信息来进行注册。反之从 D 到 A 的过程也类似,是 A 向 LocalSend D 来发出注册请求,由此来实现互相发现。

简单来说 LocalSend Switch 充当的角色就有点类似于 BT 下载中的 Tracker 服务器了,但同时也会帮忙发送单播的注册请求,用于辅助 组播隔离、单播允许 的局域网子网之间的 LocalSend 客户端互相发现。

更多详细的实现和原理说明可以见 README: localsend-switch/README.zh_CN.md at main · SomeBottle/localsend-switch

项目地址

如果这个项目帮助到了大家,希望能给个 star ˋ(° ▽、°)

其他碎碎念

  1. 虽然传递的信息不算那么敏感,但每个 Switch 节点仍然支持配置一个对称加密密钥进行端侧 AES 加密,让传输的是密文。
  2. 为了尽量消除环路,每条客户端信息都带有 TTL 和唯一 ID。
  3. 支持开机启动,资源占用很低。

目前已经在咱实验室的计算机上实装了,现在传文件真的要轻松更多了 ╰( ̄ω ̄o)


📌 转载信息
原作者:
SomeBottle
转载时间:
2026/1/10 19:04:17