0
0
0

鸿蒙造物者之路 09 · 分身术

文章摘要
|

续写章节|沿用「造物者」系列的武侠讲解体,面向电子信息 / 嵌入式方向的新手

=================前情提要===============

数据、网络、通知、后台任务、权限——应用终于"能用"了。

老陈说下一章是鸿蒙的杀手锏,也是这本书最该记住的一章。

分布式。

“让你的应用,同时跑在手机、手表、平板和开发板上——而它们看起来像一个设备。”

========================================


这一章你会得到什么

🎯 学完这一章,你应该能:

  • ☐ 理解分布式软总线的四个阶段:发现 → 认证 → 组网 → 传输
  • ☐ 理解设备虚拟化:为什么手表能调用手机的摄像头
  • ☐ 会用 DeviceManager 发现并认证设备
  • ☐ 会跨设备启动 Ability 和做跨端迁移(应用流转)
  • ☐ 会用分布式 KVStore 让数据自动同步

**🧰 需要准备:**最好有两台鸿蒙设备(手机 + 平板,或者两台手机),同 Wi-Fi。没有也可以用模拟器或多开。

**⏱ 预计用时:**约 5 小时

📊 难度:★★★★★ 概念抽象,但这才是鸿蒙的命根子


一、先把我脑子里的"设备"敲碎

"在开始之前,"老陈说,“我要你先忘掉一件事。”

“忘掉什么?”

“忘掉’一个设备就是一台机器’这个观念。”

他把四台设备摆在桌上:手机、平板、手表、还有我那块 Hi3861。

“在鸿蒙的世界观里,这四样东西可以是一个设备。”

“……怎么可能,它们是四块独立的硬件。”

"硬件是独立的,但系统可以让它们’看起来’是一个。"老陈说,“这就是鸿蒙最核心的设计——”

他在白板上写下八个字:

     硬件互助,资源共享

“具体表现成什么样?我给你举四个例子。”

1.1 四个"反常识"的场景

【场景一:借摄像头】
你的手表要扫码,但摄像头只有 30 万像素。
→ 手表直接【调用手机的摄像头】,拍完传回来
→ 手表上的代码:camera.open()  —— 一行没改

【场景二:借屏幕】
你在手机上看到一半的视频,走到客厅。
→ 视频【流转到智慧屏】,手机变成遥控器
→ 视频进度不丢,因为状态也一起过去了

【场景三:借算力】
你的门锁需要跑一个人脸识别,但它只有 128KB 内存。
→ 门锁把图像传给手机,让【手机算】,只拿结果
→ 门锁依然只是个门锁,但有了 AI

【场景四:借传感器】
你的手机没有温湿度传感器。
→ 手机【直接读客厅那个开发板上的 SHT30】
→ 对手机上的 App 来说,这个传感器就像长在自己身上

我盯着最后一条。

“……第四种,我能做吗?”

"这就是你这周的目标。"老陈说。

二、分布式软总线:一切的底座

“实现上面四件事的技术,叫分布式软总线。”

2.1 它是什么

"先理解’总线’这个词。"老陈说,“你在第 05 章学过 I2C 总线——多个设备挂在同一组线上,靠地址互相通信。”

“嗯。”

“软总线就是把’总线’这个概念,从芯片内部搬到了设备之间。”

【硬件总线(I2C)】              【软总线(分布式)】
  同一块 PCB 上                    同一个局域网 / 蓝牙范围内
  物理的 SDA/SCL 两根线             虚拟的"总线"
  靠 7 位地址区分设备                靠 deviceId 区分设备
  传几个字节                        传任意数据、传能力、传硬件

“而且软总线是’软’的——它底下可能是 Wi-Fi、可能是蓝牙、可能是以太网,但它对上层是透明的。”

┌──────────────────────────────────────┐
│  应用 / 系统服务                        │
├──────────────────────────────────────┤
│  分布式软总线(统一 API)                │  ← 上层只看到"总线"
├──────────────────────────────────────┤
│  Wi-Fi P2P │ 蓝牙 BR/BLE │ 以太网     │  ← 底层自动选
└──────────────────────────────────────┘

