ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

〖共创稿事节〗HarmonyOS 7 新特性实战(09):碰一碰事件、坐标命中与显式分享接入

〖共创稿事节〗HarmonyOS 7 新特性实战(09):碰一碰事件、坐标命中与显式分享接入 手机里选好一张展品卡在平板展板的某个区域碰一下卡片就落到那里。这个流程包含两种不同结果文件已经传到接收端以及文件被放进用户指定的位置。前者成功而后者错位用户仍会认为这次分享失败。接收端需要同时处理内容、坐标和事务状态。方案以单张展品卡为例使用系统精准分享能力传递资源与实际触碰位置应用负责把系统坐标转换为展板位置并保证同一分享只提交一次。坐标的参考系必须来自接口合同触碰坐标究竟相对屏幕、窗口还是内容区单位是物理像素还是逻辑尺寸需要从真实系统事件定义确认。状态栏、窗口边框、旋转和缩放都可能造成偏差不能看到 x/y 字段就直接传给卡片布局。将变换拆成屏幕到窗口、窗口到画布两步更容易排查。画布还有平移缩放时使用逆变换得到内容坐标。以下只描述应用的几何计算不代表系统一定返回屏幕像素interfacePoint{x:number;y:number;}interfaceCanvasTransform{originX:number;originY:number;scale:number;}functiontoCanvas(p:Point,t:CanvasTransform):Point{if(!Number.isFinite(t.scale)||t.scale0){thrownewError(Invalid canvas scale);}return{x:(p.x-t.originX)/t.scale,y:(p.y-t.originY)/t.scale};}所有输入点和偏移还应检查有限性。系统事件进入平台适配层时就附上参考系标识避免后续页面猜测来源。落点选择与文件传输分开推进接收文件可能比坐标事件晚。接收端可以先显示待接收位置但不要立即把正式卡片写入目录。资源可读、格式检查通过之后再完成落点提交失败则撤销占位并显示原因。应用记录应包括 transferId、资源临时路径、目标展板、内容坐标和状态。若坐标越出画布允许用户重新选点或放入待整理区不要静默把内容丢到某个默认角落。多窗口情况下目标展板也要稳定标识。传输期间用户切换到另一个展板最终卡片仍属于原请求或进入明确的重新确认流程不能依赖“当前活动页面”做提交。用一次提交处理重复回调弱连接和跨设备流程可能发生重试。应用用稳定 transferId 保存提交结果再次收到相同传输时返回已有结果。文件哈希可用于内容校验但不能代替业务传输 ID用户可能合法地把同一张图放进两个不同位置。收到请求 → 等待资源 → 检查格式与大小 → 确定落点 → 提交展板记录 → 记录 transferId → 返回结果资源复制与数据库更新需要设计失败补偿。记录写入失败时清除本次临时复制记录已经成功但回执丢失时保留结果让重试查到它。避免把“没有收到成功提示”当作“应该再插入一张”。临时 URI 的寿命不要穿透到长期收藏跨设备传来的 URI 可能只在授权范围和生命周期内有效。需要长期展示的卡片应在有权读取时复制到自己的资源目录并验证完整性再保存应用自己的引用。图片还需检查尺寸与解码成本不能只限制压缩文件字节数。极高分辨率小文件也可能带来较大解码内存。拒绝时说明是格式、大小还是解码失败不把所有错误都归结为“碰一碰失效”。用网格图验收精度第一版 Demo 在接收端显示编号网格手机发送一张带明显边界的测试图。分别在左上、中央、右下触碰记录系统原始坐标、变换后坐标与最终槽位。窗口移动、画布缩放、横竖屏切换后重复实验。双端录屏应能对应同一 transferId。还要验证取消、断连和重复接收不以单次中间位置成功代表全部坐标都正确。若某类设备不提供精准位置则提供普通接收后手动放置路径并明确区分两种操作。用一个算得出的落点定位偏移错误假设平台适配后得到窗口逻辑坐标 (260,180)画布原点为 (20,40)缩放为 2则内容坐标应为 (120,70)。这是人工构造的数学用例如果实际界面落在 (130,90)说明遗漏了原点扣除不能通过挪动卡片边距修补。收件方式使用条件交互代价精准坐标直接落位来源坐标系已确认资源有效需处理变换和越界接收后手动选位设备不支持位置或坐标无效多一次操作但位置可确认先完成变换与越界测试再加入资源提交及重复回执最后用成对设备核对三个网格点。提交记录和 transferId 应在同一事务中生效仅按流程先后分别写两条记录仍可能在中断时产生重复卡片。参考精准分享官方解读、HarmonyOS 7 能力入口。监听注册、坐标命中与临时分享目标坐标必须和渲染区域使用同一单位。图鉴卡片在布局变化时重新记录全局区域把 ArkUI 的 vp 转为 px负坐标、空区域和重叠区域没有唯一命中。真实触碰只建立候选分享目标用户点击分享按钮后才调用系统分享。触碰回调注册、同一函数解除监听和一次性使用目标对象已接入。离页及切换主题时解除监听页面生命周期编号拦截迟到回调。exportclassKnockProbe{privateactive:booleanfalse;privateregions:HitRect[][];setRegions(regions:HitRect[]):void{this.regionsregions.slice();}privatepending:harmonyShare.SharableTarget|undefinedundefined;privatecallback:(target:harmonyShare.SharableTarget)void(){};start(report:(message:string)void):void{if(this.active){return;}this.callback(target:harmonyShare.SharableTarget):void{if(!this.active){return;}this.pendingtarget;constcoordinate:harmonyShare.CoordinateInfo|undefinedtarget.getInfo().coordinate;consthit:string|undefinedcoordinate?TouchSelection.pick(coordinate.screenX,coordinate.screenY,this.regions):undefined;report(命中区域(hit||无唯一命中请手动选择); (coordinate?真实触碰坐标 px: coordinate.screenX, coordinate.screenY:收到触碰系统未提供坐标));};this.activetrue;try{harmonyShare.on(knockShare,this.callback);}catch(error){this.activefalse;throwerrorasError;}}asyncshareSelected():Promisevoid{consttarget:harmonyShare.SharableTarget|undefinedthis.pending;if(!target){thrownewError(先等待真实触碰事件);}this.pendingundefined;awaittarget.share(newsystemShare.SharedData({utd:general.plain-text,content:玄龟 · 山海图鉴实验,title:玄龟}));}stop():void{if(!this.active){return;}harmonyShare.off(knockShare,this.callback);this.activefalse;this.pendingundefined;}}辅助校验与边界处理使用以下实现exportinterfaceHitRect{id:string;left:number;top:number;width:number;height:number;}exportclassTouchSelection{staticpick(x:number,y:number,regions:HitRect[]):string|undefined{if(!Number.isFinite(x)||!Number.isFinite(y)||x0||y0){returnundefined;}consthits:HitRect[]regions.filter((rect:HitRect){return[rect.left,rect.top,rect.width,rect.height].every((n:number)Number.isFinite(n))rect.width0rect.height0xrect.leftyrect.topxrect.leftrect.widthyrect.toprect.height;});// Ambiguous/overlapping regions require explicit user selection.returnhits.length1?hits[0].id:undefined;}}用坐标和重复回调核对源码真机触碰坐标与布局单位对应、接收设备实际收到文本。检查层当前处理不能替代的结果编译API 26 工程进行类型检查与打包目标设备支持逻辑校验输入、状态或资源释放边界平台服务真实返回联调按上面的输入和条件逐步执行不能以按钮文案代替核心结果API 26 验证边界2026-09-23 已在 API 26 模拟器安装并启动本工程基础实验首页可见进入包含精准分享适配器的设备专项页后进程被系统终止当前日志没有给出可归因的 Kit 缺失栈。随后为本工程配置包名匹配的调试签名签名 HAP 已安装到 HBN-AL80 真机DeviceLabPage可见“监听真实碰一碰”返回“已注册监听等待真实触碰”“解除监听”返回“监听已解除”。这确认了本应用在该真机上的监听注册与释放链路。现有记录没有knockShare的真实回调、系统坐标或跨设备接收文本模拟器不能替代第二台物理碰一碰设备。因此模拟器运行、监听成功和宿主测试都不能作为物理碰一碰传输成功的依据。2026-09-23 补充把同一签名 HAP 部署到 API 26 模拟器和 HBN-AL80两个目标均能启动基础实验首页模拟器打开设备专项页后仍被系统终止因而没有把它写成专项页或系统分享成功。宿主测试直接加载实际KnockProbe与TouchSelection源码以平台 Kit 测试替身验证负坐标、右边界与重叠区域不命中重复start只注册一次stop使用同一回调分享目标仅能消费一次。这构成同包双端部署和应用逻辑联调不构成物理碰一碰传输。完整设备、构建与测试记录见 完整设备、构建与测试记录。后续物理验收仍需具备系统能力的真实受端再记录同一传输的原始坐标、命中区域和接收内容。碰一碰事件、坐标与分享接口的版本约束以 HarmonyOS 官方文档中心和当前 SDK 声明为准。触碰边界与重复监听矩形右边界采用半开区间重叠命中不选择任何条目。测试也检查监听只注册一次、注销使用同一回调以及分享目标只消费一次。宿主测试直接载入 KnockProbe 与 TouchSelection仅以替身代替系统分享 Kitload 与 test 属于测试框架。test(touch: negative, right boundary and overlap are not unique hits,(){consta{id:a,left:10,top:10,width:20,height:20};assert.equal(TouchSelection.pick(10,10,[a]),a);assert.equal(TouchSelection.pick(30,20,[a]),undefined);assert.equal(TouchSelection.pick(-1,10,[a]),undefined);assert.equal(TouchSelection.pick(20,20,[a,{...a,id:b}]),undefined);});test(touch: register once and release exact callback; do not invent events,async(){letcb,on0,off0,shared0;constkit{on(e,c){on;cbc;},off(e,c){assert.equal(c,cb);off;}};constCload(services/KnockProbe,{kit.ShareKit:{harmonyShare:kit,systemShare:{SharedData:class{constructor(record){this.recordrecord;}}}}}).KnockProbe;constxnewC();awaitassert.rejects(x.shareSelected());x.start((){});x.start((){});assert.equal(on,1);cb({getInfo:()({coordinate:{screenX:-1,screenY:-1}}),share:async()shared});awaitx.shareSelected();awaitassert.rejects(x.shareSelected());x.stop();x.stop();assert.equal(off,1);assert.equal(shared,1);});操作或边界应检查的结果输入不满足前提不调用后续平台操作平台拒绝或抛错保留错误不生成成功状态再次进入或重试检查旧状态不会污染新任务
返回列表