1k-patching-native-modules
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChinesePatching Native Modules
修补原生模块
Follow this workflow to analyze crash logs, fix native module bugs, and generate patches.
按照以下工作流程分析崩溃日志、修复原生模块漏洞并生成补丁。
Workflow Overview
工作流程概述
1. Analyze Crash Log → 2. Locate Bug → 3. Fix Code → 4. Clean Build Artifacts → 5. Generate Patch → 6. Commit & PR1. 分析崩溃日志 → 2. 定位漏洞 → 3. 修复代码 → 4. 清理构建产物 → 5. 生成补丁 → 6. 提交并创建PRStep 1: Analyze Crash Log
步骤1:分析崩溃日志
iOS Crash (EXC_BAD_ACCESS / KERN_INVALID_ADDRESS)
iOS崩溃(EXC_BAD_ACCESS / KERN_INVALID_ADDRESS)
Key information to extract:
- Exception type: ,
EXC_BAD_ACCESS, etc.SIGABRT - Stack trace: Identify the crashing function
- Memory address: Helps identify nil pointer issues
- Library: Which native module is crashing
Example crash pattern:
EXC_BAD_ACCESS: KERN_INVALID_ADDRESS at 0x3c61c1a3b0d0
objc_msgSend in unknown file
-[SDWebImageManager cacheKeyForURL:context:] ← Crashing function
-[SDWebImageManager loadImageWithURL:options:context:progress:completed:]需要提取的关键信息:
- 异常类型:、
EXC_BAD_ACCESS等SIGABRT - 调用栈:确定崩溃的函数
- 内存地址:帮助识别空指针问题
- 库:哪个原生模块发生崩溃
示例崩溃模式:
EXC_BAD_ACCESS: KERN_INVALID_ADDRESS at 0x3c61c1a3b0d0
objc_msgSend in unknown file
-[SDWebImageManager cacheKeyForURL:context:] ← 崩溃函数
-[SDWebImageManager loadImageWithURL:options:context:progress:completed:]Android Crash (NullPointerException / OOM)
Android崩溃(NullPointerException / OOM)
Look for:
- Exception class: ,
NullPointerExceptionOutOfMemoryError - Stack trace: Java/Kotlin method chain
- Thread info: Main thread vs background
需要关注:
- 异常类:、
NullPointerExceptionOutOfMemoryError - 调用栈:Java/Kotlin方法链
- 线程信息:主线程 vs 后台线程
Step 2: Locate the Bug
步骤2:定位漏洞
Find native module source
查找原生模块源码
bash
undefinedbash
undefinediOS (Swift/Objective-C)
iOS(Swift/Objective-C)
ls node_modules/<package>/ios/
ls node_modules/<package>/ios/
Android (Kotlin/Java)
Android(Kotlin/Java)
ls node_modules/<package>/android/src/main/java/
undefinedls node_modules/<package>/android/src/main/java/
undefinedCommon crash causes
常见崩溃原因
| Crash Type | Common Cause | Fix Pattern |
|---|---|---|
| Nil pointer dereference | Add |
| Accessing deallocated memory | Use weak references |
| Null object access | Add null check |
| Large image/data processing | Add size limits |
| 崩溃类型 | 常见原因 | 修复模式 |
|---|---|---|
| 空指针引用 | 添加 |
| 访问已释放的内存 | 使用弱引用 |
| 访问空对象 | 添加空值检查 |
| 大图片/数据处理 | 添加大小限制 |
Step 3: Fix the Code
步骤3:修复代码
iOS (Swift) - Nil Check Pattern
iOS(Swift)- 空值检查模式
swift
// Before (crashes when uri is nil)
imageManager.loadImage(with: source.uri, ...)
// After (safe)
guard let sourceUri = source.uri, !sourceUri.absoluteString.isEmpty else {
onError(["error": "Image source URI is nil or empty"])
return
}
imageManager.loadImage(with: sourceUri, ...)swift
// 修复前(当uri为空时会崩溃)
imageManager.loadImage(with: source.uri, ...)
// 修复后(安全)
guard let sourceUri = source.uri, !sourceUri.absoluteString.isEmpty else {
onError(["error": "图片源URI为空或无效"])
return
}
imageManager.loadImage(with: sourceUri, ...)Android (Kotlin) - Null Check Pattern
Android(Kotlin)- 空值检查模式
kotlin
// Before
val uri = source.uri
loadImage(uri)
// After
val uri = source.uri ?: return
if (uri.toString().isEmpty()) return
loadImage(uri)kotlin
// 修复前
val uri = source.uri
loadImage(uri)
// 修复后
val uri = source.uri ?: return
if (uri.toString().isEmpty()) return
loadImage(uri)Step 4: Clean Build Artifacts (CRITICAL)
步骤4:清理构建产物(至关重要)
Before generating patch, MUST clean Android build cache:
bash
undefined生成补丁前,必须清理Android构建缓存:
bash
undefinedRemove Android build artifacts to avoid polluting the patch
删除Android构建产物,避免污染补丁
rm -rf node_modules/<package>/android/build
rm -rf node_modules/<package>/android/build
For expo-image specifically:
针对expo-image的特殊操作:
rm -rf node_modules/expo-image/android/build
Why this matters:
- Android build generates `.class`, `.jar`, binary files
- These pollute the patch file (can grow to 5000+ lines)
- patch-package will include these unwanted filesrm -rf node_modules/expo-image/android/build
为什么这很重要:
- Android构建会生成`.class`、`.jar`等二进制文件
- 这些文件会污染补丁文件(可能膨胀到5000行以上)
- patch-package会包含这些不必要的文件Step 5: Generate Patch
步骤5:生成补丁
bash
undefinedbash
undefinedGenerate patch file
生成补丁文件
npx patch-package <package-name>
npx patch-package <package-name>
Example:
示例:
npx patch-package expo-image
Patch file location: `patches/<package-name>+<version>.patch`npx patch-package expo-image
补丁文件位置:`patches/<package-name>+<version>.patch`Verify patch content
验证补丁内容
bash
undefinedbash
undefinedCheck patch doesn't include unwanted files
检查补丁是否包含不必要的文件
grep -c "android/build" patches/<package-name>*.patch
grep -c "android/build" patches/<package-name>*.patch
Should return 0
应返回0
View actual changes
查看实际修改内容
head -100 patches/<package-name>*.patch
undefinedhead -100 patches/<package-name>*.patch
undefinedStep 6: Commit & Create PR
步骤6:提交并创建PR
bash
undefinedbash
undefinedStage patch file
暂存补丁文件
git add patches/<package-name>*.patch
git add patches/<package-name>*.patch
Commit with descriptive message
提交并添加描述性信息
git commit -m "fix(ios): prevent EXC_BAD_ACCESS crash in <package> when <condition>
Add guard checks in <package> native layer to prevent crash when <scenario>.
Fixes Sentry issue #XXXXX"
git commit -m "fix(ios): 修复<package>在<条件>下的EXC_BAD_ACCESS崩溃
在<package>原生层添加guard检查,防止<场景>下的崩溃。
修复Sentry问题#XXXXX"
Create PR
创建PR
gh pr create --title "fix(ios): <description>" --base x
undefinedgh pr create --title "fix(ios): <描述>" --base x
undefinedCommon Packages & Their Native Locations
常见包及其原生代码位置
| Package | iOS Source | Android Source |
|---|---|---|
| | |
| | |
| | |
| | |
| 包 | iOS源码位置 | Android源码位置 |
|---|---|---|
| | |
| | |
| | |
| | |
Existing Patches Reference
现有补丁参考
Check existing patches for patterns:
bash
ls patches/
cat patches/expo-image+3.0.10.patch查看现有补丁的模式:
bash
ls patches/
cat patches/expo-image+3.0.10.patchTroubleshooting
故障排除
Patch file too large
补丁文件过大
bash
undefinedbash
undefinedClean all build artifacts
清理所有构建产物
rm -rf node_modules/<package>/android/build
rm -rf node_modules/<package>/ios/build
rm -rf node_modules/<package>/.gradle
rm -rf node_modules/<package>/android/build
rm -rf node_modules/<package>/ios/build
rm -rf node_modules/<package>/.gradle
Regenerate
重新生成补丁
npx patch-package <package>
undefinednpx patch-package <package>
undefinedPatch not applying
补丁无法应用
bash
undefinedbash
undefinedCheck package version matches
检查包版本是否匹配
cat node_modules/<package>/package.json | grep version
cat node_modules/<package>/package.json | grep version
Rename patch if version changed
如果版本变更,重命名补丁
mv patches/<package>+old.patch patches/<package>+new.patch
undefinedmv patches/<package>+old.patch patches/<package>+new.patch
undefinedSwift/Kotlin syntax help
Swift/Kotlin语法帮助
Swift guard let:
swift
guard let value = optionalValue else {
return // Must exit scope
}
// value is now non-optionalKotlin null check:
kotlin
val value = nullableValue ?: return
// value is now non-nullSwift guard let:
swift
guard let value = optionalValue else {
return // 必须退出当前作用域
}
// value现在为非可选类型Kotlin空值检查:
kotlin
val value = nullableValue ?: return
// value现在为非空类型Related Files
相关文件
- Patches directory:
patches/ - expo-image iOS:
node_modules/expo-image/ios/ImageView.swift - expo-image Android:
node_modules/expo-image/android/src/main/java/expo/modules/image/
- 补丁目录:
patches/ - expo-image iOS:
node_modules/expo-image/ios/ImageView.swift - expo-image Android:
node_modules/expo-image/android/src/main/java/expo/modules/image/