"它会自动选最快的那条路。"老陈说,“两个设备都在同一个 Wi-Fi 下,走 Wi-Fi;只有蓝牙,走蓝牙;两者都有,自动挑。”

2.2 四个阶段

“软总线的工作,分四步。”

   ① 发现        ② 连接        ③ 组网        ④ 传输
   发现谁在      建立信任      组成一个       在网内传数据
      │             │          超级终端          │
      ▼             ▼             ▼             ▼
   设备发现      设备认证       逻辑组网       数据传输
   (谁在附近)  (你是谁)    (我们是一伙的)(说正事)

① 发现:谁在附近

“设备上线后,会广播自己的存在,同时监听别人的广播。”

“用什么协议?”

"基于 mDNS、CoAP 这类局域网发现协议,配合蓝牙扫描。"老陈说,“技术细节你不用管,你只需要知道——打开 Wi-Fi 和蓝牙,同一局域网内的设备就能互相发现。”

② 连接:你是谁(认证)

"这一步最关键,也最容易被忽略。"老陈的语气严肃了。

“**发现不等于信任。**你家的门锁不能因为’隔壁老王的设备也在附近’就把门开了。”

“所以要认证?”

"对。设备必须’配对’之后才能通信。"老陈列了几种方式:

认证方式 场景 安全性
同一帐号 同一个华为帐号下的手机、平板、耳机 高(云端已确认身份)
PIN 码 手动输入对方显示的 6 位数字 高
碰一碰(NFC) 手机碰一下设备 高(物理接触)
扫码 扫设备上的二维码 中高
附近设备(免认证) 同局域网、低敏感操作 低(受限使用)

“**认证通过之后,双方交换证书。**之后所有通信都是加密的。”

③ 组网:组成"超级终端"

“认证完之后,这些设备就组成了一个逻辑上的网络,鸿蒙管它叫’超级终端’。”

     ┌─────────────────────────────────┐
     │         超级终端                  │
     │                                  │
     │   手机 ────┬──── 平板             │
     │            │                     │
     │   手表 ────┼──── 智慧屏           │
     │            │                     │
     │  开发板 ───┴──── 音箱             │
     │                                  │
     └─────────────────────────────────┘
     每个设备都知道:
       · 伙伴有哪些
       · 每个伙伴有什么能力(摄像头?传感器?屏幕?)
       · 自己怎么调用它们

“**在系统设置里,你能看到一个’超级终端’的界面,可以把设备拖在一起组网。**那不是 UI 特效,那是真实的逻辑网络。”

④ 传输:说正事

“组网之后,就是传数据。软总线提供几类能力:”

能力 用途 类比
消息(Message) 小数据、即时 发微信
字节(Bytes) 中等数据 传文件
流(Stream) 音视频流 视频通话
文件(File) 大文件传输 传视频
RPC / 分布式对象 跨设备调用方法 就像调本地函数

"最后这个最神奇——跨设备 RPC。"老陈说,“你在手机上调一个方法,实际执行在平板上,但你写的代码跟调本地方法一模一样。”

三、设备虚拟化:把别人的硬件当自己的

“现在讲最容易让人震撼的部分。”

3.1 分布式硬件

“设备虚拟化,就是把一个设备的硬件能力,'映射’到另一个设备上。”

     手机                              开发板
  ┌──────────┐                     ┌──────────┐
  │ 应用       │                     │  SHT30   │
  │           │                     │  传感器   │
  │ 调用       │                     └────┬─────┘
  │ 温湿度API │                          │
  └─────┬────┘                          │
        │                               │
        └──────── 软总线 ──────────────┘
              ↑
        分布式硬件虚拟化层

“对手机上的应用来说,它调用的就是一个’本地传感器’。它不知道这个传感器其实在两米外的开发板上。”

“具体怎么实现的?”

"三个角色:

┌─────────────┐    ┌─────────────┐    ┌─────────────┐
│   Source    │    │  SoftBus    │    │    Sink     │
│  (提供硬件)│───►│  (软总线)  │───►│  (使用硬件)│
│  开发板      │    │             │    │  手机        │
└─────────────┘    └─────────────┘    └─────────────┘
  真实硬件在这          负责传输           虚拟硬件在这

