鸿蒙跨设备互通:让你的应用"借用"另一台设备的相机和图库

11 阅读8分钟

引言

想象一个场景:你正在平板上编辑一份文档,需要插入一张纸质资料的照片。平板没有后置摄像头,或者拍照体验远不如手机——这时候如果能直接调起旁边那台手机的相机,拍完照片自动传回平板,那该多省事。

这就是鸿蒙跨设备互通要解决的问题。它提供了一种能力,让一台设备可以调用同账号下另一台设备的相机、扫描和图库功能,拍照、扫文档、选图片视频,都不用再手动传来传去。

本文基于鸿蒙跨设备互通的开发接口,梳理这项能力的适用范围、使用条件,以及如何在应用中完成一次完整的跨设备调用。适合对鸿蒙开发有一定基础、希望为应用接入多设备协同能力的开发者阅读。


一、哪些设备能互通,谁能调用谁

跨设备互通并不是任意两台鸿蒙设备之间都能随便调用的,它有一套明确的设备关系和调用方向。

1.1 基础调用关系

最初的设计思路很直观——屏幕更大、但拍照能力可能不够好的设备,去调用拍照更强的设备:

  • 2in1 设备可以调用平板和手机
  • 平板可以调用手机

也就是说,调用方向大致是"大屏调小屏"。

1.2 API 6.1.0(23) 之后的扩展

从 API 6.1.0(23) 开始,调用关系变得更加灵活。手机、平板和 2in1 设备都可以作为发起方,去调用远端设备的能力,但远端设备能提供什么能力,取决于设备类型:

远端设备类型可被调用的能力
手机拍照、扫描、图库(图片与视频)
平板拍照、扫描、图库(图片与视频)
2in1 设备图库(图片与视频)

简单来说,手机和平板是"全能选手",三项能力都能被远端调用;2in1 设备因为自身定位,只对外开放图库能力。

1.3 必须满足的前提条件

要让跨设备互通正常工作,以下条件缺一不可:

  • 系统版本:双端设备都需要运行 HarmonyOS NEXT 及以上版本。
  • 同一账号:双端设备必须登录同一个华为账号。
  • 网络和蓝牙:双端设备都需要打开 WLAN 和蓝牙开关。如果条件允许,接入同一个局域网可以明显提升唤醒远端相机的速度。

如果在调用视频选择器时遇到资源加载异常,建议先确认双端的设备调用能力是否匹配、系统状态是否正常,然后在稳定的网络环境下重试。


二、核心流程:从发现设备到接收数据

跨设备互通的开发流程可以拆解为三个环节:发现可用设备 → 发起调用 → 接收回传数据。鸿蒙为这三个环节提供了对应的组件支持。

2.1 发现设备:设备列表选择器

第一步是让用户看到周围有哪些设备可以调用。这通过 createCollaborationServiceMenuItems 来实现——它是一个自定义构建函数,作用是在菜单中展示当前组网内具备对应互通能力的设备列表。

使用时需要传入一个能力过滤参数(CollaborationServiceFilter),告诉它你需要哪种能力的设备。目前支持的过滤值包括:

过滤值含义
ALL匹配拍照、扫描和图库选择器(预留值,后续会拓展)
TAKE_PHOTO匹配跨设备拍照能力
SCAN_DOCUMENT匹配跨设备扫描能力
IMAGE_PICKER匹配跨设备图库(图片)能力
VIDEO_PICKER匹配视频选择器
IMAGE_VIDEO_PICKER匹配图片和视频选择器

有一点需要注意:这个方法必须在 Menu 组件内调用,因为它本质上是往菜单里填充设备列表项。同时它是一个 @Builder 自定义构建函数,如果你对 @Builder 的用法还不太熟悉,建议先了解一下相关文档。

2.2 状态提示与数据回传:弹窗组件

当用户选择了一台远端设备并触发操作后(比如在远端手机上拍照),你需要一个组件来做两件事:一是提示用户远端设备当前的操作状态,二是在操作完成后接收回传的数据。

CollaborationServiceStateDialog 就是做这个的。它是一个全局弹窗组件,放在页面的 build 方法中即可,不会影响原有的页面布局。它最关键的部分是 onState 回调方法,这个回调会在远端操作完成时被触发,带回三个参数:

  • stateCode:操作完成状态,0 表示成功
  • bufferType:回传数据的类型(比如 "general.image" 表示图片)
  • buffer:回传的数据内容本身(ArrayBuffer 格式)

开发者只需要在 onState 里根据这些参数,结合自己的业务逻辑处理回传数据即可。


三、完整开发实践:调用远端相机拍照并显示

