RORK LABEN
PRICE — Rork Max の価格帯は月200ドルから1,800ドルまで幅があります。作業量の多い開発者やチーム向けの帯が上に伸びている形ですFREE — 無料枠は週5プロンプト程度です。試すには足りますが、継続的に作るなら有料前提の設計になっていますSHIP — App Store への公開はビルド・証明書・申請まで自動化されており、Mac も Xcode も持たずに iOS アプリを出せますSIM — ブラウザ配信のシミュレータで、実際の Apple 環境で動く画面を手元のブラウザから確認できますNATIVE — HealthKit、ARKit と LiDAR、NFC、Dynamic Island、Metal による3D まで届きます。React Native では触れない領域ですFUNDING — 2026年4月9日発表のシードで Left Lane Capital 主導の1,500万ドルを調達し、アプリビルダーの Paperline を買収していますPRICE — Rork Max の価格帯は月200ドルから1,800ドルまで幅があります。作業量の多い開発者やチーム向けの帯が上に伸びている形ですFREE — 無料枠は週5プロンプト程度です。試すには足りますが、継続的に作るなら有料前提の設計になっていますSHIP — App Store への公開はビルド・証明書・申請まで自動化されており、Mac も Xcode も持たずに iOS アプリを出せますSIM — ブラウザ配信のシミュレータで、実際の Apple 環境で動く画面を手元のブラウザから確認できますNATIVE — HealthKit、ARKit と LiDAR、NFC、Dynamic Island、Metal による3D まで届きます。React Native では触れない領域ですFUNDING — 2026年4月9日発表のシードで Left Lane Capital 主導の1,500万ドルを調達し、アプリビルダーの Paperline を買収しています
記事一覧/開発ツール
開発ツール/2026-04-24中級

Rork アプリのバイナリサイズが 150MB を超えた時に切り分ける 5 つの要因と実践的な削減手順

Rork で生成したアプリが 180MB まで膨らみ、App Store Connect の警告で止まった経験から、原因を 5 要素に分解して 69MB まで落とすまでの手順を、実測値と失敗した箇所も含めて共有します。

rork58bundle-sizeoptimization4app-store15expo11

Rork で作ったアプリを TestFlight に上げる段階で、「アプリサイズが大きすぎます」と App Store Connect から警告が返ってきた、ということはないでしょうか。私も自分で運営している壁紙アプリや癒し系アプリを Rork で作り直す過程で、最初のビルドで 180MB 近くに膨らみ、慌てて削減に取り掛かった経験があります。

結論から書くと、Rork 生成アプリのバイナリサイズは、ソースコードを書き換えなくても 50〜60 % まで縮められるケースがほとんどです。今回はその手順を、私が実機と xcrun ツールでサイズを測りながら調整したときのログとあわせて共有します。

「どこに脂肪が付いているか」をまず切り分ける

最適化は計測から始めないと、体感で「軽くなった気がする」で止まってしまいます。Rork 生成アプリのサイズ構成は、大まかに次の 5 要素に分解できます。

  • JavaScript バンドル(main.jsbundle や Hermes bytecode)
  • 画像・フォント・動画などのアセット
  • Expo モジュールを含むネイティブライブラリのバイナリ
  • 言語別リソース(翻訳ファイル・ローカライズアセット)
  • デバッグシンボル(dSYM・未ストリップのネイティブコード)

計測してみると、私の壁紙アプリでは最適化前後で次のような内訳になりました。数字は Xcode Organizer の App Size Report と xcrun での実測値です。

構成要素最適化前最適化後主な手段
画像アセット84 MB21 MBWebP 変換・不要解像度の削除
JavaScript バンドル12 MB8 MBmoment→dayjs・lodash の個別 import
ネイティブライブラリ48 MB34 MB未使用 Expo モジュール除去・ABI splits
言語リソース6 MB4 MB未使用ロケールの削除
デバッグシンボル22 MB2 MBdSYM をアップロードから分離・strip
合計172 MB69 MB(-60%)

この表で伝えたいのは、削減の伸びしろは要素ごとに大きく違うということです。画像で 63 MB 削れた一方、言語リソースは 2 MB。まず「いちばん重い一要素」に手を入れると、同じ労力でも効き方がまるで違います。

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 のまま残すのが無難です。

画像フォーマットの選択でさらに踏み込みたい場合は、WebP と AVIF のデコードコストと CDN ネゴシエーション に、フォーマットごとの伸長コストと配信側での出し分けをまとめています。

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 超)といった「重い常連」が浮かび上がります。lodashlodash-es への差し替えか個別インポート、momentdate-fnsdayjs への置き換えで、合計 500KB 以上削れることも珍しくありません。