“Source 端把自己真实的硬件注册到软总线上;Sink 端从软总线拿到一个’虚拟硬件’,用起来跟真的一样。”

3.2 常见的分布式硬件

分布式硬件 能力 典型场景
分布式相机 调用别的设备的摄像头 手表扫码、多机位拍摄
分布式麦克风 / 扬声器 借用音频输入输出 用手机麦克风给电视语音输入
分布式屏幕 把画面投到别的屏 手机 → 智慧屏
分布式传感器 读取远端的传感器 手机读开发板的温湿度
分布式存储 访问别设备的文件 手机直接打开平板上的文档
分布式 GPU / NPU 借算力 小设备跑 AI 推理

“你的项目要用的,是’分布式传感器’这一项。”

四、动手:让手机读到开发板的温湿度

"现在开始干活。"老陈说,“分四步。”

4.1 第一步:发现并认证设备

import distributedDeviceManager from '@ohos.distributedDeviceManager';
import { BusinessError } from '@ohos.base';

class DeviceHelper {
  private dm: distributedDeviceManager.DeviceManager | null = null;

  // ---------- 创建设备管理器 ----------
  init(bundleName: string): void {
    try {
      this.dm = distributedDeviceManager.createDeviceManager(bundleName);

      // 监听设备状态变化(上线 / 下线 / 认证完成)
      this.dm.on('deviceStateChange', (data) => {
        console.info(`设备状态变化: ${JSON.stringify(data)}`);
        // data.action:
        //   0 = 上线(ONLINE)   1 = 就绪(READY)
        //   2 = 下线(OFFLINE)  3 = 状态变化(CHANGE)
      });

      // 监听发现到的设备
      this.dm.on('deviceFound', (data) => {
        console.info(`发现设备: ${JSON.stringify(data)}`);
      });

      // 监听认证结果
      this.dm.on('deviceAuthenticate', (data) => {
        console.info(`认证结果: ${JSON.stringify(data)}`);
      });

    } catch (err) {
      console.error(`创建失败: ${(err as BusinessError).message}`);
    }
  }

  // ---------- 获取已认证(可信)设备列表 ----------
  getTrustedDevices(): distributedDeviceManager.DeviceBasicInfo[] {
    if (!this.dm) return [];
    try {
      return this.dm.getAvailableDeviceListSync();   // 同步接口
    } catch (err) {
      console.error(`获取列表失败: ${(err as BusinessError).message}`);
      return [];
    }
  }

  // ---------- 开始发现周边设备 ----------
  startDiscover(): void {
    if (!this.dm) return;
    let discoverParam: Record<string, number> = {
      'discoverTargetType': 1      // 1 = 发现所有类型
    };
    let filterOptions: Record<string, number> = {
      'availableStatus': 1,        // 只要在线的
      'discoverDistance': 0,       // 0 = 近距离
      'authenticationStatus': 0    // 0 = 未认证(一起发现)
    };
    try {
      this.dm.startDiscovering(discoverParam, filterOptions);
    } catch (err) {
      console.error(`发现失败: ${(err as BusinessError).message}`);
    }
  }

  stopDiscover(): void {
    this.dm?.stopDiscovering();
  }

  // ---------- 认证一个设备(PIN 码方式) ----------
  authenticate(deviceId: string, onPin: (pin: string) => void): void {
    if (!this.dm) return;
    let extraInfo: Record<string, string> = {
      'targetPkgName': 'com.example.myapp',
      'appName': '温湿度监控',
      'appDescription': '需要连接你的传感器设备',
      'business': '0'
    };
    let authParam: Record<string, number | string> = {
      'authType': 1,               // 1 = PIN 码认证
      'extraInfo': JSON.stringify(extraInfo)
    };

    try {
      this.dm.authenticateDevice(deviceId, authParam, (err, data) => {
        if (err) {
          console.error(`认证失败: ${JSON.stringify(err)}`);
          return;
        }
        // 对方设备上会显示一个 PIN 码,这里拿到了要展示给用户
        let pin = data?.pin as string;
        if (pin) { onPin(pin); }
      });
    } catch (err) {
      console.error(`认证异常: ${(err as BusinessError).message}`);
    }
  }

