Skip to content

Latest commit

 

History

History
61 lines (51 loc) · 26.9 KB

current_task.md

File metadata and controls

61 lines (51 loc) · 26.9 KB

Current Task — IMProgram(iOS)

活快照:只记当前状态,就地覆盖、不追加。逐功能×端状态以 ../IMServer/docs/CLIENT_PARITY.md 为唯一来源; 历史流水见 current_task.archive.md(2026-10-02 瘦身前的全量快照在其顶部)+ git log。关键约定见 CLAUDE.md / ARCHITECTURE.md / CODING_STYLE.md。

当前焦点

  • 清除所有对话(2026-10-29,test.sh 全绿(首跑 IMSocketAckTests 两条并发负载偶发红、重跑绿,属已知坑)+ IMClearAllTests 11 例(7 处变异已看红),未提交,模拟器已实测(入口/二级页/取消/确认/清空/空态/toast/限频失败路径);设计 ../IMServer/docs/design/CLEAR_ALL_CONVERSATIONS_DESIGN.md,草图 sketches/CLEAR_ALL_CONVERSATIONS_UX_SKETCH.html,契约 PROTOCOL §6.8):隐私与安全「数据」组首行转活(图标红 systemRed,不登记设置搜索)→ IMClearAllViewController(无密码框;配置 → UIAlertController 二次确认带 N=进页时 cachedConversations.count → POST → 成功返回隐私页 toast 已清除 N 个对话/没有可清除的对话,N 取服务端 cleared;失败按钮恢复 + 红字、本机不动)。版式抽成共用基类 IMDangerPageViewController(警示头 + 后果卡 + 信息条 + 错误行 + 红按钮),IMDeleteAccountViewController 改继承它(不分叉)。HTTP 成功后 IMClearAll applyResult::后台线程 IMSocketManager+ClearAll applyClearAllItems: → IMDatabase+ClearAll clearConversationsToFloors:(单事务,每项复用库内 IMClearConvToFloorInDB——从 clearMessagesForConv:toServerClearedAt: 抽出,与单条删除会话同一实现;已复活的会话保留行)→ 内存游标/下界缓存/聊天页清空通知(页面保持打开)→ 删 IMDownloads+im_original_videos(不动 im_image_cache,头像在里面)+「看过」登记 → 通知中心清空、角标 0、广播会话更新、Tab 红点清零。conv_update(delete) 回声走原 applyConvDeleteFrame:,幂等。i18n privacy.clear_all.* 14 键入 strings.json(旧 ps.row.clear_all_chats 已删)并 gen-i18n。测试 IMClearAllTests。限制:图片消息缩略图与头像共用 im_image_cache,故图片缓存不清;批量里 cleared_at<=0 的会话只移行不碰消息。
  • 删除会话=清空 + 隐藏(OFFLINE_BACKLOG_DESIGN §6.7.1,2026-10-28,test.sh 1216/1216,未提交,未真机目测):统一「清除到位点」例程 IMSocketManager+ConvClear(clearConvToFloor:serverClearedAt:database::位点=max(既有, cleared_at),无 cleared_at 取本机 head;清消息(≤位点)+区间+推游标+丢 IMBacklogTracker 下界缓存;须先于 deleteCachedConversation:)。三触发点:本机删除成功(deleteConversationWithToken 回调带 clearedAt,列表单删 / +Editing 批量)、conv_update(delete)(applyConvDeleteFrame:)、列表快照 IMConversation.clearedAt > 本机位点(alignClearFloorsFromConversations:,在 replaceCachedConversations: 之前)。DB 侧 IMDatabase+ClearFloor 新增 clearMessagesForConv:toServerClearedAt:。测试 IMConvDeleteClearTests 7 例(4 处变异已看红)。限制:服务端给了 cleared_at 时只清 ≤位点的行(位点之上的本机行保留);快照追平在列表刷新时才触发。
  • 导出我的数据(2026-10-27 已模拟器实测:错密码红字/发起/完成/分享面板·存到文件/杀进程重进冷却均过,test.sh 1203/1203;未提交;设计 ../IMServer/docs/design/DATA_EXPORT_DESIGN.md §1/§2/§5,草图 sketches/DATA_EXPORT_UX_SKETCH.html,契约 PROTOCOL §6.18):隐私与安全「数据」组「导出我的数据」转活行 → IMExportDataViewController(配置 / 进行中 / 完成 / 冷却 / 失败;进页拉 latest,进行中每 2s 轮询、页面消失即停、回前台补拉;密码错内联红字保留输入,200010 toast + 切进度,200011 读 data.retry_after_sec 进冷却态;取消不二次确认)。纯逻辑 Common/IMDataExport(任务解析 / 状态映射 IMExportResolveViewState / IMExportCanStart / 冷却小时上取整 / 下载地址拼接);REST IMHTTPService+Export;下载 IMExportDownloader(downloadTask → NSTemporaryDirectory()/im-export-yyyyMMdd.zip → UIActivityViewController,分享完删临时文件)。IMFriendlyMessageForCode 补 200010/200011。测试 IMDataExportTests 17 例。下载中态(2026-10-28 已模拟器实测 1.2GB:进度条 + 「已下载 a / b」 + 红粗 14pt 提醒、隐「下载」钮、完成弹分享面板;test.sh 1209/1209,未提交):IMExportDownloader 改每次下载独立 session + URLSessionDownloadDelegate,progress: 回调主线程、节流(≥100ms 或 ≥1%,IMExportDownloadShouldEmitProgress)、completion 后不再回调,总长未知(≤0)走不定长滑块;测试 IMExportDownloaderTests(含 setProtocolClassesForTesting: 桩)。限制:不定长态与失败态未在界面实测(仅单测);200011 缺 retry_after_sec 时按 24h 兜底;冷却倒计时只在进页 / 回前台 / 操作时重算,不逐小时自刷新;清除所有对话仍灰置。
  • 自动删除消息 v2(2026-10-21,会话级共享、不追溯,未提交;设计 ../IMServer/docs/design/AUTO_DELETE_DESIGN.md v2 §9,共用向量 conformance/auto_delete.json):单聊双方 / 群全员同时生效,服务端 auto_delete_sec + auto_delete_from 成对下发(列表项 / conv_update / GET·PUT settings)。本地存独立小表 im_conv_auto_delete_local(sec, from_ms)(IMDatabase+AutoDelete;v1 个人档位升级时整表清掉不迁移);纯判定 Common/IMAutoDelete(IMAutoDeleteExpired(ts,sec,from,now)、IMAutoDeleteWindow、IMAutoDeleteConfig,没有 floorTs 了:过期集合 = 窗口 [from, now-sec*1000])。调度 IMAutoDeleteScheduler(0.25s 合并;启动 / 回前台 / 前台 30s);conv_update / 设置页发现 sec 或 from 变且 sec>0 才扫该会话,无「开启即清历史」。入库闸 / 实时 / sync 整页 / 置顶 / 服务端分页同一公式。预览 / 未读重算(recomputeSummaryInDB):最后一条落窗口内才动,预览取最后一条未过期可见消息(越过窗口取 from 之前,如开启通知),未读 = min(扣除后, 本机剩余未读),timestamp 不清零,无变化不重复通知。UI:确认框非 destructive「开启」(新>0 且≠当前才弹;单聊 / 群两套正文与页脚);群非群主 / 管理员:详情页行进只读档位页(onReadOnlyTap),点任意行 toast autodel.group_admin_only、不发 PUT,PUT 回 300204 同 toast 并回滚。系统消息 auto_delete 在 IMSysEventFormatter(按 sys_args.sec 选 on/off、{period} 折算;气泡与会话列表预览同源)。PUT 仅主动改档位那一处带 auto_delete_sec(其余零改动)。测试 IMAutoDeleteTests(v2 向量 + 迁移 + 窗口清理 + 预览越窗 + 只读页 + 300204)、IMSysEventFormatterTests +2。限制:服务端聊天记录搜索结果未按档位过滤;缺 auto_delete_from 的 sec>0(老服务端)一律当关闭;本机无任何未过期消息行时预览会被清空(下次拉列表由服务端值校正);窗口外未下载的未读在重算后可能少计到下次拉列表;未做 v2 模拟器实测、未亲眼看到「到点 30s 内消失」。
  • 非气泡行补日期胶囊(2026-10-21,模拟器实测 + test.sh 1139/1139,未提交):新建群首条是系统消息时 iOS 整天没有日期胶囊(系统/撤回/群通话/图片/相册/链接/名片/记录卡/单聊通话行提前 return、不走 dayHeaderForRow:;Android/Web 本就有)。修:共用 IMDayPillView(高 0 或 32)挂在 IMSystemCell 与 IMMessageCell 基类(分割线改锚胶囊底),cellForRowAtIndexPath: 外包一层统一补 applyDayHeader:(气泡/语音 cell 自带,不走);dayHeaderForRow: 改与上一可见行比(跨午夜相册);估高加 32。IMBubbleCell/IMPinnedDayPillCell 仍各自内置同款(样式改动要同改)。测试 IMDayPillViewTests。图片/链接/名片/相册行为首条的实际显示未造数据目测(基类零高等价 + 单测)。
  • 会话列表编辑模式(2026-10-20,模拟器 iPhone 17 Pro Max 已逐项实测,未提交):左上角「编辑 / 完成」(带标题的 leftBarButtonItem,同聊天多选「取消」)→ 系统多选编辑态勾选圈 + 独立底栏 IMConversationEditBar(玻璃胶囊文字钮,TabBar 隐藏,列表底边接栏顶不重叠);批量已读与单条同路径、批量删除复用聊天多选同款 IMPopoverCard;切 Tab 清空选择;IMBatchRunner(并发 ≤4)。新文件:Common/IMConversationSelection、Common/IMBatchRunner、Modules/Conversation/IMConversationEditBar、IMConversationListViewController+Editing.m;IMConversationSelectionTests(读共用向量)。设计 IMServer/docs/design/CONV_LIST_EDIT_MODE_DESIGN.md + sketches/CONV_LIST_EDIT_MODE_UX_SKETCH.html;共用向量 IMServer/docs/conformance/conv_selection.json;新增 i18n 键 conv.edit.*(7 个,已重新生成三端)。
  • 注销账号·通话入口与免密提示(2026-10-20,已提交):已注销对端不可呼叫——单聊入口拦截(toast rtc.call.peer_deleted)、群通话选人 / 通话中邀请候选剔除 deleted;冷静期账号免密登录显示本地化 err.200005,不再露服务端英文。口径见 IMServer/docs/design/DELETE_ACCOUNT_DESIGN.md §3.5/§3.6。已实测通过(回拨拦截 / 群选人 / 英文文案)。限制(已确认属预期):杀 App 冷启动后直接点通话记录,对端资料未加载,靠服务端 invite-check 兜底,提示笼统「对方暂时无法被邀请」。
  • 注销账号 + 退出登录居中(2026-10-20,已提交本地 main,未 push;模拟器 iPhone 17 Pro Max 已逐项实测,设计 ../IMServer/docs/design/DELETE_ACCOUNT_DESIGN.md + sketches/DELETE_ACCOUNT_UX_SKETCH.html,契约 PROTOCOL §6.16 已对账):设置页 destructive 行居中;「我的资料」只读态底部注销组;IMDeleteAccountViewController(警示头/后果/冷静期条/密码/红按钮/群主阻断+可点群名/二次确认);成功 → IMSessionTeardown.wipeLocalChatCacheThen:(整库 owner 行 + 下载/原件/待发暂存/图片缓存/看过/文件夹快照/已注销登记,后台队列做)→ tearDownLocalSession → 登录页提示条;冷静期登录弹恢复 → /account/restore → 再 /login。别的设备:WS error{reason:account_deleted} → IMSocketManager+ErrorFrame.m(从主文件拆出)广播 → SceneDelegate.handleAccountDeletedElsewhere 清缓存回登录页(离线错过该帧的设备不清缓存,只因续期被拒回登录页)。「已注销用户」:IMRemarkStore 登记(isDeletedUser:,UserDefaults 按 owner 持久化,压过备注/群昵称);解析器只登记,撤销在权威端点收尾 reconcileDeletedFlags:(batch/friends/users/{id}/会话列表/成员目录);头像(UILabel+IMAvatar/导航头像/详情头)走默认首字母圈;选人页、通话邀请排除;对端已注销单聊输入栏只读、详情页只留搜索/更多、副标题不显在线态;发消息 300003 → chat.reject.recipient_deleted。测试 IMDeleteAccountTests、IMDeletedUserDisplayTests。限制:离线错过注销帧的设备不清缓存(上面已述);isDeletedUser: 每次取一次 owner(与 remarkForUser: 同成本,未优化)。已注销者头像=灰底人形(IMDeletedUserAvatarImage,对齐 Android);转发条目作者经 IMForwardOriginName(已注销发送者写「已注销用户」;只有快照昵称、拿不到 uid 的老转发链条目保持原文);聊天内「发送好友申请」恢复入口对已注销对端失效(dropFriendRequestNoteActions);300003 走灰字拒收行、无红❗重发。i18n 经 gen-i18n.mjs --check 无漂移(iOS .strings 为生成物)。 code-review 收口(10-20):别设备注销清库期间被踢通路让路;清库前先断 WS;待发暂存只删本账号消息引用的文件(目录各账号共用);/account/* 响应缺 code 不当成功;恢复弹窗无 delete_at 不显「-」;阻断态从群页返回自动解除。遗留:下载/视频原件目录各账号共用,注销会清空(缓存语义,同「清除缓存」);离线错过注销帧的设备不清缓存。
  • 扫一扫「我的二维码」页签改嵌名片码页 + 群邀请链接页(2026-10-16,未提交,未真机目测):IMQRScannerViewController 的名片页签 = 嵌入 IMQRCardViewController(updateMyProfile… 补资料、reloadCodeIfNeeded 切回重试、亮度由宿主 boost/restore);IMQRCardView.linkMode 链接页(链接框替代二维码,按钮=分享链接/复制链接,底部「查看二维码」)。欠账:qr.card.group_link_hint_expiry/share_link/view_code 只手写进 iOS .strings,须补进 ../IMServer/docs/i18n/strings.json 再 gen-i18n,否则下次生成会被覆盖;无 XCTest(纯 UI)。
  • 置顶消息底部面板(2026-10-15,未提交,未真机目测;设计 ../IMServer/docs/design/PINNED_PANEL_DESIGN.md + sketches/PINNED_PANEL_UX_SKETCH.html):横幅整条 / ≡ 恒开面板、恒显最新置顶(IMPinnedLatestItem)、kicker「· N 条」(chat.banner.pinned_count),轮转与 UIAlertController 旧列表 / chat.banner.unpin_current 已删。新文件:Modules/Chat/IMPinnedPanelViewController(PageSheet medium+large + grabber + 自持液态栏,宿主协议 IMPinnedPanelHost 绝大多数是聊天页已有方法,编译期声明在 +PinnedBanner.m、运行期由单测兜)、IMPinnedPanelCellFactory(复用聊天页真 cell + readOnly、定位圆钮挂 cell 本身)、IMPinnedPanelLogic(兜底顺序 / 日期胶囊 / 菜单允许项 / 权限外框)、Common/IMLocateInChatIcon(UIBezierPath template 图)。IMMessageCell/IMBubbleCell 加 readOnly(contentView 不接触摸;文本 8 行尾截断)。网络:IMPinnedMessage.message(完整对象)、clearPinnedMessagesWithToken:(POST …/pinned/clear)、批量帧 IMMsgOpPinTargetPayloads 拆单(IMSocketManager+BatchDelete 的 applyBatchPinFrameOnQueue:);取消置顶命中集合本地先摘、pin 变化改走 300ms 尾沿重拉、msg_op 被拒也重拉。测试 IMPinnedMessageTests +10 例(4 条核心已变异看红)。待真机:iOS 18 / 26 各看 medium / large、各消息类型置顶一条、长按菜单锚点、底栏胶囊(iOS 18 毛玻璃回退)、深色。
  • iOS 26 会话列表上滑后 Tab 条被染灰(2026-10-15,未提交,未滚动实测):IMConversationListViewController.m 创建 tableView 处对 topEdgeEffect.hidden = YES(@available(iOS 26.0, *))。根因判断:iOS 26 的 scroll edge effect 贴在表顶(搜索容器下沿),盖住吸顶的 Tab 条;Tab 条自身与搜索容器都是 systemBackgroundColor,色值本无差异。已编译并装 iOS 26.3 模拟器,静止态正常;上滑态待你在真机/模拟器目测,若仍灰则改查 IMChatFolderTabsView 吸顶时是否被表格 header 背景材质包裹。
  • 聊天文件夹(2026-10-14,已提交 2757f52;Tab 长按菜单锚定 5d47081;桌面/iOS 26·18 导航栏边缘待验):IMChatFolder/IMChatFolderStore/IMChatFolderLogic/IMHTTPService+Folders、会话列表拆出 IMConversationListViewController+Folders.m(Tab 条=首个 section header 吸顶、横滑与行滑动判定、长按菜单文件夹项第一位)、管理/编辑/选择三页;IMLiquidSegmentedControl 改居中贴合内容 + Tab 角标;设计见 IMServer docs/design/CHAT_FOLDERS_DESIGN.md。
  • 失效媒体口径对齐(2026-10-14,已提交并推送 adf2d14,真机已装;iOS 界面未目测):服务端已清理即标失效,不看本机缓存(取代 2026-08-07「铁律 A」);IMMediaExpiryRegistry 探测与复验共用一段 ranged-GET(bytes=0-0,只认 404/410),在途请求会被复验等待、失败 30s 冷却。宫格/气泡:有本机副本的图不批量探,视频无原件才探,进查看器那一次复验,命中经 IMMediaExpiryDidChangeNotification 回刷。查看器失效页:黑底 + 八角 ✕、清掉底下真图/画面、无进度条/下载键,「更多」滤掉 needsMediaBytes 项(复制/收藏/转发/下载);长按菜单对失效图/视频隐藏复制图片/转发/收藏。三端对齐(2026-10-14,未提交):群资料/详情查看器「更多」补收藏/复制并与聊天页同序(定位用 media.viewer.locate);详情 tab 与全屏媒体库长按「定位到聊天」第一位。欠账:探测去重/冷却/复验等待/菜单过滤缺 XCTest(需 NSURLProtocol 桩,见下一步);门控失效格点击仍会走到下载处理(不画下载 UI,但会起一个 404 的下载)。
  • 2026-10-13 修复一批(未提交):① 合并转发详情/群公告副标题/搜索跳日期提示的日期不再写死 zh_CN「M月d日」,改走 IMTheme dateLabelForDate:+timeStringFromMillis:(英文界面实测 Oct 6 21:27);② 会话列表群「待审」改为整行只显红字 [入群申请 N](可带 [有人@我]),不再接上一条消息,清零后恢复预览。文案 conv.list.pending_tag/pending_badge 已改、三端已重新生成。
  • 单聊系统消息 friend_accepted(2026-10-13,未 commit):服务端在好友新建立时往单聊落 content_type=system、sender 空的系统消息。iOS 侧:IMSysEventFormatter 事件表加 friend_accepted(键 sys.friend.accepted,0 人名槽位);会话列表单聊行预览改走 lastPreviewTextForSelfUID:(按 sys_event 本地化,未知回退 lastContent;顺带让系统通知单聊列表首行也本地化);↓N 窗口计数 / countIncomingInConv: / 标已读扣数(markConversation:readUpToConvSeq:)排除 system(此前 sender 空会被当「对方消息」)。核实无需改:落库/peer 由 convID 推(壳行建会话、unreadDelta 排除 system)、IMAlertDecide 对 system 全静默、通知扩展只处理服务端推送(不推)。测试:IMSysSegmentTests / IMSysEventFormatterTests 新增。待真机:互加好友后单聊出现居中灰字、列表置顶且无红点/无提示音;会话列表原无该会话时 new_msg 到达后行名在下一次 /conversations 刷新前先显「未命名」(壳行不知昵称,见已知限制)。
  • 群通知两行(2026-10-13,已真机验证):通知扩展 NotificationService.m 群聊把群当「发送人」(群名 + 群头像走 INPerson.image,不用 speakableGroupName),修 iOS 26 群通知只显示 logo;bare_body 不再使用。相册合并由服务端同 collapse-id 原地替换,扩展无需处理。
  • 聊天相册选择器 iOS 自建(10-07,已合入、用户真机自测通过,细节见 archive)。
  • iOS 单测欠账专项仍在进行(清单见 docs/TEST_DEBT.md;批 A/B、C1、C2 已做,剩 C3–C7 与批 D;测试由我逐个写,不派并行子代理改测试目标)。

下一步

  • 置顶面板收尾:../IMServer/docs/CLIENT_PARITY.md 置顶面板 iOS 格待更新(本次按要求未改别的仓);真机清单见「当前焦点」。二期(设计 §2.2):图片 / 视频单条预览、语音就地播放。
  1. 相册选择器:用户 2026-10-07 真机自测通过,无待办。已知限制:体积来自 PHAssetResource 的 fileSize(KVC),取不到时不置灰也不显总大小;无 VoiceOver 标签;Android/Web/桌面文案已重新生成(2026-10-07)。

  2. 拆体量欠账(下次碰就必须先拆):Network/IMSocketManager.m 1589/1600(只准降不准升;方向按 CODING_STYLE §7 三档:帧编解码 / 重连退避 / 各业务 send-recv 分组各成协作对象或 category,新逻辑优先开 category);Database/IMDatabase.m 1500/1500(已顶满,加列或新增前必须先拆),给 im_conversation_local/im_message_local 加列前先拆(参考 IMDatabase+MuteState.m / IMDatabase+ClearFloor.m;writeCachedConversations: 的整行 INSERT 是下一块该搬走的)。

  3. IMChatViewController.m 的 peerDisplayName 仍有 fallback:peerID(会在聊天页标题露内部 uid 的边缘路径),按 UI.md「末级不是 uid」改。

  4. 小项:setupUI 抽 IMComposerBar;遗留 P2(听筒切换/接力连播停止条/Web 转文字/语音发送接入 IMMediaSendService 常驻队列等,细节见 archive)。

已知坑 / 限制

  • 置顶面板:图 / 视频按下载策略门控时显 ↓ 占位但点了是「定位」(只读,不下载);引用条不取被引用消息的缩略图(退回类型小图标);相册成员置顶按单张图渲染(非宫格);IMSocketAckTests 三条与 IMMediaDownloadCoordinatorTests testImageNotGatedWhenPolicyOn 在本机并发负载下全量跑偶发红、单类跑与重跑全绿(与本改动无关,未定位)。

  • 新单聊壳行昵称/头像延后:会话列表原无该 conv 时 new_msg 只建壳行(peer 由 convID 推、昵称空),名片与头像等下次 /conversations(列表在屏 0.4s 内、不在屏则等回到列表)才补;IMDatabase.m 恰 1500 行,该处不能再加行。

  • 清空位点的取舍:① 老库回填(migrateClearedUpToColumnDB:)按「synced 以内本地没有的那一截 = 当年清掉的」推位点,对「本来就没下载全」的老会话会误判成已清空(如游标在 1000、本地只有 300..1000 → 位点 299,之后 ≤299 永不再拉);与 Android 迁移 15→16 同规则,设计文档拍板的口径。误伤面更大的是 ranges 时代只下过窗口附近的会话(超级群 max_gap=0 尤甚):游标在 head、本地只有最近一两窗 → 位点被推到「本地最小 seq − 1」,窗口之下更早的历史此后一律当「用户清掉的」、不再拉;补列与回填同一事务(失败整体回滚、下次启动重试)。② 落库 / UI 投递 / 回执 / 提醒共用同一份保留集合:sync 页落库前先 IMDropClearedMessages,实时先 incomingIsCleared:,window 页跳过位点内的行(库里的落库闸是第二道防线)。③ 位点存独立小表 im_conv_clear_floor_local(不随会话行删除;会话行被「删除会话」/ 列表不再返回删掉后重建,synced_conv_seq 取 max(旧值, 位点),不会 since=0 重拉)。旧的 im_conversation_local.cleared_up_to 列(早期实现)只在迁移时拷一次,之后不再读写、没有 DROP。iOS 没有「清账号」路径(登出不抹库,靠 owner_uid 隔离)。④ 清空不动会话未读数 / 读位点(沿用旧行为)。⑤ iOS 本机没有独立的「隐藏/删除墓碑」表(本地删除是物理删行),所以「墓碑不动」在 iOS 退化为「只动该会话的消息 / 区间 / 位点」。

  • 冷启动通知路由极端情况:全新会话的推送点击可能落空。

  • 会话列表左滑「免打扰」 在 done(YES) 之前 present IMMuteDurationMenu、通知横幅点击进会话 与自身 dismiss 动画并行:真机若两个动画叠加突兀,把 present/路由挪到 done(YES) / dismiss 完成回调里即可(一行改动)。

  • 通讯录 reload 不防重入:好友事件与切入请求并发时后发先至会让 applyFriends: 覆盖成较旧名单(短暂,下次刷新自愈);补法是在途时只记「待重跑」。

  • IMProgramUITests/IMContactsPerfUITests 对 2000 好友账号会卡住(XCUITest 给整棵无障碍树拍快照,cells.count 超时重试,App 本身不卡):重跑前改成不查大表,效果看 contacts_index_applied / contacts_cache_persist 日志与 simctl 截图。

  • 撤回消息的「重新编辑」可能在重拉后消失:服务端撤回/删除正文不再随 sync_resp/window_resp 下发,writeIncomingMessage 的 content=? 无条件覆盖,重拉后本地正文可能被空串盖掉(优雅降级,不崩溃)。

  • IMDeletedUserDisplayTests testAccountDeletedFramePostsNotification… 偶发红已修:测试宿主即真 App,模拟器有登录会话时 SceneDelegate 会响应手发的注销通知并 disconnect(_manualClose=YES)与读数竞态;测试内置 IMSessionTeardown.accountDeletionInProgress=YES 让路(不碰会话存储)。

  • IMMediaPlaceholderTests testFrostedLandscapeScalesLongestSideTo48 高负载偶发失败(scripts/test.sh 的 -only-testing:IMProgramTests + 关并行基本规避,根因未定位)。

  • runAfterKeyboardHidden: 兜底待测:依赖 resignFirstResponder 后必然收到 UIKeyboardDidHideNotification;外接键盘场景引用跳转不触发就加 dispatch_after 超时兜底。

  • 相册导出期杀 App 消息消失(PHPicker 句柄一次性,预期);Files <8MB 小文件、相机拍照、粘贴图仍是 VC 锚定一次性上传;iOS 无双向分页(进会话全量载入本地 DB);presence/typing 仅聊天页标题生效。

  • dev-login 建的账号无法再走密码登录(测密码登录用「注册并登录」或清 imserver.db)。

  • 查看器「正在播放中」视频 404 未接失效占位(窄路径可接受);失效标记是进程内 Set、冷启动首帧重探(刻意);原图路径 JPEG 字节戴 .heic 帽子(Web 靠嗅探已能显示,暂不改);系统按钮文案靠 CFBundleLocalizations,自有 UI 硬编码中文。

  • 测试只跑 -only-testing:IMProgramTests;改后端协议后需重启后端再测。体量门禁扫整个 IMProgram/(测试 target 是兄弟目录,不在范围)。

关联工程 / 常用命令

  • 后端 /Users/dev/IOSProject/im-client/IMServer;Web /Users/dev/IOSProject/im-client/im-web;Android /Users/dev/IOSProject/im-client/im-android。
  • 构建:xcodebuild -workspace IMProgram.xcworkspace -scheme IMProgram -sdk iphonesimulator -destination 'generic/platform=iOS Simulator' build CODE_SIGNING_ALLOWED=NO
  • 装真机(iPhoneWork 00008120-000131121E50C01E):xcodebuild … -destination 'id=<udid>' -derivedDataPath <dir> -allowProvisioningUpdates build → xcrun devicectl device install app --device <udid> <dir>/Build/Products/Debug-iphoneos/IMProgram.app。首次连后端要允许「查找并连接本地网络设备」,登录页填 Mac 当前 LAN IP。
  • 测试:唯一入口 ./scripts/test.sh(体量门禁 + 编译 + IMProgramTests;BUILD_ONLY=1 / ONLY=<Class> / ONLY=<Class>/<test>,三个坑见 CLAUDE.md「构建 / 测试」)。
  • 真机日志:xcrun devicectl device copy from --device iPhoneWork --domain-type appDataContainer --domain-identifier com.libeyond.IMProgram --source "Library/Caches/Logs/<file>.log" --destination <dst>;通知扩展日志 idevicesyslog -u <udid> grep IMNotificationService。
  • 完成定义 / 编码规范:见 CLAUDE.md、CODING_STYLE.md。