在这里插入图片描述

摘要

这是一篇关于距离与抵达的心迹。我和我妈隔着一千多公里,隔着三个月没见的面,也隔着一块总也看不清的屏幕。微信把照片压成模糊的色块,把视频传成转圈的等待,她那句"你发的不清楚",其实是一次次不好意思说出口的失落。直到用上鸿蒙的远场分享——不在附近也能发,而且原样不压缩——她第一次看清了高原上云的纹路,也第一次主动把院里开花的月季发回给我。这篇文章从这件小事写起,聊远场分享如何把"附近才能传"的默认改成"只要你想,就能原样送到",也聊我那些贪心的想象:分享能不能带上上下文、能不能跨设备自己"出现",以及更重要的——推送要懂得安静,授权要落在长辈那一侧。技术最温柔的部分,从来不是参数多漂亮,而是让某个远方的人,原样收到你的心意。

目录

一、一千公里,和三个月

我妈在老家,我在外地。两个城市之间,隔着一千多公里,隔着一张机票的价格,也隔着一种说不清的、慢慢习惯了的疏离。上一次见她,是三个月前的事。那次我拎着行李走的时候,她在门口站了很久,说了一句"路上慢点",然后转身去关电视。我没回头,可我知道她在看我。

我们这一代人,大概都活在这样的夹缝里:人在远方,心在家里,可心和家之间,总隔着一块发烫的屏幕。我和我妈的联络,多半是微信上几句不咸不淡的"吃了吗"“挺好的”。我知道她想知道的远不止这些,我也知道我想让她看见的,远比文字能装下的多。

小时候,我和在外地打工的表姐通信,靠的是邮票和信纸。一封信要走一个星期,可当它终于躺在手里,每一个字都带着重量,因为你知道,写它的人,是认真想让你看见的。后来有了微信,距离被压缩成一秒,可某种重量,也跟着一起被压缩了。我们发得越来越快,却越来越少"原样"。我常常想,技术的进步,是不是也在悄悄拿走某种郑重——那种"我特意让你看见"的郑重。

二、那些"不清楚"的夜晚

以前想让她看看我拍的东西,只能发微信。可微信是给"能凑合"的人设计的——照片被压成一团模糊,视频传到一半转圈,声音和画面常常对不上。她总说"你发的不清楚",然后就很体贴地不再多问。

我后来才懂,她不是真的在嫌画质。她是那种把"孩子想让我看见"这件事,悄悄换算成了"我没能看清"的遗憾。隔着屏幕,那份失落也一并传了过来。我妈这辈子没用过几样智能设备,她不会调清晰度,不会点"原图",甚至不太确定自己收到的,到底是不是我拍的那个版本。每一次"不清楚",都是一次微小的、她不好意思说出口的挫败。

我记得有一次,我在海边拍了张日落发给她,天边那道金红色的光,是我那阵子见过最好看的。她回得很快:"你这照片咋这么暗,是不是天黑了?"我盯着那行字,半天没说出话——她看到的,是一团被压缩成深灰的、丢失了所有层次的色块。我想告诉她那光有多亮,可隔着屏幕,语言太苍白。

我试过教她。视频通话里,我在这头比划:“你点这个,再点原图。“她在那头点头,说"看见了看见了”。可挂了电话再操作,又回到原点——她记不住那些藏在三级菜单里的开关,就像我记不住她年轻时会做的那些菜的顺序。那种"近在咫尺的远”,比地理上的远更让人无力。

三、第一次"原样"抵达

转机是鸿蒙的远场分享。它最打动我的一句话,是"原样传递"——不在附近也能发,而且不压缩。我一开始将信将疑,毕竟"原样"这两个字,在太多产品里只是宣传语,落到手上往往打了折扣。

直到我第一次把一段旅行视频,原样发给我妈。那是我站在高原上拍的,天很低,云很厚,风把草吹成一片流动的绿。以往发微信,这段视频到她手机上,云成了灰白的一团,风的声音闷得像隔着棉被。而那次,她收到后愣了好一会儿,才慢慢说了一句:“这云彩的纹路,都看得清。”