  destroy(): void {
    if (this.dm) {
      this.dm.off('deviceStateChange');
      this.dm.off('deviceFound');
      this.dm.off('deviceAuthenticate');
      this.dm = null;
    }
  }
}

"几个要点:"老陈说。

1. createDeviceManager 要传 bundleName
2. 监听有三个:deviceStateChange / deviceFound / deviceAuthenticate
3. getAvailableDeviceListSync() 拿【已认证】的设备
4. startDiscovering() 发现【未认证】的周边设备
5. authenticateDevice() 发起认证,回调里拿到 PIN 码
6. 用完 destroy(),注销监听

4.2 第二步:跨设备启动 Ability

“认证之后,你可以直接在别的设备上启动一个 Ability。”

import common from '@ohos.app.ability.common';
import Want from '@ohos.app.ability.Want';

async startRemoteAbility(context: common.UIAbilityContext,
                        deviceId: string): Promise<void> {
  let want: Want = {
    deviceId:    deviceId,                    // ← 关键:指定目标设备!
    bundleName:  'com.example.myapp',
    abilityName: 'SensorAbility',
    parameters:  {
      action: 'start_collect',
      interval: 5000
    }
  };

  try {
    await context.startAbility(want);
    console.info('远端 Ability 已启动');
  } catch (err) {
    console.error(`启动失败: ${(err as BusinessError).code}`);
  }
}

"就多了一个 deviceId 字段。"老陈说,“这就是分布式的威力——API 几乎没变,但目标从’本机’变成了’网内任意一台设备’。”

4.3 第三步:跨端迁移(应用流转)

“迁移是指:把正在运行的界面,从设备 A 搬到设备 B,状态不丢。”

  手机上看到一半
        │
        │  用户在"任务中心"选择"流转到平板"
        ▼
  手机:onContinue() 保存状态  ──►  软总线  ──►  平板:onCreate()/onNewWant() 恢复状态
        │                                              │
        └── 手机上的页面关闭 ───────────────────────────└── 平板上的页面打开,进度一致

“代码长这样:”

import UIAbility from '@ohos.app.ability.UIAbility';
import type Want from '@ohos.app.ability.Want';
import type AbilityConstant from '@ohos.app.ability.AbilityConstant';

export default class EntryAbility extends UIAbility {
  // ===== 源端:我要被迁移走了,保存状态 =====
  onContinue(wantParam: Record<string, Object>): AbilityConstant.OnContinueResult {
    console.info('onContinue: 保存迁移状态');

    // 把要带过去的数据塞进 wantParam
    wantParam['currentPage']  = 'DetailPage';
    wantParam['deviceId']     = 'dev_001';
    wantParam['scrollOffset'] = AppStorage.Get<number>('scrollOffset') ?? 0;
    wantParam['draftText']    = AppStorage.Get<string>('draftText') ?? '';

    // 返回 AGREE 表示同意迁移;REJECT 表示拒绝
    return AbilityConstant.OnContinueResult.AGREE;
  }

  // ===== 目标端:我接手了,恢复状态 =====
  onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
    console.info('onCreate: 恢复迁移状态');

    // launchParam.launchReason 会告诉你这是不是一次迁移
    if (launchParam.launchReason === AbilityConstant.LaunchReason.CONTINUATION) {
      let page  = want.parameters?.['currentPage'] as string;
      let devId = want.parameters?.['deviceId'] as string;
      let off   = want.parameters?.['scrollOffset'] as number;

      AppStorage.SetOrCreate('restoredPage', page);
      AppStorage.SetOrCreate('deviceId', devId);
      AppStorage.SetOrCreate('scrollOffset', off);
    }
  }

  // 如果目标端已经有这个 Ability 在跑,会走 onNewWant
  onNewWant(want: Want, launchParam: AbilityConstant.LaunchParam): void {
    console.info('onNewWant: 接收新的迁移请求');
    // 同样恢复状态
  }
}