理解了上面的核心流程后,我们来看一个完整的实现。这个示例的目标很简单:点击按钮弹出可用设备列表,选择一台远端设备拍照,拍完后把照片显示在本端页面上。

3.1 导入所需模块

import {
  createCollaborationServiceMenuItems,
  CollaborationServiceStateDialog,
  CollaborationServiceFilter
} from '@kit.ServiceCollaborationKit';
import { image } from '@kit.ImageKit';
import { hilog } from '@kit.PerformanceAnalysisKit';

这里引入了三个 Kit:ServiceCollaborationKit 提供跨设备互通的核心能力,ImageKit 用于处理回传的图片数据,PerformanceAnalysisKit 用于日志输出。

3.2 搭建页面结构

@Entry
@Component
struct Index {
  @State picture: PixelMap | undefined = undefined;

  @Builder
  MyTestMenu() {
    Menu() {
      createCollaborationServiceMenuItems([CollaborationServiceFilter.ALL])
    }
  }

  build() {
    Column({ space: 20 }) {
      // 状态弹窗:全局组件,不影响布局
      CollaborationServiceStateDialog({
        onState: (stateCode: number, bufferType: string, buffer: ArrayBuffer): void =>
          this.doInsertPicture(stateCode, bufferType, buffer)
      })

      // 按钮:点击后弹出设备选择菜单
      Button('使用远端设备进行拍照')
        .type(ButtonType.Normal)
        .borderRadius(10)
        .bindMenu(this.MyTestMenu)

      // 图片展示区:拍照完成后显示回传的照片
      if (this.picture) {
        Image(this.picture)
          .borderStyle(BorderStyle.Dotted)
          .borderWidth(1)
          .objectFit(ImageFit.Contain)
          .height('80%')
          .onComplete((event) => {
            if (event != undefined) {
              hilog.info(0, "MEMOMOCK", "onComplete " + event.loadingStatus)
            }
          })
      }
    }
    .padding(20)
    .width('100%')
    .alignItems(HorizontalAlign.Center)
  }
}

整个页面结构很清晰:顶部是全局的状态弹窗(用户感知不到它的存在,除非有状态需要提示),中间是触发操作的按钮,底部是照片展示区域。

按钮通过 .bindMenu(this.MyTestMenu) 绑定了设备列表菜单。用户点击按钮后,会看到周围可用的设备列表,选中某台设备就会唤起该设备的相机。

3.3 处理回传的照片数据

doInsertPicture(stateCode: number, bufferType: string, buffer: ArrayBuffer): void {
  if (stateCode != 0) {
    return
  }
  if (bufferType == "general.image") {
    let imageSource = image.createImageSource(buffer)
    imageSource.createPixelMap().then((pixelMap) => {
      this.picture = pixelMap;
    })
  }
}

这段逻辑是整个流程的"收尾"环节:

  1. 先检查 stateCode 是否为 0(即操作成功),不成功则直接返回。
  2. 确认回传数据类型是图片("general.image")。
  3. ImageKitcreateImageSourceArrayBuffer 创建图片源,再转成 PixelMap
  4. 赋值给状态变量 picture,触发页面刷新,照片就显示出来了。

整个过程中,开发者不需要关心设备发现、连接建立、数据传输这些底层细节,框架已经把这些封装好了。你只需要关注"要什么能力"和"拿到数据后怎么用"。


四、总结与实践建议

跨设备互通的核心价值在于打破了单台设备的能力边界。对于平板、2in1 这类大屏设备来说,它补齐了拍照和扫描的短板;对于多设备协作的场景,它省去了拍照后手动传文件的繁琐操作。

从开发角度看,这项能力的接入成本并不高。核心就是两个组件的配合使用:createCollaborationServiceMenuItems 负责设备发现和选择,CollaborationServiceStateDialog 负责状态提示和数据回传。开发者的主要工作集中在 onState 回调中——根据回传的数据类型,做好业务层面的处理即可。

在实际接入时,有几点值得注意:

  • 能力过滤要精准:如果你的场景只需要拍照,传 TAKE_PHOTO 而不是 ALL,可以让设备列表更准确,避免用户看到不相关的选项。
  • 同一局域网能提速:虽然 WLAN + 蓝牙是最低要求,但接入同一局域网对唤醒速度有明显帮助,在产品文案或引导中可以提示用户。
  • 关注 API 版本差异:6.1.0(23) 前后的调用方向有变化。如果你的应用需要兼容较早版本,在设备能力判断上要做好区分。
  • 回传数据类型判断onState 回调中的 bufferType 会区分图片和视频等不同类型,做好类型判断再处理,避免数据解析出错。

对于已经在做多设备协同场景的应用来说,跨设备互通是一个值得优先接入的能力——它的使用门槛低,但带来的体验提升是用户能直接感知到的。