注意点として、Rork で生成された直後のプロジェクトには不要な Babel プラグインが残っていることがあります。babel.config.js@babel/preset-env が含まれている場合は、React Native 標準の babel-preset-expo に統一することで、ビルド後のバンドルから数十 KB が消えます。

Hermes と Proguard でネイティブレイヤーを絞る

iOS では Hermes の有効化(Expo SDK 55 ではデフォルト)を確認し、Android では enableProguardInReleaseBuilds = trueenableShrinkResourcesInReleaseBuilds = 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 アプリの起動時間を短くする実践テクニック で、起動・描画との合わせ技として扱っています。サイズと起動を両輪で見ると、ユーザー体験の改善幅が一段上がります。

バイナリサイズと OTA 更新サイズは別物として測る

ここまでは「初回インストールで転送されるバイナリ」を縮める話でした。運用フェーズに入ると、もうひとつ別のサイズ指標が効いてきます。OTA(Over-the-Air)更新で配信される差分の大きさです。

Expo SDK 55 の EAS Update は、Hermes バイトコードの差分だけを配信する方式に変わりました。私のアプリでは、機能追加のたびに数 MB の JS バンドル全体を配っていたものが、変更分だけの配信になり、更新ペイロードが 4 分の 1 近くまで縮みました。転送量が減るぶん、バックグラウンドでの適用がほぼ即座になり、EAS プランの帯域消費も抑えられます。

ここで気をつけたいのは、バイナリを削っても OTA 更新は自動では軽くならないという点です。更新のたびに巨大な画像を新規同梱すれば、差分は当然ふくらみます。初回バイナリは Asset Catalog と App Thinning で、継続的な更新は「JS とアセットの差分をいかに小さく保つか」で、別々に最適化するのが実務的です。OTA で足りる変更か本体ビルドが必要かは、Expo の fingerprint ツールで機械的に判定できます。

削っても跳ね返ってきた三つの落とし穴

サイズ削減で厄介なのは、数字が減ったのに別のところが壊れる、という形で問題が遅れて表に出てくることです。ビルドは通り、審査も通り、リリースしてから気づく。私が実際に踏んだものを三つ挙げます。

shrinkResources で動的参照のリソースが消える。 リソース名を文字列で組み立てて getIdentifier() で引いている箇所があると、Gradle は「どこからも参照されていない」と判断して削ります。ビルドは通り、該当画面を開いた瞬間だけ落ちます。壁紙アプリのカテゴリアイコンがこれで消えました。保持したいリソースは明示します。

<!-- android/app/src/main/res/raw/keep.xml -->
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:tools="http://schemas.android.com/tools"
    tools:keep="@drawable/category_*,@raw/onboarding_*"
    tools:shrinkMode="strict" />

tools:shrinkMode="strict" を付けておくと、明示したもの以外は落とす前提になるため、後から追加したリソースの取りこぼしに気づきやすくなります。

dSYM をアーカイブから外すと、クラッシュログが読めなくなる。 表の 22 MB → 2 MB はここで稼いだ部分ですが、シンボルファイルを「削除」してしまうと Crashlytics のスタックトレースが 16 進アドレスの羅列になります。外すのではなく、アップロード対象から分離して別途保管する、が正解です。

# アーカイブから dSYM だけ取り出して保管し、バイナリからは strip する
cp -R MyApp.xcarchive/dSYMs "$HOME/dsyms/$(date +%Y%m%d)-$(git rev-parse --short HEAD)"
# Crashlytics へアップロード(保管したものを指定)
./Pods/FirebaseCrashlytics/upload-symbols -gsp GoogleService-Info.plist -p ios "$HOME/dsyms/..."

私はコミットハッシュ付きのディレクトリ名で残すようにしてから、「どのビルドの dSYM か分からない」という一番不毛な調査をしなくて済むようになりました。

Asset Catalog に入れた画像は OTA で差し替えられない。 App Thinning を効かせるために画像を Assets.xcassets へ移すと、その画像はネイティブバイナリ側の資産になります。つまり EAS Update では更新できません。季節ごとに絵柄を差し替えたい画像まで Asset Catalog に入れてしまい、次の入れ替えで本体ビルドの提出が必要になった、というのが私の失敗でした。

判断の線引きはシンプルにしています。アプリの寿命のあいだ変わらないもの(アイコン・ロゴ・恒久的な背景)は Asset Catalog へ。運用で差し替える可能性があるものはバンドル側に残し、可能なら CDN 配信に寄せる。この一本の線を引いておくだけで、後から効いてきます。