“wantParam 有大小限制(一般几十 KB)。“老陈提醒,”**只能装状态,不能装大数据。**要传大块数据,用分布式文件或分布式数据库。”

4.4 第四步:分布式数据同步

“最后一步,也是最常用的:让数据自动在多台设备间同步。”

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

class DistributedData {
  private kvManager: distributedKVStore.KVManager | null = null;
  private kvStore: distributedKVStore.SingleKVStore | null = null;

  // ---------- 初始化 ----------
  async init(bundleName: string, context: common.Context): Promise<void> {
    const kvManagerConfig: distributedKVStore.KVManagerConfig = {
      context: context,
      bundleName: bundleName
    };
    this.kvManager = distributedKVStore.createKVManager(kvManagerConfig);

    const options: distributedKVStore.Options = {
      createIfMissing: true,                        // 不存在就创建
      encrypt: true,                                // 加密存储
      backup: false,
      autoSync: true,                               // ← 自动同步!
      kvStoreType: distributedKVStore.KVStoreType.SINGLE_VERSION,
      securityLevel: distributedKVStore.SecurityLevel.S2
    };

    this.kvStore = await this.kvManager.getKVStore<distributedKVStore.SingleKVStore>(
      'sensor_store', options
    );

    // 监听数据变化(别的设备改了,这边会收到)
    this.kvStore.on('dataChange',
      distributedKVStore.SubscribeType.SUBSCRIBE_TYPE_REMOTE,
      (data) => {
        console.info(`数据变化: ${JSON.stringify(data)}`);
        // data.insertEntries / updateEntries / deleteEntries
        // data.deviceId —— 哪个设备改的
      }
    );
  }

  // ---------- 写数据 ----------
  async put(key: string, value: string | number | boolean | Uint8Array): Promise<void> {
    await this.kvStore?.put(key, value);
  }

  // ---------- 读数据 ----------
  async get(key: string): Promise<distributedKVStore.ValueType | undefined> {
    return await this.kvStore?.get(key);
  }

  // ---------- 手动同步到指定设备 ----------
  sync(deviceIds: string[], mode: distributedKVStore.SyncMode): void {
    if (!this.kvStore) return;

    this.kvStore.sync(deviceIds, mode, 1000);   // 超时 1000ms
    // SyncMode:
    //   PUSH_ONLY  只推(我改了,发给你们)
    //   PULL_ONLY  只拉(你们改了,我要过来)
    //   PUSH_PULL  又推又拉(最常用)
  }

  // ---------- 清理 ----------
  destroy(): void {
    this.kvStore?.off('dataChange');
    this.kvManager?.closeKVStore('sensor_store');
  }
}

// ===== 使用 =====
let dd = new DistributedData();
await dd.init('com.example.myapp', getContext(this));

// 本机写入,会自动同步到组网内的其他设备
await dd.put('livingroom_temp', 26.5);
await dd.put('livingroom_humi', 61);

// 也可以手动触发同步
dd.sync(['device_id_1', 'device_id_2'], distributedKVStore.SyncMode.PUSH_PULL);

"autoSync: true 是关键。"老陈说,“开了它,你 put 一次,组网内所有设备都能看到。”

“那如果两台设备同时改同一个 key 呢?”

"冲突。"老陈说,“分布式系统避不开这个问题。KVStore 的处理是——”

冲突解决策略:
1. 时间戳 —— 后写的覆盖先写的(默认)
2. 设备优先级 —— 某些设备优先级更高
3. 业务自定义 —— 你自己实现合并逻辑

“**我的建议:设计 key 的时候就避免冲突。**比如按设备分 key——dev001_temp、dev002_temp,而不是共用一个 temp。”

五、分布式任务调度

“还有最后一块:让系统在合适的设备上跑合适的任务。”

┌─────────────────────────────────────────────┐
│  分布式任务调度                                │
├─────────────────────────────────────────────┤
│  · 查询网内各设备的能力(CPU/内存/屏幕/传感器)   │
│  · 根据任务需求,挑最合适的设备执行               │
│  · 支持远程启动、远程迁移、远程停止               │
└─────────────────────────────────────────────┘

