Claude-skill-registry 1k-patching-native-modules
Patches native modules (expo-image, react-native, etc.) to fix native crashes or bugs.
install
source · Clone the upstream repo
git clone https://github.com/majiayu000/claude-skill-registry
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/data/1k-patching-native-modules" ~/.claude/skills/majiayu000-claude-skill-registry-1k-patching-native-modules && rm -rf "$T"
manifest:
skills/data/1k-patching-native-modules/SKILL.mdsource content
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
Step 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
# 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 check |
| 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
// 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
// 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:
# 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/build
Why 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
# Generate patch file npx patch-package <package-name> # Example: npx patch-package expo-image
Patch file location:
patches/<package-name>+<version>.patch
Verify patch content
# 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>*.patch
Step 6: Commit & Create PR
# 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 x
Common Packages & Their Native Locations
| Package | iOS Source | Android Source |
|---|---|---|
| | |
| | |
| | |
| | |
Existing Patches Reference
Check existing patches for patterns:
ls patches/ cat patches/expo-image+3.0.10.patch
Troubleshooting
Patch file too large
# 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
# 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.patch
Swift/Kotlin syntax help
Swift guard let:
guard let value = optionalValue else { return // Must exit scope } // value is now non-optional
Kotlin null check:
val value = nullableValue ?: return // value is now non-null
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/