我握着手机,鼻子有点酸。就这一句,值了我之前所有折腾。所谓"原样",传的不只是像素,是我当时站在那片风景前面,想让她也站一站的心情。她看清了云,也就离我站过的地方,近了一点。后来她把那段视频反复看了好几遍,还转发给了小区的老姐妹,配文是"我儿子拍的"。我没好意思说那云其实是在八百公里外,可我知道,她分享的不是一段画质,是一份骄傲。

过了几天,她又用远场分享,给我发回来一段她院里月季开花的视频。画质依旧算不上好,可那是她第一次主动"也让我看见你"。我们之间那块发烫的屏幕,好像凉下来一点,变成了能原样握住的通道。

四、不在附近,也能送到

鸿蒙总在讲"分布式",讲设备与设备之间那种无感协同。可在我这儿,它更像一种关于"在场"的哲学:距离,不该决定抵达的质量。

我们习惯了"附近才能传"——蓝牙要贴着,Wi-Fi 要同网,分享这件事,默认是给身边人准备的。可生活里最想分享的人,偏偏都不在身边。远场分享把那个默认设置,悄悄改成了"只要你想,就能原样送到"。技术退到后面,人和人之间那点惦记,浮到前面。

我把工作里拍的一段演示视频,也原样发给了异地出差的同事。以往这种事,得先传云盘、再发链接、等对方下载,中间还担心他网速慢、担心文件过期。那次直接从联系人里发起,他点个同意,文件就落在了他的设备上,带着我拍时的所有细节。他回我:"这下清楚了,比邮件靠谱。"我笑了笑——原来"原样"这件事,救的不只是亲情,还有那些被传输门槛磨掉的效率。一个功能能不能打动人,往往就看它是不是悄悄替你,把那点"将就"给抹平了。

我还试过给一个远在另一个城市的朋友发旅行视频。她当时正闷在办公室加班,收到那段原样的海和风,回了我一句"谢谢你让我喘了口气"。那一刻我意识到,远场分享治愈的不只是"看不见",还有"不在场"的那种孤单。

五、把"原样"落到代码里

前面写的都是感受,这一节换个视角,说说如果真要把远场分享接进一个鸿蒙应用,代码层面大概要经过哪几步。我按自己踩过的顺序整理,尽量让每一步都能直接对着文档跑通。

1. 先声明能力与权限

远场分享依赖分布式设备发现与跨设备数据传输,需要在 module.json5 里声明对应权限,并在首次使用时向用户申请:

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

DISTRIBUTED_DATASYNC 属于用户授权权限,必须在运行时动态申请,不能只写在配置里就当作已授权:

import { abilityAccessCtrl, common, Permissions } from '@kit.AbilityKit';
import { BusinessError } from '@kit.BasicServicesKit';

const PERMISSIONS: Permissions[] = ['ohos.permission.DISTRIBUTED_DATASYNC'];

async function requestSharePermission(context: common.UIAbilityContext): Promise<boolean> {
  const atManager = abilityAccessCtrl.createAtManager();
  try {
    const result = await atManager.requestPermissionsFromUser(context, PERMISSIONS);
    // 0 表示已授权
    return result.authResults.every((code: number) => code === 0);
  } catch (err) {
    const error = err as BusinessError;
    console.error(`request permission failed, code: ${error.code}, msg: ${error.message}`);
    return false;
  }
}

2. 发送端:从联系人发起一次原样传输

发送端的核心是"选设备 → 建会话 → 传文件"。设备发现用分布式设备管理,传输用跨设备数据通道,文件本身走文件描述符,避免把大视频整个读进内存:

import { distributedDeviceManager } from '@kit.DistributedServiceKit';
import { fileIo as fs } from '@kit.CoreFileKit';

// 1) 发现可信设备
function listenTrustedDevices(onFound: (device: distributedDeviceManager.DeviceBasicInfo) => void) {
  const dmInstance = distributedDeviceManager.createDeviceManager('com.example.farshare');
  dmInstance.on('deviceStateChange', (data: distributedDeviceManager.DeviceStateChangeInfo) => {
    if (data.action === distributedDeviceManager.DeviceStateChange.AVAILABLE) {
      onFound(data.device);
    }
  });
  return dmInstance;
}

// 2) 以只读方式打开待分享文件,拿到 fd
function openForShare(filePath: string): fs.File {
  return fs.openSync(filePath, fs.OpenMode.READ_ONLY);
}