“举个实际例子:你的人脸识别任务需要 NPU。系统扫一圈发现——门锁没有 NPU、手机有——自动把任务丢给手机算。”

“这对我们意味着什么?”

"意味着你写代码的时候,可以’声明需求’而不是’指定设备’。"老陈说,“你说’我需要一个带 NPU 的设备’,系统帮你找。这在异构硬件环境下非常重要。”

六、安全:分布式的命门

"讲完能力,必须讲安全。"老陈的语气变重了。

“**分布式 = 你的数据会跑到别的设备上。**这带来三个风险:”

风险一:假冒设备 —— 一个恶意设备伪装成你的传感器
风险二:窃听     —— 通信被中间人截获
风险三:越权     —— 别的应用读到你的分布式数据

6.1 鸿蒙怎么防

层次 机制
设备层 设备认证(PIN/碰一碰/同帐号)+ 证书交换
通信层 软总线通信全程加密(基于会话密钥)
数据层 数据分级:设备级 / 用户级 / 应用级;KVStore 支持 encrypt: true 和 SecurityLevel S1~S4
应用层 权限管控:分布式操作需要 DISTRIBUTED_DATASYNC 等权限
身份层 tokenID:每个应用有唯一身份标识,跨设备也认

“权限别忘了申请:”

{
  "module": {
    "requestPermissions": [
      {
        "name": "ohos.permission.DISTRIBUTED_DATASYNC",
        "reason": "$string:distributed_reason",
        "usedScene": {
          "abilities": ["EntryAbility"],
          "when": "always"
        }
      }
    ]
  }
}

“这是 user_grant 权限,要弹窗让用户同意。”

6.2 一条铁律

老陈在白板上写:

分布式的能力越强大,出错的代价就越大。
永远假设网络会断、设备会离线、对端可能是旧版本。

“具体怎么做?”

1. 每次调用前检查对端是否在线
2. 所有跨设备调用都要有超时
3. 所有跨设备调用都要有失败降级
4. 不要假设对端的应用版本和你一样
5. 敏感数据不要放在未加密的分布式存储里

七、常见坑

现象 原因 解法
发现不到设备 ① 不在同一 Wi-Fi
② 蓝牙没开
③ 防火墙隔离了局域网
确认网络;开蓝牙;关掉 AP 隔离
认证一直失败 ① PIN 码输错
② 两端应用签名不一致
③ 时间不同步
检查 PIN;确保两端用同一套证书签名
getAvailableDeviceListSync 返回空 设备还没认证 先 authenticateDevice
跨设备启动 Ability 失败 ① deviceId 错了
② 目标设备没装这个应用
③ 目标 Ability 没 exported: true
检查 deviceId;检查 exported
数据没同步 ① autoSync 没开
② 没调 sync()
③ 设备不在线
开 autoSync;手动 sync;确认在线
连接上了但很慢 走了蓝牙而不是 Wi-Fi 确认两端在同一 Wi-Fi;检查信号

"排错顺序:"老陈总结,“先网络 → 再认证 → 再权限 → 最后看代码。”

=================小剧场模式=================

我:老师,我有个根本性的疑问。

老陈:说。

我:这些事,用普通的网络编程也能做啊。 手机和开发板连同一个 Wi-Fi,开发板起个 HTTP 服务器,手机去轮询——不也能读到温湿度吗?

老陈:能。 而且很多人就是这么干的。

我:那分布式软总线的价值在哪?

老陈:我给你算笔账。 你自己实现一套,要做什么?

我:(数)设备发现、设备认证、连接管理、断线重连、数据加密、冲突解决、多链路选择、权限管控……

老陈:还有设备能力查询、状态同步、跨设备调用、版本兼容、功耗优化。

我:……

老陈:这些鸿蒙全给你做好了,你只需要调用 API。 而且它是系统级的——所有应用共享同一套认证,用户配对一次,所有应用都能用。

