RORK LABEN
R8 — Expo SDK 58 から、Android のリリースビルドで R8 が既定で有効になります。同じコードで前後を測っておくと、縮んだ分と壊れた箇所が見えますXCODE26.6 — EAS Build の Xcode 27 イメージはまだ準備中で、latest はいまも Xcode 26.6 です。手元の Xcode を 27 に上げているかどうかで、踏む不具合が変わります11/01 — Google Play の target API level の延長申請は11月1日までです。残り40日。新規と更新は API 36 以上、既存アプリは API 35 以上が要りますFETCH — expo/fetch が iOS では応答を返さないまま止まり、Android では切り詰めた本文を 200 のまま返すという報告です。例外が飛ばないため、タイムアウトは自分で被せる形になりますNEW — exit code 0 で止まるビルド — ログを黙らせていた設定と、空ファイルを通した存在チェックSCENE — SDK 57 のまま Xcode 27 で起動させるための opt-in が expo@57.0.23 に入りました。expo-build-properties の ios.enableSceneSupport で有効にしますR8 — Expo SDK 58 から、Android のリリースビルドで R8 が既定で有効になります。同じコードで前後を測っておくと、縮んだ分と壊れた箇所が見えますXCODE26.6 — EAS Build の Xcode 27 イメージはまだ準備中で、latest はいまも Xcode 26.6 です。手元の Xcode を 27 に上げているかどうかで、踏む不具合が変わります11/01 — Google Play の target API level の延長申請は11月1日までです。残り40日。新規と更新は API 36 以上、既存アプリは API 35 以上が要りますFETCH — expo/fetch が iOS では応答を返さないまま止まり、Android では切り詰めた本文を 200 のまま返すという報告です。例外が飛ばないため、タイムアウトは自分で被せる形になりますNEW — exit code 0 で止まるビルド — ログを黙らせていた設定と、空ファイルを通した存在チェックSCENE — SDK 57 のまま Xcode 27 で起動させるための opt-in が expo@57.0.23 に入りました。expo-build-properties の ios.enableSceneSupport で有効にします
記事一覧/開発ツール
開発ツール/2026-09-22中級

R8 が既定になる前に測っておく4つの数字 — Expo SDK 58 を待つあいだの Android 計測メモ

Expo SDK 58 では Android のリリースビルドで R8 が既定で有効になります。有効化の前後を同じ物差しで比べられるよう、AAB のダウンロードサイズ・DEX 合計・コールドスタート・ビルド時間の4つを測って残す手順をまとめます。

Expo211Android51R82計測3SDK 58

SDK 58 のベータ告知を読み返していた夜、Android の節で手が止まりました。リリースビルドで R8 が既定で有効になる、と短く書いてあります。

思い出したのは、前に SDK を大きく上げたときのことです。上げたあとのアプリは少し軽くなったように見えたのですが、それが新しいビルド設定のおかげなのか、同じ週に自分が差し替えた画像のおかげなのか、いまでも説明できません。上げる前の数字を、一つも残していなかったからです。

上げる前の数字は、上げる前にしか取れません。 ベータ期間が続いているいまは、手元の Expo プロジェクトで現在値を記録しておく、ちょうどいい時期なのだと思います。

この記事は、Rork から書き出した Expo プロジェクトを手元でビルドしている方に向けて書きます。新規プロジェクトが Swift と Kotlin に寄った後も、既に動いている Expo のアプリは引き続きビルドできますので、上げる前の計測はそのまま意味を持ちます。

SDK 58 で既定になるのは何か

Expo SDK 58 Beta のリリースノート によれば、Android のリリースビルドで android.enableMinifyInReleaseBuilds=true が既定になります。R8 が Java と Kotlin のコードを縮め、最適化し、難読化します。プリセットは proguard-android-optimize.txt です。

押さえておきたい点は三つです。

  • リフレクションに依存するライブラリは keep ルールが要ることがあります
  • 外したいときは expo-build-propertiesenableMinifyInReleaseBuildsfalse にできます
  • 効き方はアプリごとに違いますので、一般論の削減率より自分の数字のほうが役に立ちます

