Rork で作ったアプリを TestFlight に上げる段階で、「アプリサイズが大きすぎます」と App Store Connect から警告が返ってきた、ということはないでしょうか。私も自分で運営している壁紙アプリや癒し系アプリを Rork で作り直す過程で、最初のビルドで 180MB 近くに膨らみ、慌てて削減に取り掛かった経験があります。
結論から書くと、Rork 生成アプリのバイナリサイズは、ソースコードを書き換えなくても 50〜60 % まで縮められるケースがほとんどです。今回はその手順を、私が実機と xcrun ツールでサイズを測りながら調整したときのログとあわせて共有します。
「どこに脂肪が付いているか」をまず切り分ける
最適化は計測から始めないと、体感で「軽くなった気がする」で止まってしまいます。Rork 生成アプリのサイズ構成は、大まかに次の 5 要素に分解できます。
- JavaScript バンドル(
main.jsbundleや Hermes bytecode) - 画像・フォント・動画などのアセット
- Expo モジュールを含むネイティブライブラリのバイナリ
- 言語別リソース(翻訳ファイル・ローカライズアセット)
- デバッグシンボル(
dSYM・未ストリップのネイティブコード)
iOS であれば Xcode の Organizer → Archives → Download App Size Report で、App Thinning 後の実ダウンロードサイズと原因別内訳を確認できます。Android では ./gradlew :app:bundleRelease 後に生成される output-metadata.json や APK Analyzer でモジュール別の占有量を確認します。「体感で大きい」ではなく「画像アセットが 72MB」という数字に落として初めて、削減計画が立てられます。
画像アセットを「最適なフォーマット」で入れ直す
サイズが肥大化している Rork アプリの 7 割以上で、最大の原因は画像アセットです。Rork はプロンプトに合わせて高品質なプレースホルダー画像を生成してくれるため便利ですが、PNG のままバンドルに同梱されていると、壁紙系・癒し系のような画像主体アプリでは 100MB 超えがあっという間です。
私が実際に使っている削減手順は次の 3 段構えです。
# ① アセットを一括で WebP / AVIF に変換(SVG はそのまま残す)
# cwebp は brew install webp で入れられます
find assets/images -type f \( -name "*.png" -o -name "*.jpg" \) -print0 \
| xargs -0 -I {} cwebp -q 82 "{}" -o "{}.webp"
# ② 変換後のサイズを比較(オリジナル vs WebP)
du -sh assets/images/**/*.png assets/images/**/*.webp | sort -h | tail -20
# ③ 元ファイルを削除し、コード側の参照をまとめて置換
find assets/images -type f \( -name "*.png" -o -name "*.jpg" \) -delete
rg -l "\.png\"" src/ | xargs sed -i '' 's/\.png"/\.webp"/g'期待する出力として、私のアプリでは画像アセット合計 84MB → 21MB(-75%)まで減りました。React Native は標準で WebP を扱えますが、Android で透過 PNG をフラットに変換すると壊れるケースがあるため、透過が必要なアイコン類は PNG のまま残すのが無難です。
画像まわりの最適化についてもう一歩踏み込みたい場合は、Rork アプリの画像最適化とキャッシュ戦略 にリモート配信や expo-image を使ったキャッシュ戦略をまとめています。
JavaScript バンドルを「何が重いのか」まで可視化する
画像を整理してもまだ大きい場合、次に疑うべきは JavaScript バンドルに混入している巨大な依存ライブラリです。Expo SDK 55 以降では npx expo export --dump-sourcemap で出力されたソースマップを react-native-bundle-visualizer に通すと、モジュール単位での占有量が視覚化できます。
# バンドル可視化のセットアップ
npm install -D react-native-bundle-visualizer
# 本番相当のバンドルを解析
npx react-native-bundle-visualizer --platform ios --dev falseこれで lodash(全取り込みしていると 70KB 超)や moment(約 230KB、タイムゾーンデータ込みで 400KB 超)といった「重い常連」が浮かび上がります。lodash は lodash-es への差し替えか個別インポート、moment は date-fns や dayjs への置き換えで、合計 500KB 以上削れることも珍しくありません。
注意点として、Rork で生成された直後のプロジェクトには不要な Babel プラグインが残っていることがあります。babel.config.js に @babel/preset-env が含まれている場合は、React Native 標準の babel-preset-expo に統一することで、ビルド後のバンドルから数十 KB が消えます。
Hermes と Proguard でネイティブレイヤーを絞る
iOS では Hermes の有効化(Expo SDK 55 ではデフォルト)を確認し、Android では enableProguardInReleaseBuilds = true と enableShrinkResourcesInReleaseBuilds = true の両方を android/app/build.gradle に入れておくのが基本です。
// android/app/build.gradle
android {
buildTypes {
release {
shrinkResources true
minifyEnabled true
proguardFiles getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro"
}
}
}Android 側では ABI splits を有効にすると、arm64-v8a 単独の APK を生成でき、ユーザーが実際にダウンロードするサイズが半分以下になります。Google Play なら App Bundle(AAB)にするだけで、Play 側が端末ごとに最適化してくれますが、社内配布の APK を作る場合は ABI splits の方が効果があります。
App Thinning と On-Demand Resources でダウンロードサイズを下げる
ここまで来ても App Store Connect 上で「アプリの全体サイズ」がまだ大きい場合、iOS であれば Assets.xcassets を使い、App Thinning を最大限効かせます。Rork が出力するアセットはフラットファイルになりがちですが、壁紙アプリのように端末種別ごとに違う解像度で提供したい画像は、Asset Catalog に登録して 1x / 2x / 3x を分けておくと、ユーザー端末にはその端末向けの 1 セットだけが配信されます。
On-Demand Resources は少し踏み込んだ仕組みで、「初回起動時は必要最小限だけ入れ、チュートリアル中に残りをダウンロードする」といった運用ができます。教育系アプリやゲーム系アプリでは効果が大きいですが、実装コストもそれなりに高いため、まずは App Thinning の範囲で様子を見るのが現実的です。
この辺りの設計思想については、Rork アプリの起動時間を短くする実践テクニック や Rork アプリのパフォーマンス最適化完全ガイド で、起動・描画との合わせ技として扱っています。両輪で見るとユーザー体験の改善幅が一段上がります。
全体を振り返って:今日からできる一歩
バイナリサイズの削減は、一度で劇的に減らそうとするより、計測 → 画像 → バンドル → ネイティブ層の順で、各工程を 20〜40% ずつ削るつもりで進めた方が結果的に速く進みます。まずは Xcode Organizer の App Size Report を開いて、自分のアプリの「いちばん重い一要素」がどれかを数字で確認してみてください。そこが今日の改善ターゲットです。
画像主体のアプリであれば WebP 変換だけで 3 桁 MB が一気に減ることもあり、投資対効果がとても良い部分です。実装しやすく効果が大きな場所から片付けていくと、App Store 審査でサイズ警告が出なくなるだけでなく、低速回線のユーザーがインストールを諦めなくなり、インストール率そのものが改善されます。サイズの最適化は、ユーザーへの最初のプレゼントのようなものだと私は思っています。