削減の結果は「配信サイズ」で確かめる

最後に確認の話です。手元の .ipa のファイルサイズを見て安心するのは早いところがあります。ユーザーが実際にダウンロードするのは App Thinning 後の、その端末向けの一組だけだからです。手元の 120 MB が実配信では 58 MB、ということが普通に起こります。

iOS は Xcode Organizer の App Size Report が正確ですが、提出前に手元で概算したいときは、エクスポートした成果物に付いてくるレポートを見るのが早いです。

# Ad Hoc / App Store エクスポート時に生成されるサイズレポートを読む
cat build/export/App\ Thinning\ Size\ Report.txt | grep -A3 "App size"

Android は AAB から端末別 APK を実際に生成して測るのが確実です。

# bundletool で端末構成ごとの配信サイズを一覧化する
bundletool build-apks --bundle=app-release.aab --output=app.apks \
  --ks=release.keystore --ks-key-alias=release
bundletool get-size total --apks=app.apks --dimensions=ABI,SDK

get-size total は端末構成ごとの最小・最大ダウンロードサイズを返します。私はこの出力を削減前後で保存し、差分を記録するようにしました。数字が残っていると、次に同じ作業をするときの見積もりが一気に楽になります。

明日の一手をどこに置くか

バイナリサイズの削減は、一度で劇的に減らそうとするより、計測 → 画像 → バンドル → ネイティブ層の順で、各工程を 20〜40% ずつ削るつもりで進めた方が結果的に速く進みます。順番を守ると、どの施策がどれだけ効いたかが数字で分離できるからです。

明日やることを一つだけ挙げるなら、Xcode Organizer の App Size Report を開いて、自分のアプリの「いちばん重い一要素」を特定することです。画像が最重量なら WebP 変換で 3 桁 MB が動くこともありますし、ネイティブ層が重いなら ABI splits と AAB の方が先です。重い順から手を付ける、それだけで削減の速度はまるで変わります。

サイズが小さくなると、審査の警告が消えるだけでなく、低速回線のユーザーがインストールを途中で諦めなくなります。最初のダウンロードは、ユーザーがアプリに払う最初のコストです。そこを軽くしておくことは、まだ会っていない誰かへの小さな配慮だと思っています。

計測の数字が動いたら、ぜひその差分を記録に残してみてください。次の一本を作るときの、いちばん確かな見積もりになります。

シェア

お読みいただきありがとうございます

Rork Lab は広告なしで運営しており、サーバー費用などの運営コストはメンバーシップのご支援で賄っています。実装コード・ベンチマーク・本番設計パターンなど、実務でお役立ていただける記事を毎日更新しています。もし読んでよかったと感じていただけましたら、ぜひご覧ください。

  • コピー&ペーストで使える実装コード付き
  • 毎日新しい上級ガイドを追加
  • ¥580/月 または ¥1,480 の永久アクセス
メンバーシップを見る →

もしこの記事がお役に立ちましたら、チップ(¥150)で応援いただけると大変励みになります。広告なしでの運営を続けるため、皆さまのご支援が大きな力になっています。

関連記事

開発ツール2026-05-23
Rork 生成プロジェクト特有の expo start --offline forbidden — テンプレ構成が原因の4パターン
Rork が生成するテンプレート構成が原因で expo start --offline が forbidden になる4つのパターン(tsconfigPaths・expo-router キャッシュ・ネイティブプリビルド・lock 不一致)を、Rork プロジェクト固有の観点で切り分けます。汎用的な Expo 側の対処(プロキシ403・依存検証)は別記事にまとめています。
開発ツール2026-05-20
iOS の 0x8badf00d ウォッチドッグ強制終了に Rork アプリが落ちるときの対処
Rork で作った iOS アプリが起動直後に消える。クラッシュログに 0x8badf00d。Apple のウォッチドッグが React Native の重い初期化を切ったときの正しい直し方を、私の運用中アプリで実際に効いた手順で説明します。
開発ツール2026-05-05
Rork Max で App Store 審査を通すための実践ガイド
Rork Max で作成したアプリが App Store 審査で却下されやすい理由と、審査を通過するための具体的な対処法を解説。メタデータの最適化・プライバシーポリシー・アクセシビリティ・パフォーマンス要件まで実践的にまとめました。
📚RECOMMENDED BOOKS
大規模言語モデル入門
山田育矢
LLM開発
生成AIプロンプトエンジニアリング入門
我妻幸長
プロンプト
Claude CodeによるAI駆動開発入門
平川知秀
AI駆動開発
※ アフィリエイトリンクを含みます
もっと見る →