Slide 1

Slide 1 text

Build高 化 お話 Yahoo! JAPAN 森 洋之

Slide 2

Slide 2 text

No content

Slide 3

Slide 3 text

Make Your Build Great Again!

Slide 4

Slide 4 text

Jared Burrows Software Engineer @Microsoft Yammer for Android

Slide 5

Slide 5 text

Before After Reduction Time(min) 〜18+ 〜11 38.89%

Slide 6

Slide 6 text

ビルド 度 ために 最適化する対象

Slide 7

Slide 7 text

● ソフトウェア ○ Gradle ○ Android Gradle Plugin ○ Android Studio / IntelliJ ● ハードウェア ○ CPU ○ メモリ

Slide 8

Slide 8 text

No content

Slide 9

Slide 9 text

$4,999〜

Slide 10

Slide 10 text

探るべきも ● 遅くなっている原因 ● ボトルネックになっているタスク ● 不要な依存関係・プラグイン ● モジュール/build.gradle 構

Slide 11

Slide 11 text

スタート地点 ● 一番ベースとなっているところから手を付けていく

Slide 12

Slide 12 text

スタート地点 ● 一番ベースとなっているところから手を付けていく ● PCを変える、ビルドエージェントを見直すなど

Slide 13

Slide 13 text

スタート地点 ● 一番ベースとなっているところから手を付けていく ● PCを変える、ビルドエージェントを見直すなど ● Gradle 設定を最適化する

Slide 14

Slide 14 text

スタート地点 ● 一番ベースとなっているところから手を付けていく ● PCを変える、ビルドエージェントを見直すなど ● Gradle 設定を最適化する ● Android Gradle Plugin 設定を最適化する

Slide 15

Slide 15 text

スタート地点 ● 一番ベースとなっているところから手を付けていく ● PCを変える、ビルドエージェントを見直すなど ● Gradle 設定を最適化する ● Android Gradle Plugin 設定を最適化する ● Android Studio 設定を最適化する

Slide 16

Slide 16 text

Gradle 設定

Slide 17

Slide 17 text

基本

Slide 18

Slide 18 text

ソフトウェアを最新にする ● Gradle 4.3を使う

Slide 19

Slide 19 text

No content

Slide 20

Slide 20 text

ソフトウェアを最新にする ● Gradle 4.3を使う ● マイナーバージョン間 互換性を維持する

Slide 21

Slide 21 text

ソフトウェアを最新にする ● Gradle 4.3を使う ● マイナーバージョン間 互換性を維持する ● JVMも最新 も を使う

Slide 22

Slide 22 text

gradle.properties

Slide 23

Slide 23 text

Gradle daemonを有効にする ● Gradleを実行するたびに、新しいインスタンスを 立ち上げている ● デーモンを使用することで、ビルドごとにJVMを起動す るコストを避けられる ● 3.0〜 デフォルトで有効

Slide 24

Slide 24 text

gradle.properties org.gradle.daemon=true

Slide 25

Slide 25 text

daemon ヒープサイズを増やす ● デフォルトで 1GB ● Androidプロジェクト 、通常もっと使う ● AGP 2.1以上だと、”Dex in Process”に 最低2GB 必要 ● 大きなプロジェクトほど、メモリ 増設が効く

Slide 26

Slide 26 text

gradle.properties org.gradle.daemon=true

Slide 27

Slide 27 text

gradle.properties org.gradle.daemon=true org.gradle.jvmargs=-Xmx2048m

Slide 28

Slide 28 text

並列ビルドを有効にする ● Gradleタスク 並列実行 ビルド 度を くする ● モジュール分割されたプロジェクトで効果的 ● JavaCompileタスクを別プロセスで行うと良い ● テストタスクも別プロセスが良い

Slide 29

Slide 29 text

gradle.properties org.gradle.daemon=true org.gradle.jvmargs=-Xmx2048m

Slide 30

Slide 30 text

gradle.properties org.gradle.daemon=true org.gradle.jvmargs=-Xmx2048m org.gradle.parallel=true

Slide 31

Slide 31 text

Javaコンパイルタスクを分離する tasks.withType(JavaCompile) { options.fork = true }

Slide 32

Slide 32 text

テストタスクを分離する tasks.withType(Test) { def maxCount = gradle.startParameter.maxWorkerCount maxParallelForks = (maxCount < 2) ? 1 : maxCount / 2 forkEvery = 100 }

Slide 33

Slide 33 text

No content

Slide 34

Slide 34 text

Configure on Demandを有効にする ● 関係 あるモジュール/タスクで み Configurationを行う ● モジュール分割されたプロジェクトで効果的 ● こ 設定をしても、“subprojects”や”allprojects”で 設定を使うと無意味になる