拿到 fd 之后,把它和文件名、大小、MIME 类型一起封装成传输请求发给对端。这里有个容易忽略的点:"不压缩"不是默认行为,而是要在传输参数里显式关掉转码,否则图片仍可能被按屏幕尺寸重采样,视频仍可能被降码率——那"原样"就又成了宣传语。

interface SharePayload {
  fileName: string;
  fileSize: number;
  mimeType: string;
  fd: number;
  // 关键:显式声明原样传输,禁止服务端转码/重采样
  keepOriginal: true;
}

function buildPayload(filePath: string): SharePayload {
  const file = openForShare(filePath);
  const stat = fs.statSync(filePath);
  return {
    fileName: filePath.split('/').pop() ?? 'unnamed',
    fileSize: stat.size,
    mimeType: guessMimeType(filePath),
    fd: file.fd,
    keepOriginal: true
  };
}

3. 接收端:先确认,再落盘

接收端不要一收到就自动写进相册,先弹一次确认,把"是否接收""存到哪个目录"交给用户决定,这既是体验,也是隐私边界:

async function onShareReceived(payload: SharePayload, context: common.UIAbilityContext) {
  const granted = await showReceiveDialog(payload.fileName, payload.fileSize);
  if (!granted) {
    return; // 用户拒绝,直接丢弃,不落盘
  }
  const targetDir = context.filesDir + '/received';
  if (!fs.accessSync(targetDir)) {
    fs.mkdirSync(targetDir);
  }
  const targetPath = `${targetDir}/${payload.fileName}`;
  const dest = fs.openSync(targetPath, fs.OpenMode.CREATE | fs.OpenMode.READ_WRITE);
  // 按块搬运,避免大文件一次性占用内存
  await copyByChunk(payload.fd, dest.fd, payload.fileSize);
  fs.closeSync(dest);
  fs.closeSync({ fd: payload.fd });
}

4. 传输状态要能被感知

跨设备传输耗时不短,进度、失败重试、断点续传都得有反馈,否则用户只会看到"卡住了":

type TransferState = 'pending' | 'transferring' | 'success' | 'failed';

function onTransferProgress(state: TransferState, transferred: number, total: number) {
  const percent = total > 0 ? Math.floor((transferred / total) * 100) : 0;
  switch (state) {
    case 'transferring':
      updateProgressBar(percent);
      break;
    case 'success':
      toast('已原样送达');
      break;
    case 'failed':
      // 失败时保留已传分片,下次从断点继续
      toast('传输中断,可重试');
      break;
    default:
      break;
  }
}

5. 上下文打包:让文件带上"背后的门道"

第五节聊到的"带上上下文",落到代码上就是给 payload 加一个可选的 context 字段,把笔记、坐标、时间戳一起序列化过去。接收端解析后,就能在预览页旁边挂出"这道菜怎么复刻":

interface ShareContext {
  note?: string;          // 文字笔记,如食材清单
  location?: { lat: number; lon: number };
  capturedAt?: number;    // 拍摄时间戳
  deviceModel?: string;
}

function attachContext(payload: SharePayload, ctx: ShareContext): SharePayload {
  return { ...payload, context: ctx } as SharePayload & { context: ShareContext };
}

6. 隐私分级:默认最小授权

第七节说的"授权落在长辈那一侧",在代码里就是默认只同步白名单类型,并且把开关做成一次性、可回看的设置项,而不是藏在三级菜单:

const DEFAULT_ALLOWED_TYPES = ['image/jpeg', 'image/png', 'video/mp4'];

function isAllowedToSync(mimeType: string, userAllowed: string[]): boolean {
  const allowed = userAllowed.length > 0 ? userAllowed : DEFAULT_ALLOWED_TYPES;
  return allowed.includes(mimeType);
}

写到这里我最大的体会是:所谓"原样",在代码里其实是一连串默认值的取舍——默认不压缩、默认先确认、默认最小授权、默认给进度反馈。这些开关单看都不起眼,可它们叠在一起,才让"隔着屏幕也能原样抵达"从一句文案,变成用户真的能感受到的东西。

五、如果分享还能带上上下文

用了几次之后,我冒出一个贪心的念头:要是分享还能顺手带上上下文,该多好。

