feat(diff): emit copiesCrc for content-based resource matching (fix AAB image hot update)#54
Conversation
…ontent
When the uploaded baseline is an APK but the app is installed from an AAB
(Play split APKs), res/ drawable paths are shortened on device, so the
path recorded in `copies` (e.g. res/drawable-xhdpi-v4/x.webp) does not
exist verbatim and images (webp) fail to copy during a from-package patch.
diffFromPackage already finds unchanged/moved files by CRC32 internally but
only hands the client a path. This adds an optional `copiesCrc` map to
__diff.json ({ to: crc32 }) for "moved" entries (the res/ resources at
risk of path divergence), letting the client locate them by content when
the path is missing. CRC32 is over the uncompressed content, so it is
stable across APK/AAB packaging.
- Only moved entries get a crc (same-path assets stay path-stable) → minimal
manifest growth.
- Keyed by `to` (unique) to avoid same-content collisions.
- Fully backward compatible: old clients ignore the field; new clients
treat its absence as today's path-based behavior.
Consumed by react-native-update (Android BundledResourceCopier).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (2)
📝 WalkthroughWalkthroughThis PR extends the diff manifest generation to track CRC32 checksums for relocated file entries. The ChangesCRC32 Checksum Tracking for Moved Files
Estimated code review effort🎯 2 (Simple) | ⏱️ ~10 minutes Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
…s + openRawResource density fix (#577) * fix(android): match copied resources by content (CRC32) for AAB installs A from-package (PATCH_FROM_APK) hot update copies unchanged resources out of the on-device package using the path recorded in __diff.json `copies`. When the baseline uploaded to the server was an APK but the app is installed from an AAB (Play split APKs), res/ drawable paths are shortened on device, so the recorded path (e.g. res/drawable-xhdpi-v4/x.webp) does not exist verbatim and images (webp) silently fall through and go missing. Add a CRC32 content-match tier in BundledResourceCopier: build a crc32 -> entry index while scanning the base + split APKs, and when a `from` path is not found by exact/normalized path, locate the file by the content checksum supplied via the new manifest `copiesCrc` map. CRC32 is over the uncompressed content, so it is stable across APK/AAB packaging. This tier runs before resolveBundledResource (content match is more reliable than the resource-id heuristic). Also fix openResolvedResourceStream: use openRawResource(id, typedValue) with the density-resolved TypedValue instead of openRawResource(id), which ignored the requested density and could copy the wrong variant. Backward/forward compatible: manifests without `copiesCrc` (older CLI) simply skip the CRC tier and fall back to today's path-based behavior. Requires CLI support: reactnativecn/react-native-update-cli#54 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(android): address review — exact CRC archive + real density-correct copy Two follow-ups from review on the resource copier: 1. CRC index stored only the entry name, so resolving it back through availableEntries could yield a different-content entry when two APKs (base + split) expose the same name with different bytes. Store the matched ZipEntry together with its SafeZipFile (ZipSource) and copy from that archive directly. 2. openRawResource(id, typedValue) is a no-op for density: AOSP's ResourcesImpl re-runs getValue(id, value, true) and overwrites the passed TypedValue at the current configuration before opening the stream. Instead of going through openRawResource (or the hidden openNonAsset API), take the density-correct file path resolved by getValueForDensity and copy that exact entry from the already-open archives — public API, correct variant. openRawResource(id) remains only as a defensive fallback. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Problem
热更新「上传 APK 基线 + 设备运行 AAB(Google Play 拆分包)」组合下,WebP 图片加载不出来。
diffFromPackage把同内容文件以路径写进copies(copies[to] = movedFrom,AndroidhdiffFromApk的transformPackagePath为恒等),客户端只能按路径在设备包里找。但:drawable-*/foo.webp,APK 基线里在res/drawable-*-v4/foo.webp→ 每张图片都走 moved 分支,from = res/...。res/做了资源路径压缩,同一张图变成res/xY.webp,可读全名不存在 → 路径匹配落空 → 图片缺失。assets/路径稳定,不受影响 → 只有图片挂。历史上 #512 曾用
copiesv2(CRC32 内容匹配)修过,后被移除退化成纯路径启发式。Change
__diff.json新增可选字段copiesCrc,与copies并列(键=目标路径to,值=内容 CRC32):{ "copies": { "drawable-xhdpi/x.webp": "res/drawable-xhdpi-v4/x.webp" }, "copiesCrc": { "drawable-xhdpi/x.webp": 2746328104 } }CRC32 对 zip 条目算的是解压后内容,只要图片字节一致(webp 在 APK/AAB 通常原样存储),crc 就一致,天然跨 APK/AAB 格式。客户端在路径找不到时按内容命中。
设计取舍(高效 + 兼容)
''同路径条目稳定,不输出 → 清单只为图片多「一路径+一数字」。to(唯一),避免同内容(同 crc)互相覆盖(弃用旧copiesv2的 crc→to)。diffFromPackage;diffFromPPK(磁盘文件补丁、路径稳定)不动。Test
tests/diff.test.ts新增用例:断言 moved 的res/图片进copiesCrc且值等于其 crc32、assets/同路径文件不进copiesCrc。bun test tests/diff.test.ts→ 13 pass / 0 fail。客户端配套
需配合 react-native-update 客户端(Android
BundledResourceCopier增加 CRC 内容兜底层)。对应 PR 见 reactnativecn/react-native-update。🤖 Generated with Claude Code
Summary by CodeRabbit
New Features
Tests