Slide 35

Slide 35 text

gradle.properties org.gradle.daemon=true org.gradle.jvmargs=-Xmx2048m org.gradle.parallel=true

Slide 36

Slide 36 text

gradle.properties org.gradle.daemon=true org.gradle.jvmargs=-Xmx2048m org.gradle.parallel=true org.gradle.configureondemand=true

Slide 37

Slide 37 text

ビルドキャッシュを有効にする ● インクリメンタルビルドによって、 無駄な再ビルドを減らすことができる ● ブランチを変えたときにも効果的 ● 異なるビルドフレーバーをビルドする時に効果的

Slide 38

Slide 38 text

gradle.properties org.gradle.daemon=true org.gradle.jvmargs=-Xmx2048m org.gradle.parallel=true org.gradle.configureondemand=true

Slide 39

Slide 39 text

gradle.properties org.gradle.daemon=true org.gradle.jvmargs=-Xmx2048m org.gradle.parallel=true org.gradle.configureondemand=true org.gradle.caching=true

Slide 40

Slide 40 text

build.gradle

Slide 41

Slide 41 text

プラグイン 適用 よく考えて ● 必要なモジュールにだけプラグインを適用する ● “subprojects” / “allprojects”を使う 、 本当に実際に使用しているプラグインだけにする

Slide 42

Slide 42 text

