1k-patching-native-modules
Original:🇺🇸 English
Translated
Patches native modules (expo-image, react-native, etc.) to fix native crashes or bugs.
8installs
Sourceonekeyhq/app-monorepo
Added on
NPX Install
npx skill4agent add onekeyhq/app-monorepo 1k-patching-native-modulesTags
Translated version includes tags in frontmatterSKILL.md Content
View Translation Comparison →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 & PRStep 1: Analyze Crash Log
iOS Crash (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:]Android Crash (NullPointerException / OOM)
Look for:
- Exception class: ,
NullPointerExceptionOutOfMemoryError - Stack trace: Java/Kotlin method chain
- Thread info: Main thread vs background
Step 2: Locate the Bug
Find native module source
bash
# iOS (Swift/Objective-C)
ls node_modules/<package>/ios/
# Android (Kotlin/Java)
ls node_modules/<package>/android/src/main/java/Common 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
iOS (Swift) - Nil Check Pattern
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, ...)Android (Kotlin) - Null Check Pattern
kotlin
// Before
val uri = source.uri
loadImage(uri)
// After
val uri = source.uri ?: return
if (uri.toString().isEmpty()) return
loadImage(uri)Step 4: Clean Build Artifacts (CRITICAL)
Before generating patch, MUST clean Android build cache:
bash
# Remove Android build artifacts to avoid polluting the patch
rm -rf node_modules/<package>/android/build
# For expo-image specifically:
rm -rf node_modules/expo-image/android/buildWhy this matters:
- Android build generates ,
.class, binary files.jar - These pollute the patch file (can grow to 5000+ lines)
- patch-package will include these unwanted files
Step 5: Generate Patch
bash
# Generate patch file
npx patch-package <package-name>
# Example:
npx patch-package expo-imagePatch file location:
patches/<package-name>+<version>.patchVerify patch content
bash
# Check patch doesn't include unwanted files
grep -c "android/build" patches/<package-name>*.patch
# Should return 0
# View actual changes
head -100 patches/<package-name>*.patchStep 6: Commit & Create PR
bash
# Stage patch file
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"
# Create PR
gh pr create --title "fix(ios): <description>" --base xCommon Packages & Their Native Locations
| Package | iOS Source | Android Source |
|---|---|---|
| | |
| | |
| | |
| | |
Existing Patches Reference
Check existing patches for patterns:
bash
ls patches/
cat patches/expo-image+3.0.10.patchTroubleshooting
Patch file too large
bash
# Clean all build artifacts
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>Patch not applying
bash
# Check package version matches
cat node_modules/<package>/package.json | grep version
# Rename patch if version changed
mv patches/<package>+old.patch patches/<package>+new.patchSwift/Kotlin syntax help
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-nullRelated 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/