1k-patching-native-modules

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Patching 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 & PR
1. 分析崩溃日志 → 2. 定位漏洞 → 3. 修复代码 → 4. 清理构建产物 → 5. 生成补丁 → 6. 提交并创建PR

Step 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
    ,
    SIGABRT
    , etc.
  • 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:
    NullPointerException
    ,
    OutOfMemoryError
  • Stack trace: Java/Kotlin method chain
  • Thread info: Main thread vs background
需要关注:
  • 异常类
    NullPointerException
    OutOfMemoryError
  • 调用栈:Java/Kotlin方法链
  • 线程信息:主线程 vs 后台线程

Step 2: Locate the Bug

步骤2:定位漏洞

Find native module source

查找原生模块源码

bash
undefined
bash
undefined

iOS (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/
undefined
ls node_modules/<package>/android/src/main/java/
undefined

Common crash causes

常见崩溃原因

Crash TypeCommon CauseFix Pattern
EXC_BAD_ACCESS
Nil pointer dereferenceAdd
guard let
check
KERN_INVALID_ADDRESS
Accessing deallocated memoryUse weak references
NullPointerException
Null object accessAdd null check
OutOfMemoryError
Large image/data processingAdd size limits
崩溃类型常见原因修复模式
EXC_BAD_ACCESS
空指针引用添加
guard let
检查
KERN_INVALID_ADDRESS
访问已释放的内存使用弱引用
NullPointerException
访问空对象添加空值检查
OutOfMemoryError
大图片/数据处理添加大小限制

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
undefined

Remove 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 files
rm -rf node_modules/expo-image/android/build

为什么这很重要:
- Android构建会生成`.class`、`.jar`等二进制文件
- 这些文件会污染补丁文件(可能膨胀到5000行以上)
- patch-package会包含这些不必要的文件

Step 5: Generate Patch

步骤5:生成补丁

bash
undefined
bash
undefined

Generate 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
undefined
bash
undefined

Check 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
undefined
head -100 patches/<package-name>*.patch
undefined

Step 6: Commit & Create PR

步骤6:提交并创建PR

bash
undefined
bash
undefined

Stage 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
undefined
gh pr create --title "fix(ios): <描述>" --base x
undefined

Common Packages & Their Native Locations

常见包及其原生代码位置

PackageiOS SourceAndroid Source
expo-image
node_modules/expo-image/ios/
node_modules/expo-image/android/src/
react-native
node_modules/react-native/React/
node_modules/react-native/ReactAndroid/
@react-native-async-storage/async-storage
node_modules/@react-native-async-storage/async-storage/ios/
...android/src/
react-native-reanimated
node_modules/react-native-reanimated/ios/
...android/src/
iOS源码位置Android源码位置
expo-image
node_modules/expo-image/ios/
node_modules/expo-image/android/src/
react-native
node_modules/react-native/React/
node_modules/react-native/ReactAndroid/
@react-native-async-storage/async-storage
node_modules/@react-native-async-storage/async-storage/ios/
...android/src/
react-native-reanimated
node_modules/react-native-reanimated/ios/
...android/src/

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.patch

Troubleshooting

故障排除

Patch file too large

补丁文件过大

bash
undefined
bash
undefined

Clean 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>
undefined
npx patch-package <package>
undefined

Patch not applying

补丁无法应用

bash
undefined
bash
undefined

Check 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
undefined
mv patches/<package>+old.patch patches/<package>+new.patch
undefined

Swift/Kotlin syntax help

Swift/Kotlin语法帮助

Swift guard let:
swift
guard let value = optionalValue else {
  return  // Must exit scope
}
// value is now non-optional
Kotlin null check:
kotlin
val value = nullableValue ?: return
// value is now non-null
Swift 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/