安定版の日付は、いまのところ一次情報に書かれておりません。ベータは 2026-09-15 に始まり、公式には「三〜四週間」と、そして React Native 0.88 の公開後に安定版へ移る、とだけ記されています。日付が決まってから慌てるより、決まっていないあいだに測っておくほうが穏やかです。

測る数字を4つに絞りました

最初のうち、私は測れるものを片端から並べようとしました。メモリ、フレーム落ち、APK 内のリソース内訳——項目が増えるほど、二度目の計測を同じ条件で踏めなくなりました。結果は芳しくありませんでした。

いまは4つに絞っています。R8 が直接動かす対象と、動かした結果が読者に届く場所だけです。

数字どこで取るか単位注意
ダウンロードサイズbundletool get-size totalバイトAAB のファイルサイズではなく、端末が実際に落とす量を見ます
DEX の合計AAB 内の classes*.dexバイトR8 が縮めるのは主にここですので、差が最も素直に出ます
コールドスタートam start-activity -W の TotalTimeミリ秒1回では揺れますので、中央値で見ます
リリースビルドの所要time ./gradlew :app:bundleReleaseR8 を通す分だけ伸びます。CI の見積もりに効きます

ダウンロードサイズと DEX を両方取るのは、片方だけでは誤読するからです。DEX が縮んでもネイティブライブラリや画像が支配的なアプリでは、利用者から見た差はほとんどありません。サイズの内訳そのものを詰めたい場合は、Rork アプリのバイナリサイズが 150MB を超えた時に切り分ける 5 つの要因と実践的な削減手順 のほうが近い話をしています。

前提を固定してから、同じ手順を二度踏みます

比較を壊すのは、たいてい計測の腕ではなく前提のずれです。私は次の4点だけメモに書いてから始めます。同じコミット、同じ実機、同じ JDK と Gradle、そして versionCode も触らないこと。片方だけ CI で、もう片方を手元で取ると、それだけで比べられなくなります。

有効化は SDK 57 のままでも試せます。プラグインの設定を一行足すだけです。

{
  "expo": {
    "plugins": [
      ["expo-build-properties", { "android": { "enableMinifyInReleaseBuilds": true } }]
    ]
  }
}

ビルドとサイズの取得は、この順に回します。

# 1 回目は現在値(プラグイン設定なし)、2 回目は有効化した状態で、同じコミットから
npx expo prebuild -p android --clean
cd android
./gradlew clean
time ./gradlew :app:bundleRelease
 
AAB=app/build/outputs/bundle/release/app-release.aab
ls -l "$AAB"
unzip -l "$AAB" | grep '\.dex'

ダウンロードサイズは、AAB のファイルサイズとは別物です。bundletool に署名鍵を渡して、端末ごとの配信サイズを出します。

bundletool build-apks \
  --bundle=app/build/outputs/bundle/release/app-release.aab \
  --output=/tmp/app.apks \
  --ks=$HOME/keystores/release.jks \
  --ks-key-alias=YOUR_KEY_ALIAS
 
bundletool get-size total --apks=/tmp/app.apks --dimensions=SDK,ABI

コールドスタートは、揺れをそのまま受け取らないことが大事です。最初の2回は端末側のキャッシュが温まる途中ですので捨て、残り8回の中央値を採ります。

#!/usr/bin/env bash
# 10 回起動して、最初の 2 回を捨て、TotalTime の中央値を出します
ACT="com.example.app/.MainActivity"
 
for i in $(seq 1 10); do
  adb shell am start-activity -W -S -n "$ACT" \
    | awk -F': ' '/TotalTime/ {print $2}'
  sleep 3
done | tail -n 8 | sort -n | awk '{a[NR]=$1}
  END {print "median=" (NR % 2 ? a[(NR + 1) / 2] : (a[NR / 2] + a[NR / 2 + 1]) / 2)}'

-S は起動前にアプリを止めるための指定で、これがないと二度目以降が温かい起動になります。私はここを忘れて、有効化のおかげで速くなったと早合点しかけました。

