当前位置: 首页 > article >正文

iOS开发 实习产出(给我自己看的 笔记而已)

app总览这个 app 是一个通过多设备协同进行 AR 数据采集 / 录制 / 上传的 iOS 应用主界面由 4 个一级 Tab 组成背后由一组领域模块支撑。一、主界面 4 个板块一级 Tabenum Tab {case prepare, record, upload, profile}Tab入口 View作用主要目录preparePrepareV2录制前准备配对蓝牙夹爪、选择 UMI 版本、多机同步等src/prepare_v2/recordRecordViewAR 相机录制主界面src/record/,src/record_v2/uploadUploadQueueView录制产物排队上传S3 / coscenesrc/upload/,src/upload_v2/,src/s3/,src/coscene/profileProfileView用户 / 设置src/user/,src/settings_ui/二、顶层 Dependencies各 Tab 共享的核心 Managerfinal class Dependencies: ObservableObject {let cfg: Utils.ObsRwUserConfiglet peers: PeersManagerlet ble: BluetoothEncoderManagerlet up: UploadManagerlet ar: ArManagerV1let inference: InferenceManagercfg用户配置src/config/,src/config_v2/peers多设备同步 / 发现src/peers/,src/nw/ble蓝牙夹爪编码器src/bluetooth/,src/gripper/up上传队列src/upload/,src/upload_v2/arARKit 姿态 / 轨迹src/ar/,src/ar_v2/,src/ar_v3/,src/arkit/inference端侧推理src/inference/三、按业务领域划分的支撑模块大致可以分成几层AR 传感ar/,ar_v2/,ar_v3/,arkit/,calib/标定,math/,opencv/外设 / 硬件bluetooth/,gripper/UMI2/UMI3 夹爪,usb/,device/,robot/多机协同peers/,nw/网络层,pubsub/,stream/录制流水线record/,record_v2/,camera_ui/,image/,img/,quality/,task/上传 / 云端upload/,upload_v2/,s3/,coscene/,totp/推理与实验inference/,expr/,stress_test/,nedf2/配置 用户config/,config_v2/,user/,settings_ui/UI / 基础设施ui/,ui_kit/,swift_ui/,foundation/,utils/,log/,thread/,py_like/,tools/四、一眼速览业务主线一条完整的使用链路基本就是 4 个 Tab 串起来的prepare连夹爪 选 UMI3 前缀 多机同步→recordAR 轨迹 拍摄 夹爪编码→upload本地队列上传到 S3/coscene→profile账号 / 设置。从录制到落盘的流程下面从按下开始到成为本地一条可上传的记录为止完整讲一遍录制数据在 app 内的落盘流程。为了看得清我按谁触发 → 在哪里 → 产生什么分阶段走。一、按下开始生成本次录制的身份证入口在录制页面的按钮它并不直接开始写文件而是做一串前置校验再把开始命令既广播给自己、也广播给同组的其他设备必须所有设备都处于空闲且健康状态。多机同步时只允许右腕那台触发。如果是 UMI3 的腕部机位必须先在首页填过合法的硬件版本前缀300-310且与当前相机位置一致否则弹窗拦下。校验通过后主机做两件事作为本次协同录制的身份锚:生成一个全局唯一的协同标识本次录制所有设备共用一个保证多机产物能合并成同一条记录。生成一个以当前时间命名的输出目录名三台机都用同一个名字。然后把开始这一条命令带上目录名、协同标识、起始 UNIX 时间一起广播出去。二、各端启动在文件系统里开出这一录制坑位每台设备的录制总控收到开始命令后在专门的帧队列里执行:在Documents/时间戳/下创建本次录制的独立目录。给视频写入器指定recording.mp4作为输出路径并按当前屏幕方向设置画面 transform、按夹爪代际选不同比特率老一代 10 Mbps新一代 2.5 Mbps。给深度图写入器指定同一目录。把本次录制的先验元数据组装成一个起始快照放进内存中的录制会话包含协同标识、用户指纹、多机模式、任务标签与描述、起始时间、起始方向、相机帧率、相对于主机的初始位姿等。状态切到录制中并广播模式变更事件。注意真正的帧数据还没有落盘只是打开了文件句柄和建立了内存容器。三、录制中边跑 AR 边把三路数据往外写ARKit 每出一帧都会走到录制中的分支。每一帧做三件事帧级问题检测是否离物体太远、跟踪是否失稳、蓝牙夹爪是否掉线、镜头是否装对……这些问题以第 N 帧出现了哪些问题的形式暂存在内存里。把标量数据追加到内存每帧追加一条记录 时间戳 ARKit 位姿 夹爪宽度 夹爪角度 其它辅助量。还会把第一帧单独保留用于最后生成元数据时填分辨率、深度图尺寸等。把像素/深度数据真正写入文件视频写入器把当前画面缩放后写进recording.mp4。深度图写入器把场景深度追加进depth_images.tar如果某一帧 ARKit 没给深度图会复用上一帧避免张数对不齐。所以录制期间磁盘上持续在增长的是 mp4 和深度图包其它每帧标量还在内存里累积等结束时再一次性写入。四、按下结束先停写、再定稿结束按钮也走同样的广播路径。录制总控收到结束命令后状态切到结束中广播模式变更。调用视频写入器和深度图写入器的 finish 等待完成确保 mp4/深度包都完整落盘。交给产物定稿器进行最后的收尾。五、定稿把一次录制变成一个可归档的目录这是整个流程最关键的一步都发生在产物定稿器里5.1 跑一遍离线质量检查在所有帧都录完后对采到的数据再跑一次状态机质检把这些事后才能发现的问题合并到之前的帧级问题里得到最终的问题字典。5.2 帧数一致性校验这一步会比较三者内存里记录的帧计数 ↔ 每帧标量时间戳的条数 ↔ 实际写进 mp4 的帧数 ↔ 深度图的帧数。如果帧计数和时间戳条数对不上直接判为严重存储异常广播一个存储异常事件本次录制作废。视频/深度图允许一定偏移随时长变化的容忍值。超过就判异常作废。如果三者都对得上才继续往下。5.3 把内存里的帧数据序列化到磁盘把前面累积的时间戳 / 位姿 / 夹爪宽度 / 夹爪角度 / 每帧问题 / 附加字段用 BSON 编码成frame_data.bson写进录制目录。5.4 腕部机位额外复制 3 张 ROI 掩膜如果这台是左腕或右腕会把夹爪宽度检测用到的 3 张 ROI 掩膜图roi_mask_0/1/2.png从Documents/gripper/拷贝到录制目录里用于事后离线重现夹爪宽度的计算。5.5 生成校验和 元数据 JSON对三个必需文件recording.mp4、frame_data.bson、depth_images.tar各算一个 sha256。生成metadata.json里面大致有代码版本、本机录制的唯一 id、协同标识、设备代际、用户 id、用户指纹、多机模式、相机位置头/左腕/右腕、硬件版本号、任务标签/描述/执行 id、起始时间ISO8601 UNIX、时长、帧数、帧率、视频宽高、深度图宽高/量程/位深/帧数、设备机型/系统版本/设备 id、起始方向、本机相对于主机的初始位姿、帧级问题、三个文件的 sha256 列表。到这一步磁盘上该目录的形态就稳定了长这样Documents/20260429_121855_xxxx/recording.mp4frame_data.bsondepth_images.tarmetadata.jsonroi_mask_0.png # 仅腕机位roi_mask_1.pngroi_mask_2.png六、进入上传队列成为 app 里的一条记录定稿器最后一步会把这个目录交给上传管理器。上传管理器做的事再做一次保护目录不能是空的且必要文件齐全否则拒收这时候直接失败返回。以本机录制 id 作为主键抽取元数据里的关键字段文件夹名、起始时间、任务标签、任务执行 id、用户指纹、相机位置、帧数、时长、本次的问题、总字节数组装成一条队列条目初始上传状态为待上传。在主线程做原子 append如果队列还在从磁盘加载中就挂到加载完成后再执行的延迟队列里避免先 append 又被覆盖。如果已有同名目录就拒绝重复入队。否则追加到内存队列并立刻把整个队列序列化回磁盘让 app 被杀掉后也不会丢记录。定稿成功后广播一个录制已保存事件携带目录、时间、元数据。底部 Tab 栏的上传角标数、上传页面的列表等都是订阅到这个事件之后刷新的。七、异常路径什么情况下这条记录会消失结束过程中任一步失败比如第一帧始终没到、元数据生成失败、sha256 失败、一致性校验失败、写frame_data.bson失败、写metadata.json失败、入队失败finish 里的 defer 会把整个录制目录从磁盘上删掉并广播结束失败事件状态回到空闲。用户主动取消同样是在空闲化之前把正在写的视频 / 深度图取消并把目录整个删掉。帧数严重不一致在发布存储异常事件后本次记录不会被加进上传队列也会随失败路径被删除。八、一张数据去向总结来源落点时机每帧画面缩放后recording.mp4录制中逐帧写每帧场景深度depth_images.tar录制中逐帧写缺帧时补上一张每帧时间戳 / ARKit 位姿 / 夹爪宽度 / 夹爪角度 / 每帧问题frame_data.bson结束时一次性写前置信息协同标识、任务、起始时间、起始方向 首帧分辨率 事后统计时长、总帧数、sha256 设备信息 相机位置 硬件版本metadata.json结束时一次性写夹爪 ROI 掩膜仅腕机位roi_mask_0/1/2.png结束时从Documents/gripper/复制目录元信息状态待上传、问题摘要、字节数等磁盘上的上传队列序列化入队成功后立即持久化一句话概括录制期间 mp4 和深度图是边拍边写其余结构化数据全部攒在内存里结束时由产物定稿器做一致性校验、一次性把内存数据写成 BSON JSON 校验和最后挂进持久化的上传队列。入队的那一瞬间它才算是 app 里一条可被看到、可被上传的录制记录。由app上传到平台的流程一、上传被触发的几种方式录制结束入队后app 不会自动上传。真正发起上传的入口只有以下几种用户主动触发在上传Tab 选中若干条记录点上传按钮也可以上传所有待上传。协同录制时被广播带起来协同录制中主机一旦在云端建好/复用了这条录制记录会通过同组广播把哪个录制对应哪个记录名告诉所有从机从机收到广播后如果自己队列里有同名待上传条目会自动开跑避免每台从机各自再去云端建一条同名的空记录。app 启动时的孤儿自愈上次 app 在上传中途被系统杀掉磁盘上残留一些标记为上传中的条目启动后会被一律重置回待上传等用户再次手动上传。失败重试失败的条目会被保留在队列里用户也可以选中、点重置为待上传再点上传。二、调度把选中的几条变成一个串行任务入口接收到一组要上传的文件后做这几件事队列还在从磁盘加载时直接挂起。app 启动后队列是异步加载的加载没完前主动避让调用被排到一个加载完后再执行的延迟队列里。去重入队把每条记录用文件夹名做去重只追加未在队列里的。判断是否已经有上传循环在跑如果已经在跑只把待跑总数加上去复用现有任务否则起一个新的后台异步任务开始 while 循环。后台循环每次做一件事从队列取下一条 → 把它的状态置为上传中 → 跑这条文件的上传 → 拿到结果成功 / 失败 / 取消→ 更新这条状态 → 累积成功/失败计数和已传字节数 → 把进度推给 UI → 进入下一条。整个 app 同一时间只跑一条串行但 UI 会持续看到全局进度已完成几条/共几条、已传字节/总字节、当前文件名、当前文件已传/总大小。为了避免高带宽下 URLSession 一秒上百次回调把主线程刷爆进度回调是在后台先累加 / 校正再每一帧派一次到主线程更新同一帧里所有进度字段一致更新。三、单条上传先做通用准备不管最终上传到哪个云每条记录都先在本地经过同一套准备3.1 路径与元数据校验找到Documents/时间戳/这个录制目录确认它真的存在、确实是目录。必须有metadata.json并且能正常解码成元数据对象解码失败直接报错带可读路径信息。3.2 选打包工作目录按当前选择的上传目标决定.tar.gz放哪儿DM3 平台放在Documents/dm3UploadResume/目录键/这种持久化 staging 子目录里。这样即使 app 重启 / 进程被杀下次进来还能续传。其他三种目标放在系统临时目录里跑完即扔。目录键是把 (录制目录名, 协同标识, 相机位置) 三段做百分号编码、用下划线拼起来这样下次 app 启动后能反向解析出来方便垃圾回收。3.3 打包成.tar.gz先用 tar 打成单文件.tar。然后做 gzip这里用了流式压缩每次只在内存里持有 1 MB 数据。如果用最直观的先把整个 tar 读进内存再压几 GB 录制立刻把 jetsam 触发然后被系统杀掉。具体做法是自己手写 RFC1952 的 gzip 头/尾10 字节 header 8 字节 CRC32 输入字节数中间走 Apple 系统库的 raw deflate边读边写边算 CRC。DM3 续传场景下如果 staging 子目录里上次的.tar.gz还在且非空直接复用不重新打可以省一次几十秒到几分钟的压缩。3.4 失败/取消时的清理约定整个uploadFile用一个 defer 兜底非 DM3 目标.tar和.tar.gz都在临时目录无脑全删。DM3 目标中间的.tar总是删.tar.gz留在 staging 给下次续传用只有当用户主动取消时才把 staging 整个清掉因为续传也没意义了。DM3 走到网络/服务端错误时故意不清理 staging下次进来 SDK 会用里面的 checkpoint 自动续传。SDK 软件开发工具包一句话别人把现成的功能封装好打包给你你直接调用不用自己从零写底层代码。里面一般包含代码库、接口 示例 demo 文档、配置文件四、四种上传目标分别怎么把 .tar.gz 推走4.1 上传到刻行默认路径这是 app 主要的上传目标流程最长算 sha256服务端要校验完整性。解析业务记录名刻行平台上一次录制等于一条记录三机协同时三段视频要挂在同一条记录下。优先级调度层透传过来的一般是从机收到广播带的本机内存缓存之前收到过广播自己是主机调建立或复用记录接口建好后立即广播给所有从机自己是从机但有同步对端等主机广播最多 15 秒超时降级自建保住可用性。拼好标签和自定义字段任务标签做成一个 label采集人 用户指纹、任务描述 录制时填的描述如果这次录制中检测到距离过远 / 夹爪量程过小 / 夹爪宽度缺失 / 跟踪特征不足这种轻问题给打黄色 SLAM 异常标其他严重问题打红色 SLAM 异常标。拿一次性预签名 URL调生成上传 URL接口传文件名、大小、sha256得到一个有限期的 PUT 直传地址。直传 .tar.gz用 URLSession 做 PUT带 progress delegate 实时回报已传/总数同时起一个每 5 秒打一行心跳日志的并行任务方便排查卡住了到底卡在哪PUT 完成时心跳自动取消。业务登记上传完文件还不算结束。必须再调同步文件信息接口把 (任务执行 id、文件名、大小、时长) 登记到业务侧。这一步要求登录态有效且不是访客如果没登录或是访客文件其实已经在桶里了但本地状态会标失败提示用户已上传未登记。只有走完这一整串含登记成功这条记录才会被标为已完成。4.2 上传到 DM3直接打到阿里云 OSS走的是阿里云 SDK 的分片可断点续传模式封装比较厚但行为很清晰拉 STS 凭证先用登录态 token 找后端要一次性的 endpoint / bucket / region / 路径前缀 (ak / sk / securityToken / 过期时间)。这一步如果失败直接报错不会进上传。构造 SDK 凭证 provider把如何拉 STS安全令牌服务这个动作包成一个同步闭包给 SDKSDK 在内部判断 token 在 5 分钟内将过期时会自动回调它再拉一次新的外面不需要自己起定时器。构造 SDK 客户端每个上传任务一个不全局复用不同账号/region 会切换 endpoint复用反而麻烦构造代价本身很轻。配三个超时/重试单请求 30 秒、整任务最长 24 小时、SDK 自动重试 3 次。endpoint 没带 scheme 时这里兜底加https://苹果 ATS 强制要求。拼云端路径dir/录制目录名_协同标识/相机位置 basename.tar.gz。其中 basename 是head/left/right中的一个相机位置不是这三个就直接透传空就用unknown。三机的协同标识是同一个所以三段录制最终落在同一个云端二级目录下。配置分片任务分片大小 5 MBOSS 限制 100 KB ~ 10000 片checkpoint 目录就是本地 staging 子目录CRC 校验开并把取消时不要删 checkpoint打开取消时由我们自己清避免和续传语义打架。跑上传把阿里云 SDK 那一套 OC 风格的 future 桥成 Swift 的 async进度回调照样转给上层。结果分支成功 → 主动清掉 staging连.tar.gz和 checkpoint 一起用户取消 → 主动清 staging网络/服务端错误 → 故意不清 staging下次进来 SDK 会自动 ListParts 跳过已完成分片继续传服务端孤儿分片不靠客户端 abort 接口而是依赖云端桶上配置的分片清理生命周期策略建议 7 天兜底。冷启动垃圾回收app 每次冷启动会扫一遍持久化的 staging 根目录下面这三种情况之一就把整个子目录删掉目录名解析不出来手撸残留 / 老版本结构(录制目录名, 相机位置) 已经不在当前活跃队列里了7 天没改过文件明显是孤儿。 不会动正在跑的或仍在队列里的。4.3 上传到 S3 / 兼容 S3 协议最简单先校验 S3 连接配置access key、secret、桶、endpoint、region、路径前缀。拼 object key 前缀/文件名.tar.gz。走 SigV4 签名做一次PutObject单次 PUT 把整个.tar.gz推上去进度回调照样转给上层。4.4 上传到自建通用服务走通用的 multipart POST 到用户配置的 URL由一个什么都干一点的客户端封装负责。这条路径主要用于自部署调试。五、状态与进度的写回每条记录贯穿整个上传都在动两组东西5.1 队列里的这一条的状态队列条目的关键字段本机录制 id、文件夹名、入队时间、起始时间、任务标签、任务执行 id、用户指纹、相机位置、帧数、时长、本次的问题字典、问题文字摘要、上传状态待上传 / 上传中 / 已完成 / 失败、上次尝试时间、失败原因、失败分类、字节数。主要写点开始跑这一条 → 状态 上传中成功 → 状态 已完成这条以后不会再被自动重跑失败 → 状态 失败并写入失败原因 / 失败分类详见下一节用户在循环跑到它之前点取消 → 状态从上传中回到待上传并把它从内存队列踢出。每次状态变更都会立刻把整张队列序列化回磁盘的uploadQueue.json同时维护一份.bak这样 app 任何时候被杀掉都不会丢记录。5.2 全局进度UI 看到的几个数字总文件数 / 已完成 / 失败数 / 总字节 / 已传字节 / 当前文件名 / 当前文件已传 / 当前文件总大小。这一组是节流后批量推到主线程的避免 URLSession 高频回调把主线程刷爆。5.3 失败分类失败时不会把原始错误直接展示给用户而是过一遍错误分类器归到几大类网络断开 / 鉴权失败 / 磁盘满 / 服务端 5xx / 业务登记失败 / 其它。这样 UI 上能给用户一个能理解的提示并且后续可以按鉴权失败这种类做统一的退避策略。六、取消、续传与孤儿处理6.1 用户点取消后台循环里会立刻看到取消标记 当前文件那把 async 抛出取消错误当前正在跑这条 → 状态从上传中回到待上传从内存队列踢出循环 break后续未跑的条目 → 整个内存队列被清空但磁盘上的状态仍是待上传DM3 目标的 staging 子目录会被主动清掉续传无意义其他目标的临时.tar.gz由 defer 兜底删掉。6.2 失败保留 重试刻行 / S3 / 通用临时.tar.gz已经被删重试会从头打包再传SDK 的 3 次重试 用户重试都打不进可断点续传语义。DM3staging 子目录里.tar.gz和 SDK checkpoint 都还在用户重试或下次 app 启动自动重试时会复用.tar.gz不重压再让 SDK 自动 ListParts跳过已上传分片继续传。这是为什么.tar.gz会有已存在则复用的判断。6.3 孤儿/碎片清理上传队列那一头app 启动时会重置上传中为待上传避免转圈死锁。DM3 staging 那一头每次冷启动跑一遍前面说的 GC解析失败 / 不在活跃队列 / 7 天未动。云端 OSS 那一头客户端不调 AbortMultipartUpload怕对桶策略形成强依赖孤儿分片由桶级生命周期策略兜底自动清理。七、一张总表整个上传链路的数据流向阶段输入关键动作输出触发用户点按钮 / 主机广播 / 启动重试入队去重 启或复用循环内存上传队列准备录制目录 metadata.json校验 选 staging or 临时目录工作目录打包录制目录tar → 1 MB chunk 流式 gzip CRC32 字节数.tar.gzDM3 持久化 / 其它临时走刻行.tar.gz 元数据算 sha256 → 解析记录名含主机广播→ 拿预签名 URL → PUT → 业务登记云端记录 业务侧已登记走 DM3.tar.gz 元数据 协同标识拉 STS → 构造 SDK 凭证/客户端 → 5 MB 分片 ResumableUpload checkpoint → 成功/失败差异化清理云端桶 同协同标识三段同前缀走 S3.tar.gz S3 配置校验 → SigV4 PutObject 单次 PUT云端桶里一个对象走通用.tar.gz 通用 URLmultipart POST自建服务接收完成状态上传过程中的事件节流推 UI 写uploadQueue.json含.bak 失败分类用户看到的状态 持久化队列取消用户点取消抛 cancel 状态回滚 清 stagingDM3/ 临时其它队列清空磁盘条目仍可重新发起八、几个容易忽略的设计点单条串行app 同一时间只跑一条文件避免几个 GB 的 .tar.gz 并发压垮内存和带宽也方便进度展示。流式 gzip 是命脉录制几分钟就能上 GB整文件读进内存做 gzip 一定 OOM内存耗尽流式 1 MB chunk 是必须的。DM3 续传强依赖持久化目录staging 是.tar.gz SDK checkpoint共生命周期目录它两个必须放在一起单独丢任何一个续传都坏。协同录制的记录名协调靠主机一次广播就把三机的挂哪条记录绑死避免每台从机各自建一条同名孤儿记录是这条上传链路里最微妙的一段一致性逻辑。业务登记是刻行链路的真终点文件就算 PUT 成功没登记成功这条记录就算失败这是为了让业务侧能查得到、能分配训练任务。DM3 直传不依赖客户端 abort服务端孤儿分片靠桶级策略兜底清理让客户端 IAM 只需要上传/列分片权限不需要中止分片部署侧成本更低。用户在上传Tab 选中条目并点上传后后台会起一个串行任务循环跑选中的每条录制目录单条流程是先校验目录与元数据 → 把整个录制目录用 tar 打包再做 1 MB 流式 gzip 压成.tar.gz避免大文件 OOM→ 按目标分发上传成功后写状态、推进度、持久化队列失败按类别记错可重试。两个目标的差异主要在第三步——走刻行CoScene临时目录里产出的.tar.gz算 sha256 后先解析这次录制对应的业务记录主机直接调建/复用接口并广播给从机从机优先用主机广播带的或缓存里的最多等主机 15 秒否则降级自建拿到记录后调云端要一个一次性预签名 PUT URL用 URLSession 直传.tar.gz并实时回报进度传完还要再调一次同步文件信息接口做业务登记任务执行 id、文件名、大小、时长登记成功才算这条完成临时.tar.gz全程跑完即扔。走 DM3阿里云 OSS.tar.gz落在Documents/dm3UploadResume/目录键/这种持久化 staging 子目录里已存在则直接复用不重压先用登录态拉一次 STS 拿到 endpoint/桶/路径前缀和临时 ak/sk/securityToken再把 STS 刷新逻辑包成阿里云 SDK 的凭证 provider过期前 5 分钟自动回调刷新每个任务起独立 SDK 客户端配 30 s 单请求 / 24 h 整任务超时和 3 次重试最后用 SDK 的可断点续传上传5 MB 一片checkpoint 写在同一 staging 目录云端路径是dir/录制目录名_协同标识/head|left|right.tar.gz三机协同时同一协同标识落在同一二级目录下成功 → 清 staging用户取消 → 清 staging网络/服务端错误 → 故意保留 staging 让下次进来跳过已传分片续传服务端孤儿分片由桶生命周期策略兜底每次冷启动还会扫一遍 staging 删除解析失败/不在活跃队列/7 天未动的孤儿。细拆刻行跟dm3上传逻辑一、两条路径在做的事其实是一样的不管走哪条本质都是把那个.tar.gz推到一个云端对象存储里。区别只在于凭什么权限去推和推的姿势。走刻行app 自己没有云端的钥匙它先找刻行后端要一把一次性临时门票带签名的 PUT URL再用普通 HTTP 一口气传上去。走 DM3app 找 DM3 后端要一把短期工牌STS 临时密钥带过期时间凭这把工牌直接以客户身份到阿里云对象存储那边按云厂商原生的分片续传协议传。一句话刻行那边是门票一次性 PUTDM3 是工牌原生协议分片。所以 DM3 比较啰嗦但能力上确实强不少。二、刻行那条路径的脆弱点把刻行的姿势再拆一下几个隐性约束就出来了那个签名 PUT URL 是一次性且有时效的必须一口气 PUT 完整个.tar.gz中途断了URL 可能就过期了下次得重新去要一次。它走的是 HTTP PUT 的整文件上传语义没有断点传到 80% 网断了下次只能从 0% 开始。一次性 PUT 由 URLSession 自己管你没法精确地告诉它这一段已经传过了不要重来。所有上传都得走刻行后端发 URL 这一跳刻行后端挂了传不了要换别的 region 也得它配合。对几十 MB 的录制重传一次大不了等几秒钟无所谓但 app 的录制经常是几百 MB 到几 GBPUT 到 90% 网络抖一下就全废这事在差网络下非常痛。三、DM3 是怎么把这些痛点逐一破掉的理解 DM3 那套设计的钥匙就是把凭证和上传解耦把上传过程变成可中断、可恢复的状态机。它一共做了 4 件互相咬合的事1. 用 STS 把长期账号换成短期工牌安全令牌服务核心就是发临时权限凭证DM3 后端不会把云厂商的长期 ak/sk 给客户端那等于把保险柜钥匙给陌生人。它每次只发一对临时凭证access key、secret、安全 token、过期时间再加上你这次能往哪个桶 / 哪个目录写。好处即使临时凭证泄露几小时就过期了破坏面很小。客户端拿这把工牌直连云厂商不再每分钟都去 ping DM3 后端发 URLDM3 后端只负责发凭证这一下瞬时压力低可用性更好。桶、地域是 STS 现说现给的后端要换 region、换桶、按账号路由都不用改 app。2. 凭证用的时候才刷——不是定时器是回调如果你写过定时器刷 token 的代码会知道一堆边界 caseapp 退后台定时器停了、刷新和上传请求打架、刷新失败要不要重试、临界点 ms 误差……这里改成把如何从 DM3 后端拉一次新凭证包成一个回调交给云 SDKSDK 内部判断当前凭证还剩 5 分钟内会过期吗是就当场同步回调一次这个闭包拉新的不是就直接复用旧的。app 这边一行定时器都没有不会有刷过头刷漏刷打架。底层有个细节SDK 要的是同步返回但拉凭证是异步网络请求为此那段代码用Task.detached信号量把异步硬转同步——这事看起来很怪但被严格限定在只在 SDK 后台线程的回调里调所以不会卡主线程。3. 真正的杀招原生分片 断点续传这一步是 DM3 比刻行强出最多的地方。分片把.tar.gz切成 5 MB 一块每块独立上传一次。一块失败只重传这一块不影响别的。断点续传上传任务在云端有个 uploadId一边传云端就一边记哪些块已经收到了。客户端这边对应也有一份本地 checkpoint 文件记着 uploadId、分片大小、已完成块号。把这两条合起来就有了非常关键的能力这次传到 60% 时进程被杀掉。下次启动 appSDK 看到本地 checkpoint会先去云端 ListParts 问一句我上次报的这个 uploadId你那边收到哪些块了然后只补传剩下那 40%并把所有块合并成最终对象。这就是为什么 DM3 路径里还需要一个持久化的 staging 目录——不像刻行那样把.tar.gz扔临时目录里跑完就丢DM3 要把.tar.gz和 SDK 的 checkpoint 绑在一起存到Documents下进程被杀、用户重启 app、网卡换 Wi-Fi 再回 4G 都能接着传。刻行那一条是传到 90% 断了从 0 重来DM3 是传到 90% 断了从 90 接着来。在几 GB 文件 弱网场景下这就是能上得去和永远上不上去的差别。4. 失败、取消、重启的三种状态机非常清晰DM3 这套之所以看起来深奥是因为它把三种异常做了截然不同的处理不像刻行只能一刀切重传情况本地 staging云端那个未完成的分片任务用户主动取消主动整个删掉续传也没意义了不调中止接口让云端按生命周期策略自动清网络/服务端错误故意保留保留下次进来 ListParts 续传上传成功删掉含 .tar.gz checkpoint自动转正孤儿分片自动消失app 冷启动后扫一遍三种条件之一就清目录名解析失败 / 不在活跃队列 / 7 天没动同上由桶生命周期兜底staging iPhone 上Documents/dm3UploadResume/下的一个本地暂存目录每条 DM3 上传任务一个里面同时放打好的.tar.gz和阿里云 SDK 的续传 checkpoint作用就是让上传可以跨进程被杀、跨重启、跨网络中断地从中间接着传。这里有几个故意为之的设计判断特别值得说取消时不调中止上传接口而是让云端的桶生命周期策略建议 7 天来兜底清理孤儿分片。原因是调这个接口需要给客户端一个额外的 IAM 权限部署时多一个坑不调它权限可以收得更紧放在那儿过几天自己烂掉反而更稳。错误时不删 checkpoint直觉上失败应该清场但这里反过来——失败保留重试才能续传。清干净的语义只在用户取消和传成功两个场景下才执行。冷启动 GC 是兜底万一某条上传被人为从队列里删除了 / 永远没机会重试 / 网络真的卡了一周那个 staging 目录会被自动回收不会无限占磁盘。四、形象一点的类比刻行那条你委托一个中间人去寄快递。每次寄你都要先打电话给中间人要一张今天寄到上海仓的提货单一次性、有时效然后你必须一口气把整个箱子送到。送一半箱子掉路上那张提货单作废你下次得重新打电话要一张整个箱子从头送。DM3 那条DM3 给你发了一张今天有效的临门工牌让你直接进阿里云仓库。你可以把箱子拆成 5 MB 一份的小盒子一个一个交仓库会逐个登记到你的任务单 uploadId下。送一半你走了没事明天回来打开你家里的小本子本地 checkpoint看上次送到第几个盒子再问仓库前台核对一下没送的接着送全部送完仓库自动把它们拼成一个完整的箱子这期间工牌过期了你的 SDK 助理会自动回去 DM3 前台再换一张新工牌你都感知不到。五、一句话回答强在哪DM3 比刻行那条路径强出来的能力本质就这五条断点续传不再全有或全无弱网/被杀/取消重启都能从中间接着传。凭证短期化长期密钥不下发泄露代价低。凭证自动刷新无感知不依赖任何定时器。不依赖一次性签名 URL不会出现签名过期了得回头再要一张的连锁失败。后端只在发凭证时被路过一次链路短DM3 后端故障不直接拖死上传。代价就是它必须额外维护持久化 staging 目录 冷启动 GC STS 同步桥接这三块工程量看起来比刻行那条复杂但只要文件足够大、网络足够烂这套复杂度立刻就会变成传得上去 vs 传不上去的硬差别。

相关文章:

iOS开发 实习产出(给我自己看的 笔记而已)

app总览这个 app 是一个通过多设备协同进行 AR 数据采集 / 录制 / 上传的 iOS 应用,主界面由 4 个一级 Tab 组成,背后由一组领域模块支撑。一、主界面 4 个板块(一级 Tab)enum Tab {case prepare, record, upload, profile}Tab入口…...

CloudCompare 2025保姆级避坑指南:10个新手最常踩的雷区与高效解决路径

CloudCompare 2025保姆级避坑指南:10个新手最常踩的雷区与高效解决路径 第一次打开CloudCompare时,面对密密麻麻的工具栏和复杂的点云数据,很多新手会感到手足无措。作为一款功能强大的开源点云处理软件,CloudCompare在三维建模、…...

别再只会用@PreAuthorize了!手把手教你用SpringBoot AOP+自定义注解+SpEL打造更灵活的权限控制

超越PreAuthorize:用SpringBoot AOPSpEL构建动态权限控制体系 在后台管理系统开发中,权限控制是保障业务安全的核心环节。虽然Spring Security提供的PreAuthorize注解能够满足基础需求,但面对"仅工作日可访问"、"只能操作自己…...

TVA在显示面板制造与检测中的实践与挑战(4)

重磅预告:本专栏将独家连载新书《AI视觉技术:从入门到进阶》精华内容。本书是《AI视觉技术:从进阶到专家》的权威前导篇,特邀美国 TypeOne 公司首席科学家、斯坦福大学博士 Bohan 担任技术顾问。Bohan师从美国三院院士、“AI教母”…...

年薪百万不是梦!AI大模型十大高薪岗位全解析!AI大模型时代

在人工智能大模型的推动下,职场格局正在发生翻天覆地的变化。AI大模型不仅在技术领域引发革命,也为相关岗位的从业者带来了前所未有的薪资待遇。以下是AI大模型领域的热门岗位薪资盘点,带你详细了解这些高薪职位的职责要求和发展前景。1. AI系…...

告别盲调!手把手教你用ETAS ISOLAR配置AUTOSAR XCP模块(附A2L文件生成避坑指南)

告别盲调!手把手教你用ETAS ISOLAR配置AUTOSAR XCP模块(附A2L文件生成避坑指南) 在汽车电子控制单元(ECU)开发中,XCP协议作为测量与标定的黄金标准,其重要性不言而喻。但对于许多刚接触ETAS ISO…...

大模型算法工程师:AI黄金赛道!高薪+风口+大厂争抢,速来围观!

大模型算法工程师,是具备扎实算法基础,深度理解Transformer、预训练与微调等大模型核心技术,负责模型训练、优化、部署与迭代的技术核心岗位。当下大模型赛道持续爆发,企业对能落地的算法人才需求井喷,大模型算法工程师…...

ARM MMU-401调试寄存器与TLB访问机制详解

1. ARM MMU-401调试寄存器架构解析在ARM处理器架构中,内存管理单元(MMU)负责虚拟地址到物理地址的转换工作。MMU-401作为ARM CoreLink系列的重要组件,其调试寄存器设计提供了独特的TLB(Translation Lookaside Buffer)访问机制,这对系统开发人…...

YimMenu:GTA5最强防护与增强工具完整指南

YimMenu:GTA5最强防护与增强工具完整指南 【免费下载链接】YimMenu YimMenu, a GTA V menu protecting against a wide ranges of the public crashes and improving the overall experience. 项目地址: https://gitcode.com/GitHub_Trending/yi/YimMenu Yim…...

2026最权威的六大AI写作网站解析与推荐

Ai论文网站排名(开题报告、文献综述、降aigc率、降重综合对比) TOP1. 千笔AI TOP2. aipasspaper TOP3. 清北论文 TOP4. 豆包 TOP5. kimi TOP6. deepseek 当下各类AI写作工具不断涌现,然而多数都得付费订阅。本文着重关注真正能够免费使…...

2026届学术党必备的六大AI学术助手推荐

Ai论文网站排名(开题报告、文献综述、降aigc率、降重综合对比) TOP1. 千笔AI TOP2. aipasspaper TOP3. 清北论文 TOP4. 豆包 TOP5. kimi TOP6. deepseek 基于自然语言处理跟深度学习技术的智能创作工具,是AI写作软件。它能依照用户输入…...

2026届毕业生推荐的AI论文方案推荐榜单

Ai论文网站排名(开题报告、文献综述、降aigc率、降重综合对比) TOP1. 千笔AI TOP2. aipasspaper TOP3. 清北论文 TOP4. 豆包 TOP5. kimi TOP6. deepseek 当今学术写作范畴之内,一键生成论文的工具借由结构化模板以及智能填充技术&#…...

Umi-OCR:免费开源的离线文字识别工具终极指南

Umi-OCR:免费开源的离线文字识别工具终极指南 【免费下载链接】Umi-OCR OCR software, free and offline. 开源、免费的离线OCR软件。支持截屏/批量导入图片,PDF文档识别,排除水印/页眉页脚,扫描/生成二维码。内置多国语言库。 …...

【2026最新】Arduino IDE下载安装汉化保姆级教程(附安装包)

简介: Arduino IDE是全球最易用的开源单片机开发环境,专为初学者设计,支持Win/macOS/Linux全平台,免费开源。界面简洁、汉化便捷,配套教程丰富,兼容海量硬件与项目,助电子爱好者、学生和创客快…...

Claude Code 全攻略:命令大全 + 实战工作流(建议收藏)

Claude Code 全攻略:命令大全 实战工作流(建议收藏)1. Claude 常用命令查看版本:claude --version启动交互界面(当前目录):claude指定目录启动:claude /path/to/project升级到最新版…...

微信H5导航踩坑实录:绕过限制调用高德/百度地图,我用这招解决了(附完整代码)

微信H5导航功能深度优化:跨平台地图调用的实战解决方案 在移动互联网时代,H5页面作为轻量级应用载体,经常需要集成地图导航功能。然而,微信浏览器环境下的特殊限制让这一看似简单的需求变得异常复杂。本文将分享一套经过实战检验的…...

ArcGIS Server 切片服务发布实战:从ArcMap预处理到JavaScript加载的完整避坑指南

ArcGIS Server切片服务发布实战:从预处理到前端加载的全链路避坑指南 当遥感影像数据需要从本地TIF文件转变为可被全球访问的Web地图服务时,ArcGIS Server的切片服务发布流程往往成为GIS工程师的必经之路。这个看似标准化的技术路径中,却隐藏…...

抖音无水印下载终极指南:3分钟搞定批量下载,免费获取高清资源

抖音无水印下载终极指南:3分钟搞定批量下载,免费获取高清资源 【免费下载链接】douyin-downloader A practical Douyin downloader for both single-item and profile batch downloads, with progress display, retries, SQLite deduplication, and brow…...

ComfyUI-BiRefNet-ZHO:5分钟掌握AI图像视频抠图终极解决方案

ComfyUI-BiRefNet-ZHO:5分钟掌握AI图像视频抠图终极解决方案 【免费下载链接】ComfyUI-BiRefNet-ZHO Better version for BiRefNet in ComfyUI | Both img & video 项目地址: https://gitcode.com/gh_mirrors/co/ComfyUI-BiRefNet-ZHO 还在为繁琐的背景去…...

偏见检测代码总报错?R 4.3+ + tidymodels + fairness包协同失效真相,92%用户忽略的3个底层统计假设校验步骤

更多请点击: https://intelliparadigm.com 第一章:R 语言在大语言模型偏见检测中的统计方法 报错解决方法 在使用 R 语言对大语言模型(LLM)输出进行偏见量化分析时,常见报错包括 object bias_score not found、non-nu…...

产品经理必看:如何利用GB/T 4754-2017标准,搞定用户画像与市场细分?

产品经理实战指南:用GB/T 4754-2017标准重构用户画像方法论 当你在设计一款SaaS产品的注册表单时,"所属行业"这个下拉框是否总让用户纠结?当团队讨论"目标客群定位"时,各部门对"金融科技客户"的定义…...

PHP支付系统国密改造实录:从OpenSSL到GMSSL的7大断点排查与3小时热切换方案

更多请点击: https://intelliparadigm.com 第一章:PHP支付系统国密改造的背景与合规要求 随着《密码法》正式施行及《金融行业信息系统商用密码应用基本要求》(JR/T 0092—2021)等监管文件落地,面向金融级业务的PHP支…...

如何用3分钟从视频中智能提取PPT:告别手动截图的终极指南

如何用3分钟从视频中智能提取PPT:告别手动截图的终极指南 【免费下载链接】extract-video-ppt extract the ppt in the video 项目地址: https://gitcode.com/gh_mirrors/ex/extract-video-ppt 你是否曾花费数小时从教学视频或会议录像中手动截图保存PPT内容…...

SAP ABAP ALV表格里,如何给自定义字段加上F4搜索帮助?(附完整代码示例)

SAP ABAP ALV表格自定义字段F4搜索帮助实战指南 在SAP ABAP开发中,ALV(ABAP List Viewer)表格是最常用的数据展示控件之一。当我们需要在ALV表格中实现数据录入功能时,F4搜索帮助(输入帮助)能够显著提升用户…...

中国数字资产安全新纪元:Ledger 官方直营时代开启

中国数字资产安全新纪元:Ledger 官方直营时代开启 【核心摘要】 2026 年,中国数字资产安全领域迎来里程碑式变革——法国 Ledger 正式确立大中华区直营服务体系。通过京东(JD.com)及微信生态构建的官方授权链路,彻底解…...

RimSort终极指南:如何轻松管理《环世界》模组,告别加载冲突烦恼

RimSort终极指南:如何轻松管理《环世界》模组,告别加载冲突烦恼 【免费下载链接】RimSort RimSort is an open source mod manager for the video game RimWorld. There is support for Linux, Mac, and Windows, built from the ground up to be a reli…...

别再只用一个ChatGPT了!试试Poe这个AI聊天机器人聚合平台,一次体验ChatGPT、Claude、Sage和Dragonfly

解锁AI协作新维度:Poe平台多模型智能工作流实战指南 当ChatGPT成为日常生产力工具的代名词,许多深度用户开始意识到:不同AI模型其实各有所长。就像专业摄影师不会只用一支镜头完成所有拍摄,真正的效率追求者需要学会调用最适合当前…...

K8S证书管理避坑指南:除了kubeadm certs renew,你还需要知道这些备份和验证技巧

K8S证书管理避坑指南:从备份到验证的全流程安全策略 当Kubernetes集群的证书突然失效时,整个集群可能瞬间陷入瘫痪——API调用失败、kubectl命令无法执行、核心组件间通信中断。这不是危言耸听,而是每个运维工程师都可能面临的真实噩梦。本文…...

【新手攻略】2026年OpenClaw/Hermes Agent京东云6分钟快速安装指南

【新手攻略】2026年OpenClaw/Hermes Agent京东云6分钟快速安装指南。OpenClaw和Hermes Agent是什么?OpenClaw和Hermes Agent怎么部署?如何部署OpenClaw/Hermes Agent?2026年还在为部署OpenClaw和Hermes Agent到处找教程踩坑吗?别再…...

别再死记硬背了!用Flink SQL窗口函数搞定实时订单统计(附Kafka数据源配置)

实时电商订单分析的Flink SQL窗口函数实战指南 电商平台每天产生海量订单数据,如何实时分析这些数据成为技术团队面临的挑战。本文将深入探讨如何利用Flink SQL的窗口函数实现电商订单的实时统计分析,从基础概念到实战应用,帮助开发者快速掌握…...