大家好,我是[晚风依旧似温柔],新人一枚,欢迎大家关注~

前言

先抛个灵魂拷问:
  都 2025 年了,你的 App 还只跑在一台设备上,不觉得有点“保守”吗?

想象一下这些场景:

  • 手机上点开视频 → 自动推到电视大屏播放,手机变身遥控器和弹幕输入端
  • 平板写文档 → 手机突然响了个消息 → 手机打开就是“同一个文档、同一处光标位置”
  • 手表采集运动数据 → 实时同步到手机 → 手机上画曲线、出报告
  • 车机播歌 → 手机调音量、切歌 → 回家后电视继续播刚才那首

这些事儿拼接口、靠一堆“蓝牙 + Wi-Fi + 本地同步 + 轮询”也不是不能做,就是——又土又累又不稳

鸿蒙的 分布式能力(Super Device) 干的事情,简单粗暴一句话:

让多台设备像“一个超级设备”一样工作,
让开发者用“写单机”的心智,做“多端协同”的体验。

这章我们就按你给的那条大纲,一步步把几个关键点掰开讲:

  • 分布式软总线到底是什么鬼?
  • 设备是怎么自动发现、自动连到一起的?
  • 分布式数据对象怎么用一份对象搞定多端同步?
  • UI 跨端协同到底是怎么设计出来的,不是喊喊口号?
  • 跨屏输入、跨端播放这种骚操作如何落地?
  • 安全和权限这一块,哪里最容易踩坑?

别担心,全程有代码、有图景、有吐槽,不整那种 PPT 式废话。


一、分布式软总线:所有跨设备能力的“血管”

先说重点:不理解分布式软总线,后面所有分布式 API 都会是玄学。

1.1 为什么要软总线?

传统做法:

  • 手机想跟电视说话:你要么配对蓝牙,要么搞个局域网 IP,再来一层自定义协议
  • 再加上车机、手表、平板……每多一台设备,你就多一个“对接方案”

久而久之,你的项目结构就会变成:

“一堆 if (deviceType == xxx) 的 spaghetti code(意大利面代码)”,
维护起来跟拆炸弹差不多。

鸿蒙干脆直接整了个分布式软总线(SoftBus),给它的定位大概是:

在系统层统一管理设备发现、连接、通道、加密、传输,
你在上层只管写“我要发一个对象给某台设备”。

换张嘴说:

  • 你不用管设备是通过 Wi-Fi 连接还是蓝牙直连
  • 你不用记对面 IP、端口
  • 你不用自己做“可靠传输 + 重连”
  • 你甚至可以不用自己造消息通道

系统帮你抽象出一个“分布式网络空间”,你只需要:

  1. 拿到设备列表
  2. 决定要和谁协同
  3. 扔数据 / 调用分布式 API

就这。


1.2 SoftBus 在代码里长什么样?

通常我们是通过“设备管理”这条线来获知 SoftBus 已经搭好,然后再玩后面的分布式对象、协同能力。

一个典型入口是 Distributed Device Manager。示例(伪代码,接口名不同版本会有轻微出入,但套路是一样的):

import deviceManager from '@ohos.distributedDeviceManager';

let dm: deviceManager.DeviceManager | null = null;

deviceManager.createDeviceManager('com.example.superdevice', (err, manager) => {
  if (err) {
    console.error('创建 DeviceManager 失败:', JSON.stringify(err));
    return;
  }
  dm = manager;
  console.info('DeviceManager 创建成功');
});

拿到 dm 之后,你就等于站在了整个分布式网络的门口,后面所有“发现设备、连接设备、建立协同”的动作,基本都从这里起步。

后面我们会基于这个继续往下走。


二、设备发现与连接:设备怎么“自动认识彼此”?

你看,SoftBus 在内核层面帮你统一了通道,那上层第一步就得解决:设备怎么互相找到、互相信任?

鸿蒙这块做得比较“人性化”:

  • 设备发现:自动发现局域网 / 同账号 / 同可信域下的设备
  • 认证连接:用户确认 + 证书交换
  • 状态监听:在线 / 离线 / 变化回调

2.1 启动设备发现

const SUBSCRIBE_ID = 1001;

