应用内拖拽一切正常,拖到另一台设备上,onDrop 里 event.getData() 返回空,getRecords() 也是空的。代码里 onDragStart 明明 setData 了一个自定义对象,字段都在,本机拖拽读得好好的。问题不在 setData 有没有执行,在跨设备拖拽不吃自定义 JS 对象。拖拽数据必须走 UDMF 的标准记录类型,比如 PlainText、FileUri、Image,对端只认识这些标准类型,自定义 Record 在跨设备链路上没有兼容承诺。

跨设备传的是标准 UTD,不是序列化后的 JS 对象

setData 成功只代表数据交给了系统,不代表对端一定能反序列化出你期望的对象。跨设备拖拽的正确姿势是把业务字段编码成 PlainText 的 JSON 字符串,或者把文件写成沙箱 URI 用 FileUri 传,接收端先读 getTypes(),再按实际记录类型解析。as 强转只绕过类型检查,不会把空数据转换出来。

typescript

import { unifiedDataChannel, uniformTypeDescriptor } from '@kit.ArkData';

// 拖出端:普通业务字段序列化成 PlainText
function buildDragData(payload: object): unifiedDataChannel.UnifiedData {
  const record = new unifiedDataChannel.UnifiedRecord(
    uniformTypeDescriptor.UniformDataType.PLAIN_TEXT,
    JSON.stringify(payload)
  );
  return new unifiedDataChannel.UnifiedData(record);
}

// 落入端:先判类型,再解析,不强转
function parseDropData(data: unifiedDataChannel.UnifiedData): object | null {
  for (const record of data.getRecords()) {
    if (record.getType() === uniformTypeDescriptor.UniformDataType.PLAIN_TEXT) {
      return JSON.parse(record.getValue() as string);
    }
  }
  return null;
}

getType() 的判断必须在 getValue() 之前。如果对端送来的不是 PLAIN_TEXT,强行走 JSON.parse 只会得到异常或空值。

大文件传引用不传内容,rawfile 不能直接跨设备拖

文件场景的正确做法是“传引用不传内容”:拖出方把文件写到应用沙箱,通过 FileUri 记录传出,系统负责临时授权,落入方拿到 URI 后按需读取。直接把几十兆的 ArrayBuffer 塞进 UnifiedData 会带来序列化开销和内存压力。另一个硬边界是 rawfile 里的资源:它只在本应用包内有意义,不能直接作为跨设备拖拽的数据源,必须先复制到沙箱、生成可授权的 file:// URI,再走 FileUri 记录。

allowDrop 的类型必须和拖出记录一致

落区的 allowDrop() 声明的类型如果和拖出端的记录类型不匹配,数据根本不会完成协商传递。拖出端发 FileUri,落区只声明了 PLAIN_TEXT,onDrop 拿到空数据是预期行为。排查时把源端 record types 和目标端 dataTypes 一起打出来,能快速区分“根本没传过来”和“传过来了但类型对不上”。

跨设备拖拽的边界可以收成一句话:标准类型走 UDMF,业务字段序列化进 PlainText,文件走沙箱 FileUri,rawfile 先落沙箱,落区类型和拖出类型严格对齐。自定义对象在本机拖拽里活得很好,一跨设备就哑火,不是链路坏了,是你塞的东西对端不认识。

Logo

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

更多推荐