数字が動いたとき、どこを見るか

R8 が縮めるのは DEX ですので、差は DEX の合計にいちばん素直に出ます。ダウンロードサイズの差がそれより小さいときは、アプリの重さが画像や音源やネイティブライブラリの側にあるということです。私の壁紙アプリはまさにその形で、縮んだ絶対量より「どこが支配的か」が分かったことのほうが後で効きました。

起動時間は、変わらないこともあります。むしろ、変わらないと分かっていること自体が資産です。次に誰かが「R8 で速くなるらしい」と言ったとき、自分の数字で穏やかに返せます。

気をつけたいのは、壊れ方がリリースビルドでしか出ない点です。開発ビルドで動いたことは何の保証にもなりません。リフレクションでクラス名や型情報を読むライブラリ、アノテーション処理に頼る層、ネイティブモジュールの名前解決あたりが最初に転びます。落ちたクラスを keep ルールで救う手順は、リリースビルドだけ落ちる — Expo(Android) で R8 が剥がしたクラスを keep ルールで救う にまとめてあります。

# android/app/proguard-rules.pro — 反射でクラス名を解決している層だけを残します
-keep class com.example.model.** { *; }
-keepattributes Signature, *Annotation*, InnerClasses

もう一つ、難読化されたスタックトレースを読み戻すための mapping.txt は、ビルドのたびに出ます。

ls -l android/app/build/outputs/mapping/release/mapping.txt

これを保管し損ねると、本番のクラッシュが記号のまま届きます。ビルドの成果物と同じ場所に置き、バージョンごとに残しておくと後で助かります。仕組みそのものは Android のコード圧縮のドキュメント が詳しく書いています。

記録は1枚の表に残します

数字は、取ったその日に表へ落とさないと消えます。私はリポジトリの中に docs/ を掘って、テキスト1枚で残すようにしております。凝った形式にしないことが、続ける唯一のこつなのかもしれません。

項目有効化前有効化後
ダウンロードサイズ(最大)(記入)(記入)(記入)
DEX 合計(記入)(記入)(記入)
コールドスタート中央値(記入)(記入)(記入)
bundleRelease 所要(記入)(記入)(記入)
実機で触って気づいたこと(記入)

末尾の一行を空けておくのは、数字が説明してくれないことを書くためです。起動直後の一瞬だけ白い、通知のタップから開くと遅い——そういう観察は、あとで数字の意味を決め直してくれます。

安定版が出てから測り直すとき、この表があるかないかで、言えることがまるで変わります。今週のうちに一度だけ ./gradlew clean :app:bundleRelease を回して、AAB のサイズと DEX の合計だけでもテキストに書き出していただければと思います。二つなら、10分ほどで終わります。

ここまでお読みいただき、ありがとうございました。

シェア

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

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

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

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

関連記事

開発ツール2026-09-10
画面を暗くする機能を足したら、アプリを閉じたあとも iPhone が暗いままでした
expo-brightness の setBrightnessAsync は、Android では現在のアクティビティにだけ効き、iOS では端末の明るさそのものを変えます。戻す責任が片側にしかない理由と、AppState で後始末をするフックの実装をまとめました。
開発ツール2026-08-31
画面ロックから3分後、expo-audio の環境音は静かに止まっていました
expo-audio の音が画面ロックで止まる原因を、ビルド設定・オーディオセッション・ロック画面連携の三層に分けて切り分けます。Android で約3分後に止まるのは、ドキュメントに書かれた止まり方です。
開発ツール2026-08-21
生成ループが緑を返した後に、私が手元で回している4つの受け入れ検査
ビルドが成功しても出荷できない状態は実在します。AI がビルドを反復する構成で見落とされやすい4点を、成果物そのものを走査する検査スクリプトとして手元に置く方法をまとめました。
📚RECOMMENDED BOOKS
大規模言語モデル入門
山田育矢
LLM開発
生成AIプロンプトエンジニアリング入門
我妻幸長
プロンプト
Claude CodeによるAI駆動開発入門
平川知秀
AI駆動開発
※ アフィリエイトリンクを含みます