参照するリポジトリを減らす よくあるやつ ● jcenter() ● mavenCentral() ● maven { url “https://plugins.gradle.org/m2/” } ● maven { url “https://maven.google.com” } ● maven { url “https://jitpack.io” }

Slide 43

Slide 43 text

参照するリポジトリを減らす repositories { jcenter() mavenCentral() maven { url “https://plugins.gradle.org/m2/” } google() maven { url “https://jitpack.io” } }

Slide 44

Slide 44 text

参照するリポジトリを減らす repositories { maven { url “https://plugins.gradle.org/m2/” } google() } // これでいけるかも?

Slide 45

Slide 45 text

動的バージョン指定 避ける(+) ● そもそも警告されていると思うが ● 意図しないアップデートが発生する ● バージョン比較 難しい ● 毎回バージョンチェックして遅くなる

Slide 46

Slide 46 text

動的バージョン指定 避ける(+) dependencies { // ダメ implementation ‘com.android.support:appcompat-v7:+’ }

Slide 47

Slide 47 text

最新 バージョンを探す goo.gl/qy5uJa プロジェクト 依存ライブラリ 、 最新バージョンを探してレポートするプラグイン

Slide 48

Slide 48 text

動的バージョン指定 避ける(+) こうすると ./gradlew dependencyUpdates -Drevision=release

Slide 49

Slide 49 text

動的バージョン指定 避ける(+) ------------------------------------------------------------ : Project Dependency Updates (report to plain text file) ------------------------------------------------------------ The following dependencies are using the latest release version: - com.android.support.test.espresso:espresso-core:3.0.1 - com.github.ben-manes:gradle-versions-plugin:0.17.0 - junit:junit:4.12 - com.android.support.test:runner:1.0.1 The following dependencies have later release versions: - com.android.support:appcompat-v7 [26.1.0 -> 27.0.1] - com.android.support.constraint:constraint-layout [1.0.2 -> 1.1.0-beta3] - com.android.tools.build:gradle [3.0.0 -> 3.1.0-alpha03] - org.jacoco:org.jacoco.agent [0.7.4.201502262128 -> 0.7.9] - org.jacoco:org.jacoco.ant [0.7.4.201502262128 -> 0.7.9]

Slide 50

Slide 50 text

動的バージョン指定 避ける(+) ------------------------------------------------------------ : Project Dependency Updates (report to plain text file) ------------------------------------------------------------ The following dependencies are using the latest release version: - com.android.support.test.espresso:espresso-core:3.0.1 - com.github.ben-manes:gradle-versions-plugin:0.17.0 - junit:junit:4.12 - com.android.support.test:runner:1.0.1 The following dependencies have later release versions: - com.android.support:appcompat-v7 [26.1.0 -> 27.0.1] - com.android.support.constraint:constraint-layout [1.0.2 -> 1.1.0-beta3] - com.android.tools.build:gradle [3.0.0 -> 3.1.0-alpha03] - org.jacoco:org.jacoco.agent [0.7.4.201502262128 -> 0.7.9] - org.jacoco:org.jacoco.ant [0.7.4.201502262128 -> 0.7.9]

Slide 51

Slide 51 text

動的バージョン指定 避ける(+) ------------------------------------------------------------ : Project Dependency Updates (report to plain text file) ------------------------------------------------------------ The following dependencies are using the latest release version: - com.android.support.test.espresso:espresso-core:3.0.1 - com.github.ben-manes:gradle-versions-plugin:0.17.0 - junit:junit:4.12 - com.android.support.test:runner:1.0.1 The following dependencies have later release versions: - com.android.support:appcompat-v7 [26.1.0 -> 27.0.1] - com.android.support.constraint:constraint-layout [1.0.2 -> 1.1.0-beta3] - com.android.tools.build:gradle [3.0.0 -> 3.1.0-alpha03] - org.jacoco:org.jacoco.agent [0.7.4.201502262128 -> 0.7.9] - org.jacoco:org.jacoco.ant [0.7.4.201502262128 -> 0.7.9]

Slide 52

Slide 52 text

不要な / 使用してないライブラリを避ける ● でかいライブラリ 避ける ● 同様 機能で、より軽量 ライブラリを使用する Jacksonより 、Gson / Moshiを選ぶ Guava 使わない ● 詳しく   goo.gl/miu6aV

Slide 53

Slide 53 text

インクリメンタルビルドを有効にする ● 修正したクラスと、それに依存するクラスだけ コンパイルする

Slide 54

Slide 54 text

インクリメンタルビルドを有効にする tasks.withType(JavaCompile) { options.fork = true }

Slide 55

Slide 55 text

インクリメンタルビルドを有効にする tasks.withType(JavaCompile) { options.incremental = true options.fork = true }

Slide 56

Slide 56 text

インクリメンタルビルドを有効にする ● AutoValue / Glide / Butterknife / Dagger等、 APTを行うライブラリ 、インクリメンタルビルドを無効 化する ● Android Gradle Plugin(AGP) 3.0〜 APTもサポートされている…?

Slide 57

Slide 57 text

No content

Slide 58

Slide 58 text

Android Gradle Plugin

Slide 59

Slide 59 text

ソフトウェアを最新にする ● AGP 3.0.0を使う ● SDK tools / platform toolsも最新 も を使う

Slide 60

Slide 60 text

不要なリソース コンパイルを避ける ● “resConfig”で、必要ないローカリゼーションを 除外することができる ● 自分 とこ 、日本語リソースしかないけど? →外部ライブラリ 、そうでもない で ?

Slide 61

Slide 61 text

不要なリソース コンパイルを避ける android { defaultConfig { resConfigs “ja” } } // 日本語だけ

Slide 62

Slide 62 text

不要なリソース コンパイルを避ける android { defaultConfig { resConfigs “ja”,”en” } } // 日本語と英語

Slide 63

Slide 63 text

定数を使う android { compileSdkVersion 27 buildToolsVersion “27.0.0” defaultConfig { applicationId “com.example.android.hmori.sample” versionCode new Date().format(“ddMMyyHHmm”).toInteger() versionName “1.0” minSdkVersion 19 targetSdkVersion 27 } }

Slide 64

Slide 64 text

定数を使う android { compileSdkVersion 27 buildToolsVersion “27.0.0” defaultConfig { applicationId “com.example.android.hmori.sample” versionCode new Date().format(“ddMMyyHHmm”).toInteger() versionName “1.0” minSdkVersion 19 targetSdkVersion 27 } }

Slide 65

Slide 65 text

定数を使う def isRelease = project.hasProperty(“release”) android { compileSdkVersion 27 buildToolsVersion “27.0.0” defaultConfig { applicationId “com.example.android.hmori.sample” versionCode isRelease ? new Date().format(“ddMMyyHHmm”).toInteger() : 1 versionName “1.0” minSdkVersion 19 targetSdkVersion 27 } }

Slide 66

Slide 66 text

ライブラリモジュールに分割する ● Gradle 修正したモジュールだけコンパイルする ● コンパイル結果 キャッシュされる ● モジュール分割 + “configurationOnDemand” + 並列ビルドが効果的

Slide 67

Slide 67 text

PNG crunchを無効にする ● PNGをWebPに変換できないなら、 PNG crunchを使う ● 無効にすることで、AGP ビルドごとにPNGを 再圧縮すること なくなる ● AGP 3.0.0〜、PNG crunch 、 ”debug”ビルド時に 、デフォルトで無効

Slide 68

Slide 68 text

PNG crunchを無効にする android { aaptOptions { cruncherEnabled = project.hasProperty(“ci”) } }

Slide 69

Slide 69 text

lagacyなmultidexを避ける ● minSdkVersion < 21 : legacyなmultidex ● minSdkVersion >= 21 : ネイティブでmultidexがサポートされている ● 開発時 み、minSdkVersionを21以上になるように すれ 、開発時 ビルドが くなる

Slide 70

Slide 70 text

lagacyなmultidexを避ける android { compileSdkVersion 27 buildToolsVersion “27.0.0” defaultConfig { applicationId “com.example.android.hmori.sample” versionCode 1 versionName “1.0” minSdkVersion 19 targetSdkVersion 27 } }

Slide 71

Slide 71 text

lagacyなmultidexを避ける android { compileSdkVersion 27 buildToolsVersion “27.0.0” defaultConfig { applicationId “com.example.android.hmori.sample” versionCode 1 versionName “1.0” minSdkVersion rootProject.hasProperty(“lollipop”) ? 21 : 19 targetSdkVersion 27 } }

Slide 72

Slide 72 text

CIで pre-dexライブラリを無効化する ● pre-dex インクリメンタルビルドで 効果的 ● CIでクリーンビルドするときに 無駄

Slide 73

Slide 73 text

CIで pre-dexライブラリを無効化する android { dexOptions { preDexLibraries = !project.hasProperty(“ci”) } }

Slide 74

Slide 74 text

ビルドキャッシュを有効にする ● AGP 幾つか 生成物をキャッシュする ● AGP 2.3.0〜 デフォルトで有効

Slide 75

Slide 75 text

gradle.properties # Gradle specific org.gradle.daemon=true org.gradle.jvmargs=-Xmx2048m org.gradle.parallel=true org.gradle.configureondemand=true org.gradle.caching=true

Slide 76

Slide 76 text

gradle.properties # Gradle specific org.gradle.daemon=true org.gradle.jvmargs=-Xmx2048m org.gradle.parallel=true org.gradle.configureondemand=true org.gradle.caching=true # Android specific android.enableBuildCache=true

Slide 77

Slide 77 text

新しいDEXコンパイラを有効にする ● DEXコンパイラ 、.class → .dexに変換する ● D8 より早く.dexファイルに変換する。 ● しかも生成物 より小さくなる ● しかも実行時パフォーマンスも改善する ● AGP 3.1.0〜デフォルトで有効

Slide 78

Slide 78 text

gradle.properties # Gradle specific org.gradle.daemon=true org.gradle.jvmargs=-Xmx2048m org.gradle.parallel=true org.gradle.configureondemand=true org.gradle.caching=true # Android specific android.enableBuildCache=true

Slide 79

Slide 79 text

gradle.properties # Gradle specific org.gradle.daemon=true org.gradle.jvmargs=-Xmx2048m org.gradle.parallel=true org.gradle.configureondemand=true org.gradle.caching=true # Android specific android.enableBuildCache=true android.enableD8=true

Slide 80

Slide 80 text

Android Studio 設定

Slide 81

Slide 81 text

画像をWebPにする ● WebPにすることで、画像サイズを削減できる ● ビルド時にやる必要 ない ● ビルド前にやっておくことで、 ビルド時間 改善される

Slide 82

Slide 82 text

画像をWebPにする ● “drawable”フォルダを右クリック

Slide 83

Slide 83 text

Instant Runを有効にする ● 一定 コード追加やリソース修正で、 新しくAPKファイルを作成せずに実行できる ● 特定 場合に 、アクティビティ 再起動さえ いらない

Slide 84

Slide 84 text

offline modeを有効にする ● dependencyやプラグインを頻繁に更新しない な ら、offline modeで更新チェックを外すといい ● ./gradlew --offline

Slide 85

Slide 85 text

offline modeを有効にする ● Preferences ”Build, Execution, Deployment”

Slide 86

Slide 86 text

Profiling Your Build

Slide 87

Slide 87 text

ビルドプロセスをプロファイルする ● “gradlew --profile” ● “gradlew --scan”(goo.gl/UT1Qtb) ● そ 他: https://github.com/gradle/gradle-profiler

Slide 88

Slide 88 text

ビルドプロセスをプロファイルする ● “gradlew clean assembleDebug --profile”

Slide 89

Slide 89 text

ビルドプロセスをプロファイルする ● “gradlew clean assembleDebug --scan”

Slide 90

Slide 90 text

ビルドプロセスをプロファイルする

Slide 91

Slide 91 text

結果

Slide 92

Slide 92 text

1回目 2回目 3回目 4回目 5回目 Before 2 min 37.376 sec 1 min 43.3 sec 1 min 39.9 sec 1 min 37.8 sec 1 min 40.8 sec After 1 min 29 sec 1 min 11 sec 47 sec 46 sec 45 sec

Slide 93

Slide 93 text

No content