我:所以价值是省掉了全部基础设施?

老陈:对。而且是统一标准的。 你自己实现的方案,只能你的应用用;软总线的方案,所有鸿蒙设备、所有应用都认。

我:就像……大家都说同一种语言?

老陈:就像第 01 章说的——让一堆设备像一个设备那样工作。 你现在明白那句话了吧?

========================================

八、本章速查

【软总线四步】
发现(谁在附近)→ 认证(你是谁)→ 组网(超级终端)→ 传输(说正事)

【关键 API】
distributedDeviceManager.createDeviceManager()     创建管理器
  .getAvailableDeviceListSync()                    已认证设备
  .startDiscovering()                              发现周边
  .authenticateDevice()                            认证(拿 PIN)

startAbility({ deviceId, bundleName, abilityName })  跨设备启动
onContinue() / onCreate(launchReason=CONTINUATION)   跨端迁移
distributedKVStore + autoSync                        数据自动同步

【设备虚拟化】
Source(提供硬件)→ 软总线 → Sink(虚拟硬件)
分布式相机 / 麦克风 / 屏幕 / 传感器 / 存储 / 算力

【权限】
ohos.permission.DISTRIBUTED_DATASYNC(user_grant,要弹窗)

【铁律】
假设网络会断、设备会离线、对端是旧版本
跨设备调用:必查在线 + 必设超时 + 必有降级

"这一章,"老陈合上本子,“如果这本书你只能记住一章,就记这一章。”

“为什么?”

"因为 APK、ArkTS、Ability、路由这些,别的系统也有。"他说,“但’把一堆设备变成一个设备’——这是鸿蒙真正不一样的地方。”

“下一章呢?”

老陈把那块 Hi3861 又推到我面前。

“你的温湿度数据,现在还在开发板上,对吧?”

“对。”

"分布式能让它跑到手机上。但你有没有想过——"他敲了敲板子,“开发板上跑的是 C 代码,手机上跑的是 ArkTS。它们俩,怎么直接对话?”

我愣住了。

“……对啊。我一直在想设备之间怎么连,但没想过——设备内部的两种代码,怎么打通。”

"这就是下一章。"老陈说。

“NAPI。南北打通。”


本章自检

过一遍下面的问题。答不上来的,回去翻对应小节——那些就是你这个章的欠账。

  • ☐ 软总线的四个阶段分别做什么?
  • ☐ 「发现」和「认证」的区别?为什么必须先认证?
  • ☐ Want 里加了 deviceId 会发生什么?
  • ☐ 跨端迁移时,保存状态用哪个回调?恢复又在哪?
  • ☐ wantParam 有没有大小限制?大数据该怎么传?
  • ☐ 分布式环境下,安全靠哪几层来保证?
  • ☐ 说出一句总结:分布式到底想让什么变得像什么?

**➡️ 下一站:**第 10 章 · 南北打通 —— 让 C 和 ArkTS 直接对话。


=================剧情片段=================

导演:卡。这一章是全书的第一个高潮。

助理:软总线、设备虚拟化、跨端迁移、分布式数据——信息量很大,但主线很清楚。

导演:主线就是那四个字:硬件互助。 所有技术都是为它服务的。

助理:下一章 NAPI,是不是有点"降温"?

导演:不,是另一个高潮。 前面九章,南向和北向是两条平行线——

助理:对,C 语言和 ArkTS 各干各的。

导演:NAPI 把它们接起来。 打通之后,主角才能做出一个真正的软硬结合产品。

助理:而且这正好是他专业背景的优势?

导演:对。 会 C 又会 ArkTS、还能把两者接起来的人——这就是他在这个行业里最值钱的地方。

助理:那下一章要讲透 NAPI 的机制。

导演:N-API 是什么、为什么用它、怎么注册模块、类型转换、异步回调、线程安全——一个都不能少。

助理:还有个完整的软硬结合案例吧?

导演:有。从驱动到应用,一条线走到底。

========================================

未完待续。。。

支持与分享

如果这篇文章对你有帮助,欢迎分享给更多人或者给予支持!

评论

欢迎来到我的博客!