1k-patching-native-modules について
クラッシュログの分析からネイティブモジュールの修正、パッチ生成までを案内するスキルです。iOS と Android の調査、ビルド生成物の削除、patch-package による確認を扱います。
主な機能
- 01iOS と Android のクラッシュログ分析
- 02ネイティブモジュールのソースと障害箇所の特定
- 03NULL とメモリ安全性の確認を適用
- 04パッチ生成前のビルド生成物削除
- 05パッチ内容の確認とコミット準備
活用シーン
- 01ネイティブモジュールが原因のアプリクラッシュ調査
- 02Swift または Kotlin の NULL 処理の修正
- 03Android のビルドファイルがパッチに入るのを防止
- 04依存モジュールの変更パッチを生成して検証
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ onekeyhq/ app-monorepo --skill 1k-patching-native-modulesインストール後、Claude Code で/1k-patching-native-modulesを入力して読み込まれたか確認します。
詳細
ネイティブモジュールのパッチ適用
クラッシュログを分析し、ネイティブモジュールのバグを修正して、パッチを生成するには、次のワークフローに従ってください。
ワークフローの概要
1. Analyze Crash Log → 2. Locate Bug → 3. Fix Code → 4. Clean Build Artifacts → 5. Generate Patch → 6. Commit & PR
ステップ 1:クラッシュログを分析する
iOS のクラッシュ(EXC_BAD_ACCESS / KERN_INVALID_ADDRESS)
抽出する重要な情報:
- 例外の種類:
EXC_BAD_ACCESS、SIGABRTなど - スタックトレース:クラッシュしている関数を特定します
- メモリアドレス:nil ポインターの問題を特定するのに役立ちます
- ライブラリ:クラッシュしているネイティブモジュールを確認します
クラッシュパターンの例:
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 のクラッシュ(NullPointerException / OOM)
次の点を確認します:
- 例外クラス:
NullPointerException、OutOfMemoryError - スタックトレース:Java/Kotlin のメソッドチェーン
- スレッド情報:メインスレッドかバックグラウンドスレッドか
ステップ 2:バグの場所を特定する
ネイティブモジュールのソースを見つける
# iOS (Swift/Objective-C)
ls node_modules/<package>/ios/
# Android (Kotlin/Java)
ls node_modules/<package>/android/src/main/java/
よくあるクラッシュの原因
| クラッシュの種類 | よくある原因 | 修正パターン |
|---|---|---|
EXC_BAD_ACCESS | nil ポインターの参照解除 | guard let チェックを追加する |
KERN_INVALID_ADDRESS | 解放済みメモリへのアクセス | 弱参照を使用する |
NullPointerException | null オブジェクトへのアクセス | null チェックを追加する |
OutOfMemoryError | 大きな画像やデータの処理 | サイズ制限を追加する |
ステップ 3:コードを修正する
iOS(Swift)- nil チェックパターン
// 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 チェックパターン
// Before
val uri = source.uri
loadImage(uri)
// After
val uri = source.uri ?: return
if (uri.toString().isEmpty()) return
loadImage(uri)
ステップ 4:ビルド成果物をクリーンアップする(重要)
パッチを生成する前に、必ず Android のビルドキャッシュをクリーンアップしてください:
# 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
重要な理由:
- Android のビルドでは、
.class、.jar、バイナリファイルが生成されます - これらがパッチファイルに混入し、ファイルが 5000 行以上になることがあります
- patch-package にこれらの不要なファイルが含まれてしまいます
ステップ 5:パッチを生成する
# Generate patch file
npx patch-package <package-name>
# Example:
npx patch-package expo-image
パッチファイルの場所:patches/<package-name>+<version>.patch
パッチの内容を確認する
# 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
ステップ 6:コミットして 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
よく使われるパッケージとネイティブコードの場所
| パッケージ | 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/ |
既存パッチの参照
パターンを確認するには、既存のパッチを参照してください:
ls patches/
cat patches/expo-image+3.0.10.patch
トラブルシューティング
パッチファイルのサイズが大きすぎる
# 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>
パッチが適用されない
# 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 の構文について
Swift の guard let:
guard let value = optionalValue else {
return // Must exit scope
}
// value is now non-optional
Kotlin の null チェック:
val value = nullableValue ?: return
// value is now non-null
関連ファイル
- パッチディレクトリ:
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/
コメント
Markdown 対応