function startDiscover() {
  if (!dm) return;

  dm.startDeviceDiscovery({
    subscribeId: SUBSCRIBE_ID,
    mode: 0,            // 主动发现
    medium: 0,          // 由系统自动决定用 Wi-Fi/BT 等
    freq: 1,            // 发现频率
    isSameAccount: true,
    isWakeRemote: true
  }, (err) => {
    if (err) {
      console.error('启动设备发现失败:', JSON.stringify(err));
    } else {
      console.info('设备发现已启动');
    }
  });

  dm.on('deviceFound', (device) => {
    console.info('发现设备:', JSON.stringify(device));
    // 这里可以弹个 UI,让用户选择要连哪一台
  });

  dm.on('discoverFail', (info) => {
    console.error('设备发现失败事件:', JSON.stringify(info));
  });
}

你不需要管理什么搜索广播包、不同链路,只要启动发现,然后等回调,就像等外卖一样。

2.2 设备认证与连接

一旦用户选中一台设备,你通常要走一遍认证流程:

function authDevice(deviceId: string) {
  if (!dm) return;

  const authParam = {
    authType: 1,  // 比如 PIN 验证 / 对码等,由系统 UI 帮你做
    appIcon: 'xxx', 
    appName: 'Super Device Demo'
  };

  dm.authenticateDevice(deviceId, authParam, (err, result) => {
    if (err) {
      console.error('认证失败:', JSON.stringify(err));
      return;
    }
    console.info('认证成功,token = ' + result.token);
    // 后续可以存一份可信设备列表
  });

  dm.on('deviceOnline', (dev) => {
    console.info('设备上线:', JSON.stringify(dev));
  });

  dm.on('deviceOffline', (dev) => {
    console.info('设备下线:', JSON.stringify(dev));
  });
}

一旦认证成功,同一账户、同一可信网域内,多数情况下你后续都不用再重复认证,直接用设备 ID 搞协同就行。


三、分布式数据对象:多设备共享“一块内存”的感觉

如果你让我选 HarmonyOS 分布式能力里最有“黑科技感”的一块,我肯定投 Distributed Data Object(分布式数据对象) 一票。

它大概的体验是:

你在手机上 obj.count++
平板、电视、手表上监听这个对象的页面就会一起刷新。

没有显式“发消息”、“写 socket”、“做同步”,你只是在改一个对象。

3.1 创建一个分布式数据对象

import distributedDataObject from '@ohos.data.distributedDataObject';

// 定义一个跨设备共享的状态
const docState = distributedDataObject.create({
  title: '未命名文档',
  content: '',
  cursor: 0,
  lastEditDevice: '',
});

// 监听变化(每个设备都可以监听)
docState.on('change', (changedFields) => {
  console.info('分布式对象变化:', JSON.stringify(changedFields));
  // 比如刷新 UI、更新光标位置
});

这时候,只要你的设备已经处在同一个分布式网络中并且启用了分布式同步,这个 docState 就像放在“分布式内存”里一样。

3.2 修改数据 = 自动同步

在手机端:

function onUserInput(text: string) {
  docState.content = text;
  docState.lastEditDevice = 'phone';
}

在平板端:

docState.on('change', () => {
  editor.setText(docState.content);
  console.info('来自:' + docState.lastEditDevice);
});

你完全没有看到什么网络请求、序列化、信道选择;
你唯一看到的是:

  • 改对象
  • 自动同步
  • 监听变化

这套东西用在:

  • 多端文档编辑
  • 多设备播放控制状态(当前播放进度 / 播放状态)
  • 家庭 IoT 场景下的“当前场景状态”
  • 多端白板协同

都非常舒服。


四、跨端 UI 协同设计:不是简单“投屏”,而是“迁移”和“协作”

很多人一听“跨端 UI”,第一反应是 —— 投个屏不就完了?
说实话,这种理解太屈才了。

鸿蒙的思路是:

UI 不是死在一台设备上的,而是可以在设备之间
迁移 / 拆分 / 协同

4.1 能力 1:界面迁移(Continuation)

最典型的例子:视频从手机迁移到电视

在手机侧的 UIAbility:

// 允许迁移时携带状态
onContinue(wantParams: Record<string, Object>): boolean {
  wantParams['videoUrl'] = this.currentVideoUrl;
  wantParams['position'] = this.currentPosition;
  wantParams['fromDevice'] = 'phone';
  return true; // 同意迁移
}

在电视侧接住:

onCreate(want: any) {
  const params = want.parameters ?? {};
  const url = params['videoUrl'];
  const pos = params['position'] ?? 0;

  if (url) {
    this.player.setSource(url);
    this.player.seek(pos);
    this.player.play();
  }
}

这一来一回,两边 UI 跑的是同一套业务逻辑,只是界面的承载设备变了:

  • 手机变成控制端
  • 电视变成主播放端

而不是简单把“画面投出去”那么粗糙。


4.2 能力 2:多屏协作设计思路

这种能力玩起来就很有意思了,比如:

  • 平板 显示文档主区域
  • 手机 只显示工具栏和评论列表
  • 手写板 只负责手写/涂鸦

设计思路一般是:

  1. 分布式数据对象 管“业务状态”
  2. 多 Ability 按设备类型渲染不同 UI
  3. 设备信息(屏幕尺寸、输入能力) 决定显示布局

伪代码示意:

import deviceManager from '@ohos.distributedDeviceManager';

function getDeviceRole(deviceInfo): 'main' | 'tool' | 'input' {
  if (deviceInfo.deviceType === 'tablet') return 'main';
  if (deviceInfo.deviceType === 'phone') return 'tool';
  if (deviceInfo.deviceType === 'stylusBoard') return 'input';
  return 'tool';
}

然后在不同端,根据 role 决定渲染哪些组件。
统一的业务状态 + 不同的 UI 布局,这才是真正的“跨端协同”。


五、跨设备调用示例:跨屏输入、跨端播放怎么搞?

光讲理念太虚,我们来点“有手就能 copy 的例子”。


5.1 跨屏输入:手机当电视的输入法

场景:

  • 电视上有一个搜索框
  • 遥控器打字太折磨人
  • 手机同账号登录以后,直接变成电视的“键盘”
5.1.1 电视侧:暴露一个“远程输入”接口

你可以用分布式 RPC / 自定义服务 / 分布式数据对象承载,下面用一个超简化思路:

// 假设我们用分布式对象承载输入内容
const searchInput = distributedDataObject.create({
  text: '',
  fromDevice: '',
});

searchInput.on('change', () => {
  if (searchInput.fromDevice === 'phone') {
    tvSearchBox.setText(searchInput.text);
  }
});
5.1.2 手机侧:同步用户输入
function onPhoneInputChange(text: string) {
  searchInput.text = text;
  searchInput.fromDevice = 'phone';
}

如果你想做得更“底层”一点,也可以用分布式输入设备能力(不同版本 SDK 的命名略有区别),核心逻辑是:

  • 电视注册一个“接收按键/文本事件”的监听
  • 手机作为发送端,发“按键事件 / 文本事件”

5.2 跨端播放:手机控制电视播放

常见玩法:

  • 手机选择一个视频 → 选择目标设备 → 让对方播放
  • 手机动态控制“播放 / 暂停 / 进度 / 音量”
5.2.1 电视侧:注册一个“媒体控制服务”

伪代码示意:

import serviceExtension from '@ohos.app.ability.ServiceExtensionAbility';
import rpc from '@ohos.rpc';

class TvPlayerRemote extends rpc.RemoteObject {
  player: any;

  constructor(descriptor: string) {
    super(descriptor);
    this.player = createTvMediaPlayer();
  }

  onRemoteRequest(code: number, data: rpc.MessageParcel, reply: rpc.MessageParcel) {
    switch (code) {
      case 1: // play
        const url = data.readString();
        this.player.setSource(url);
        this.player.play();
        return true;
      case 2: // pause
        this.player.pause();
        return true;
      case 3: // seek
        const pos = data.readInt();
        this.player.seek(pos);
        return true;
      default:
        return false;
    }
  }
}

export default class TvPlayerService extends serviceExtension {
  remote: TvPlayerRemote | null = null;

  onCreate() {
    this.remote = new TvPlayerRemote('TvPlayerRemote');
  }