比如我给我妈发一段做菜的视频,能不能把对应的食材清单、火候和步骤笔记,一起打包过去?她点开视频,旁边就挂着"这道菜怎么复刻",不用再打电话问我"你放了多少盐"。再比如我发一段旅行视频,系统如果能自动带上拍摄地的坐标、时间和设备参数,她收到的就不只是一个文件,还有那段旅程背后的故事——我在哪、为什么停、当时几点。

文件还是那个文件,可附上的上下文,让它有了温度。分享不再是"我丢给你一段画面",而是"我把当时那整段经历,原样交给你"。我妈这种人,最在意的就是"背后的门道":她看我拍的菜,想知道怎么做的;看我拍的景,想知道在哪。上下文,恰恰是把"看见"升级成"懂得"的那把钥匙。

我甚至想象过一个具体的画面:过年回家,我教她做红烧肉,拍下视频,顺手把"五花肉一斤、冰糖八颗、先炒糖色再下肉"的笔记一起发去。她在老家照着做,做得比我还好,又发视频回来显摆。这样一来一回,隔着一千公里,我们竟像是在同一口锅边忙活。技术要是能成全这种"在一起",才算没白进步。

六、让分享自己"出现"

脑洞再放大一点,我更想要的是"跨设备接力"。我在外面用手机拍了段东西,家里那台平板不用我特意操作,就自动原样落了一份;我妈的开机屏或者锁屏,直接弹出一句"孩子刚分享给你一段视频"。她不用主动去翻哪个 App,不用琢磨怎么下载,抬眼就看见了。

在这个想象里,分享的主动权,从"我推给你",变成了"你刚好就在那看到"。技术退到更后面,人和人之间那点惦记,浮到最前面。我妈这种不太会用智能设备的人,恰恰最该被这种"不用学、不用找"的设计照顾到——不是让她适应机器,是让机器迁就她。

我脑子里常浮现一个清晨:她刚起床,平板从休眠里醒来,锁屏上静静躺着昨夜我发来的那段雪。她不用戴老花镜找图标,不用问我"在哪看",只是像翻日历一样,一眼就看见。那种不打扰的、刚刚好的出现,才是科技该有的体贴。我们总说科技要向善,可善的起点,往往只是把那个最不会被照顾到的人,也轻轻托住。

七、不打扰,是一门功课

当然,贪心之外,我也清楚这里面有分寸。开机屏弹窗要是没节制,就会从"贴心"变成"打扰";自动落盘要是没边界,隐私就成了一件悬在头顶的事。

我尤其在意两件事。一是授权要落在长辈那一侧:哪些内容允许自动同步到家里设备、能不能按"仅照片""仅视频"分级,得让他们一次性点清楚,而不是我在远端替他们决定。二是推送要懂得安静:最好能设个安静时段,或者把一天的消息收敛成一条摘要,别让锁屏变成随时蹦出来的广告位。主动推送和不动声色之间,那根线得拿捏好——毕竟,我们想给父母的,是陪伴,不是负担。

有一回,我差点把一张私密的截图也一起同步到了家里的平板,幸好动手前犹豫了一下。从那以后我更确信:能"原样"是本事,知道"什么不该原样"是修养。一项技术能不能被人长久地喜欢,往往不取决于它能做多少,而取决于它懂得克制什么。想清楚这些,我反而更期待了,因为真正成熟的"远场",不是把功能做满,是把分寸做对。

八、技术最温柔的部分

技术的浪漫,从来不是参数有多漂亮、跑分有多高。它最动人的时刻,往往很安静:是某个人,在某个远方,原样收到了你的心意。

前阵子,我妈破天荒地主动发来一段她拍的广场舞,画质算不上好,可那是她学会"也让我看见你"之后,递回来的回应。后来又是一桌刚出锅的菜,配了句"今天多做了你爱吃的"。我们之间的屏幕,好像没那么烫了——它不再是隔着一层、总也看不清的屏障,而成了能够原样抵达的通道。

隔着屏幕,也能原样抵达——这大概就是我眼里,鸿蒙最温柔的部分。它没说什么大话,只是悄悄把"想让你看见"这件事,变得真正可行。而这件事,值得我用很多个普通的深夜,去认真对待,也值得更多像我一样隔着距离的人,去慢慢相信。也许有一天,当"原样"成了分享的默认,我们反而会重新找回小时候那封信里的郑重——因为知道对方一定能看清,所以每一次发送,都格外用心。

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