  onConnect() {
    return this.remote;
  }
}
5.2.2 手机侧:作为控制端
class TvPlayerProxy {
  constructor(private remote: rpc.IRemoteObject) {}

  play(url: string) {
    let data = rpc.MessageParcel.create();
    let reply = rpc.MessageParcel.create();
    let opt = new rpc.MessageOption();
    data.writeString(url);
    return this.remote.sendRequest(1, data, reply, opt);
  }

  pause() {
    let data = rpc.MessageParcel.create();
    let reply = rpc.MessageParcel.create();
    let opt = new rpc.MessageOption();
    return this.remote.sendRequest(2, data, reply, opt);
  }

  seek(pos: number) {
    let data = rpc.MessageParcel.create();
    let reply = rpc.MessageParcel.create();
    let opt = new rpc.MessageOption();
    data.writeInt(pos);
    return this.remote.sendRequest(3, data, reply, opt);
  }
}

配合上“设备发现 + 用户选择目标设备 + 权限认证”,就可以做一个完整的“投屏 + 遥控”体验了。


六、安全与权限问题:跨设备不是“裸连”,安全得先想明白

凡是跟“跨设备”“分布式”的东西,安全一定是重中之重。
你总不能随便搞个 App 就能控制别人家的电视、车机、摄像头吧?

6.1 设备层面的安全:可信设备 + 用户确认

鸿蒙分布式设备的安全通常包含几层:

  1. 同一华为账号 / 同一家庭组 / 同一可信域
  2. 首次连接需要用户确认(PIN、扫码、弹窗)
  3. 系统维护设备证书与信任关系
  4. 后续使用走的是加密通道

也就是说,就算你知道对面设备的 ID,只要不是可信设备,系统也不会让你随意拉通分布式能力。


6.2 应用层面的权限声明

你要玩分布式,就离不开权限,例如:

{
  "module": {
    "abilities": [ /* ... */ ],
    "requestPermissions": [
      "ohos.permission.DISTRIBUTED_DATASYNC",          // 分布式数据同步
      "ohos.permission.DISTRIBUTED_DEVICE_STATE_CHANGE", // 监听设备状态
      "ohos.permission.GET_NETWORK_INFO",
      "ohos.permission.INTERNET"
    ]
  }
}

你没声明,跑的时候就会被系统毫不留情地拦下来。

对于跨设备调用某些“敏感能力”(比如摄像头、麦克风、定位),还会涉及到目标设备上的二次授权,这一点在设计 UX 时必须考虑进去:

  • 不要“连着连着”突然把对方摄像头打开
  • 不要悄悄从别的设备录音、采集位置

6.3 通信层安全:

软总线在通信层帮你做了一堆事情:

  • 加密传输
  • 会话校验
  • 消息完整性

你不需要自己再实现一套复杂的 SSL / TLS,
但你要对“哪些数据可以跨设备传”有最低限度的自觉:

  • 不要传明文密码
  • 不要在不合规的前提下同步隐私数据
  • 尽量对敏感信息做脱敏

在企业项目里,很多安全审计就是卡在这里:
技术做得很酷,合规上完全不合格。


写在最后:分布式不是“加个卖点”,是真正改变架构思维

总结一下今天这趟旅程:

  • 分布式软总线:统一传输底座,让你不用再操心蓝牙/Wi-Fi/局域网底层细节
  • 设备发现与连接:自动发现 + 用户确认 + 可信域管理,避免设备乱连
  • 分布式数据对象:像操作本地对象一样搞多端数据同步
  • 跨端 UI 协同:界面可迁移、可拆分、可协作,不是简单投屏
  • 跨设备调用(输入/播放等):服务 + RPC + 分布式,让设备之间互相“打工”
  • 安全与权限:没有安全和权限控制,一切分布式都是“高危操作”

更现实一点说:

未来几年,“会不会做分布式协同”,
多半会成为区分普通 App 和“新一代表达力 App”的分水岭。

如果你已经在做鸿蒙原生项目,真心建议:
别把分布式能力当成“锦上添花”,它是你架构升级的大杀器。

如果觉得有帮助,别忘了点个赞+关注支持一下~
喜欢记得关注,别让好内容被埋没~

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