Slide 1

Slide 1 text

Diffusing Changes in Your APK @JakeWharton

Slide 2

Slide 2 text

2½ years ago…

Slide 3

Slide 3 text

jakes.link/hidden-changes

Slide 4

Slide 4 text

No content

Slide 5

Slide 5 text

No content

Slide 6

Slide 6 text

No content

Slide 7

Slide 7 text

No content

Slide 8

Slide 8 text

No content

Slide 9

Slide 9 text

6 months ago…

Slide 10

Slide 10 text

Analysis Files

Slide 11

Slide 11 text

Files Analysis

Slide 12

Slide 12 text

ApkDiffStats:WhateverReleaseApp ApkDiffStats:WhateverDebugApp + + Files Analysis

Slide 13

Slide 13 text

ApkDiffStats:WhateverDebugApp + Files Analysis + ApkDiffStats:WhateverReleaseApp

Slide 14

Slide 14 text

ApkDiffStats:WhateverReleaseApp - Analyze the difference between two APK versions. Analyzer description: ApkDiffStats:WhateverReleaseApp WhateverApp.apk : 0 B (25.1 MiB → 25.1 MiB) Verbose diff: http://internal-thing/android-apk-analysis/diffstats/results/cl-123456789:9:WhateverRelease App/WhateverApp.diff.txt Code: compressed delta : -28 B (4.7 MiB → 4.7 MiB) uncompressed delta : +1.6 KiB (10.6 MiB → 10.6 MiB) Resources: compressed delta : 0 B (16.3 MiB → 16.3 MiB) uncompressed delta : 0 B (18.5 MiB → 18.5 MiB) Files/Assets: compressed delta : 0 B (2.1 MiB → 2.1 MiB) uncompressed delta : 0 B (4.9 MiB → 4.9 MiB) Native: compressed delta : 0 B (1.3 MiB → 1.3 MiB) uncompressed delta : 0 B (3.5 MiB → 3.5 MiB) strings : +62 (26,806 → 26,868) types : +15 (21,548 → 21,563) fields : +7 (53,443 → 53,450) methods : -17 (70,530 → 70,513) classes : -3 (16,305 → 16,302) Test links: Base build : ... Pending build : ... Scan Options: alert_reviewer=someone percentage_apk_alert=1% label=WhateverReleaseApp target=//java/com/google/android/apps/whatever/app:WhateverApp go/some-link-here ApkDiffStats:WhateverDebugApp +

Slide 15

Slide 15 text

ApkDiffStats:WhateverReleaseApp - Analyze the difference between two APK versions. Analyzer description: ApkDiffStats:WhateverReleaseApp WhateverApp.apk : 0 B (25.1 MiB → 25.1 MiB) Verbose diff: http://internal-thing/android-apk-analysis/diffstats/results/cl-123456789:9:WhateverRelease App/WhateverApp.diff.txt Code: compressed delta : -28 B (4.7 MiB → 4.7 MiB) uncompressed delta : +1.6 KiB (10.6 MiB → 10.6 MiB) Resources: compressed delta : 0 B (16.3 MiB → 16.3 MiB) uncompressed delta : 0 B (18.5 MiB → 18.5 MiB) Files/Assets: compressed delta : 0 B (2.1 MiB → 2.1 MiB) uncompressed delta : 0 B (4.9 MiB → 4.9 MiB) Native: compressed delta : 0 B (1.3 MiB → 1.3 MiB) uncompressed delta : 0 B (3.5 MiB → 3.5 MiB) strings : +62 (26,806 → 26,868) types : +15 (21,548 → 21,563) fields : +7 (53,443 → 53,450) methods : -17 (70,530 → 70,513) classes : -3 (16,305 → 16,302) Test links: Base build : ... Pending build : ... Scan Options: alert_reviewer=someone percentage_apk_alert=1% label=WhateverReleaseApp target=//java/com/google/android/apps/whatever/app:WhateverApp go/some-link-here ApkDiffStats:WhateverDebugApp + Verbose diff: http://internal-thing/android-apk-analysis/diffstats/results/cl-123456789:9:WhateverRelease App/WhateverApp.diff.txt

Slide 16

Slide 16 text

No content

Slide 17

Slide 17 text

No content

Slide 18

Slide 18 text

Present day

Slide 19

Slide 19 text

$ diffuse diff sdk-search-release-1.apk sdk-search-release-2.apk

Slide 20

Slide 20 text

$ diffuse diff sdk-search-release-1.apk sdk-search-release-2.apk OLD: sdk-search-release-1.apk (signature: V2) NEW: sdk-search-release-2.apk (signature: V2) │ compressed │ uncompressed ├───────────┬───────────┬───────┼───────────┬───────────┬──────── APK │ old │ new │ diff │ old │ new │ diff ──────────┼───────────┼───────────┼───────┼───────────┼───────────┼──────── dex │ 664.8 KiB │ 664.8 KiB │ -25 B │ 1.5 MiB │ 1.5 MiB │ -112 B arsc │ 201.7 KiB │ 201.7 KiB │ 0 B │ 201.6 KiB │ 201.6 KiB │ 0 B manifest │ 1.4 KiB │ 1.4 KiB │ 0 B │ 4.2 KiB │ 4.2 KiB │ 0 B res │ 418.2 KiB │ 418.2 KiB │ -14 B │ 488.3 KiB │ 488.3 KiB │ 0 B asset │ 0 B │ 0 B │ 0 B │ 0 B │ 0 B │ 0 B other │ 37.1 KiB │ 37.1 KiB │ 0 B │ 36.3 KiB │ 36.3 KiB │ 0 B ──────────┼───────────┼───────────┼───────┼───────────┼───────────┼──────── total │ 1.3 MiB │ 1.3 MiB │ -39 B │ 2.2 MiB │ 2.2 MiB │ -112 B DEX │ old │ new │ diff ─────────┼───────┼───────┼────────────

Slide 21

Slide 21 text

$ diffuse diff sdk-search-release-1.apk sdk-search-release-2.apk OLD: sdk-search-release-1.apk (signature: V2) NEW: sdk-search-release-2.apk (signature: V2) │ compressed │ uncompressed ├───────────┬───────────┬───────┼───────────┬───────────┬──────── APK │ old │ new │ diff │ old │ new │ diff ──────────┼───────────┼───────────┼───────┼───────────┼───────────┼──────── dex │ 664.8 KiB │ 664.8 KiB │ -25 B │ 1.5 MiB │ 1.5 MiB │ -112 B arsc │ 201.7 KiB │ 201.7 KiB │ 0 B │ 201.6 KiB │ 201.6 KiB │ 0 B manifest │ 1.4 KiB │ 1.4 KiB │ 0 B │ 4.2 KiB │ 4.2 KiB │ 0 B res │ 418.2 KiB │ 418.2 KiB │ -14 B │ 488.3 KiB │ 488.3 KiB │ 0 B asset │ 0 B │ 0 B │ 0 B │ 0 B │ 0 B │ 0 B other │ 37.1 KiB │ 37.1 KiB │ 0 B │ 36.3 KiB │ 36.3 KiB │ 0 B ──────────┼───────────┼───────────┼───────┼───────────┼───────────┼──────── total │ 1.3 MiB │ 1.3 MiB │ -39 B │ 2.2 MiB │ 2.2 MiB │ -112 B DEX │ old │ new │ diff ─────────┼───────┼───────┼────────────

Slide 22

Slide 22 text

$ diffuse diff sdk-search-release-1.apk sdk-search-release-2.apk OLD: sdk-search-release-1.apk (signature: V2) NEW: sdk-search-release-2.apk (signature: V2) │ compressed │ uncompressed ├───────────┬───────────┬───────┼───────────┬───────────┬──────── APK │ old │ new │ diff │ old │ new │ diff ──────────┼───────────┼───────────┼───────┼───────────┼───────────┼──────── dex │ 664.8 KiB │ 664.8 KiB │ -25 B │ 1.5 MiB │ 1.5 MiB │ -112 B arsc │ 201.7 KiB │ 201.7 KiB │ 0 B │ 201.6 KiB │ 201.6 KiB │ 0 B manifest │ 1.4 KiB │ 1.4 KiB │ 0 B │ 4.2 KiB │ 4.2 KiB │ 0 B res │ 418.2 KiB │ 418.2 KiB │ -14 B │ 488.3 KiB │ 488.3 KiB │ 0 B asset │ 0 B │ 0 B │ 0 B │ 0 B │ 0 B │ 0 B other │ 37.1 KiB │ 37.1 KiB │ 0 B │ 36.3 KiB │ 36.3 KiB │ 0 B ──────────┼───────────┼───────────┼───────┼───────────┼───────────┼──────── total │ 1.3 MiB │ 1.3 MiB │ -39 B │ 2.2 MiB │ 2.2 MiB │ -112 B DEX │ old │ new │ diff ─────────┼───────┼───────┼──────────── count │ 1 │ 1 │ 0 strings │ 14220 │ 14218 │ -2 (+6 -8)

Slide 23

Slide 23 text

asset │ 0 B │ 0 B │ 0 B │ 0 B │ 0 B │ 0 B other │ 37.1 KiB │ 37.1 KiB │ 0 B │ 36.3 KiB │ 36.3 KiB │ 0 B ──────────┼───────────┼───────────┼───────┼───────────┼───────────┼──────── total │ 1.3 MiB │ 1.3 MiB │ -39 B │ 2.2 MiB │ 2.2 MiB │ -112 B DEX │ old │ new │ diff ─────────┼───────┼───────┼──────────── count │ 1 │ 1 │ 0 strings │ 14220 │ 14218 │ -2 (+6 -8) types │ 2258 │ 2257 │ -1 (+0 -1) classes │ 1580 │ 1579 │ -1 (+0 -1) methods │ 11640 │ 11641 │ +1 (+6 -5) fields │ 4369 │ 4369 │ 0 (+0 -0) ARSC │ old │ new │ diff ─────────┼──────┼──────┼────── configs │ 51 │ 51 │ 0 entries │ 1950 │ 1950 │ 0 ================= ==== APK ====

Slide 24

Slide 24 text

strings │ 14220 │ 14218 │ -2 (+6 -8) types │ 2258 │ 2257 │ -1 (+0 -1) classes │ 1580 │ 1579 │ -1 (+0 -1) methods │ 11640 │ 11641 │ +1 (+6 -5) fields │ 4369 │ 4369 │ 0 (+0 -0) ARSC │ old │ new │ diff ─────────┼──────┼──────┼────── configs │ 51 │ 51 │ 0 entries │ 1950 │ 1950 │ 0 ================= ==== APK ==== ================= compressed │ uncompressed │ ───────────┬───────┼─────────┬────────┤ size │ diff │ size │ diff │ path ───────────┼───────┼─────────┼────────┼───────────────────────────────────────── 664.8 KiB │ -25 B │ 1.5 MiB │ -112 B │ ∆ classes.dex 458 B │ -14 B │ 272 B │ 0 B │ ∆ res/drawable-hdpi-v4/abc_ab_share_pack ───────────┼───────┼─────────┼────────┼───────────────────────────────────────── 665.2 KiB │ -39 B │ 1.5 MiB │ -112 B │ (total)

Slide 25

Slide 25 text

ARSC │ old │ new │ diff ─────────┼──────┼──────┼────── configs │ 51 │ 51 │ 0 entries │ 1950 │ 1950 │ 0 ================= ==== APK ==== ================= compressed │ uncompressed │ ───────────┬───────┼─────────┬────────┤ size │ diff │ size │ diff │ path ───────────┼───────┼─────────┼────────┼─────────────────────────────────────────────────────────── 664.8 KiB │ -25 B │ 1.5 MiB │ -112 B │ ∆ classes.dex 458 B │ -14 B │ 272 B │ 0 B │ ∆ res/drawable-hdpi-v4/abc_ab_share_pack_mtrl_alpha.9.png ───────────┼───────┼─────────┼────────┼─────────────────────────────────────────────────────────── 665.2 KiB │ -39 B │ 1.5 MiB │ -112 B │ (total) ================= ==== DEX ==== ================= STRINGS: old │ new │ diff ───────┼───────┼──────────── 14220 │ 14218 │ -2 (+6 -8)

Slide 26

Slide 26 text

================= ==== DEX ==== ================= STRINGS: old │ new │ diff ───────┼───────┼──────────── 14220 │ 14218 │ -2 (+6 -8) + %s does not implement %s + %s.androidInjector() returned null + androidInjector + b1b69b7d0f149276095d82b6e0b884f82ac4d3f4 + getAndroidInjector + ~~R8{"compilation-mode":"release","min-api":24,"pg-map-id":"5362c3b","version":"1.5.59"} - %s does not implement %s or %s - %s.activityInjector() returned null - 0e95da1111e6daf6172ec76c544c88764db28334 - HasActivityInjector.java - Ldagger/android/HasActivityInjector; - activityInjector - getActivityInjector - ~~R8{"compilation-mode":"release","min-api":24,"pg-map-id":"3041c7f","version":"1.5.59"} TYPES:

Slide 27

Slide 27 text

- %s.activityInjector() returned null - 0e95da1111e6daf6172ec76c544c88764db28334 - HasActivityInjector.java - Ldagger/android/HasActivityInjector; - activityInjector - getActivityInjector - ~~R8{"compilation-mode":"release","min-api":24,"pg-map-id":"3041c7f","version":"1.5.59"} TYPES: old │ new │ diff ──────┼──────┼──────────── 2258 │ 2257 │ -1 (+0 -1) - Ldagger/android/HasActivityInjector; METHODS: old │ new │ diff ───────┼───────┼──────────── 11640 │ 11641 │ +1 (+6 -5) + com.jakewharton.sdksearch.AppComponent getAndroidInjector() → DispatchingAndroidInjector + com.jakewharton.sdksearch.DaggerReleaseAppComponent getAndroidInjector() → DispatchingAndroidInje + com.jakewharton.sdksearch.SdkSearchApplication androidInjector() → AndroidInjector + com.jakewharton.sdksearch.SdkSearchApplication androidInjector() → DispatchingAndroidInjector + dagger.android.AndroidInjection inject(Object, HasAndroidInjector) + dagger.android.HasAndroidInjector androidInjector() → AndroidInjector

Slide 28

Slide 28 text

old │ new │ diff ──────┼──────┼──────────── 2258 │ 2257 │ -1 (+0 -1) - Ldagger/android/HasActivityInjector; METHODS: old │ new │ diff ───────┼───────┼──────────── 11640 │ 11641 │ +1 (+6 -5) + com.jakewharton.sdksearch.AppComponent getAndroidInjector() → DispatchingAndroidInjector + com.jakewharton.sdksearch.DaggerReleaseAppComponent getAndroidInjector() → DispatchingAndroidInjector + com.jakewharton.sdksearch.SdkSearchApplication androidInjector() → AndroidInjector + com.jakewharton.sdksearch.SdkSearchApplication androidInjector() → DispatchingAndroidInjector + dagger.android.AndroidInjection inject(Object, HasAndroidInjector) + dagger.android.HasAndroidInjector androidInjector() → AndroidInjector - com.jakewharton.sdksearch.AppComponent getActivityInjector() → DispatchingAndroidInjector - com.jakewharton.sdksearch.DaggerReleaseAppComponent getActivityInjector() → DispatchingAndroidInjector - com.jakewharton.sdksearch.SdkSearchApplication activityInjector() → AndroidInjector - com.jakewharton.sdksearch.SdkSearchApplication activityInjector() → DispatchingAndroidInjector - dagger.android.HasActivityInjector activityInjector() → AndroidInjector

Slide 29

Slide 29 text

Why?

Slide 30

Slide 30 text

$2.79 vs. $2.99

Slide 31

Slide 31 text

$2.79 vs. $2.99 METHODS: old │ new │ diff ─────┼─────┼────────────── 279 │ 299 │ +20 (+25 -5)

Slide 32

Slide 32 text

$2.79 vs. $2.99 METHODS: old │ new │ diff ─────┼─────┼────────────── 279 │ 299 │ +20 (+25 -5) $2.79 vs. $27.99 METHODS: old │ new │ diff ─────┼──────┼──────────────────── 279 │ 2799 │ +2520 (+2674 -154)

Slide 33

Slide 33 text

jakes.link/generated-economics

Slide 34

Slide 34 text

jakes.link/generated-economics

Slide 35

Slide 35 text

jakes.link/dex-ed

Slide 36

Slide 36 text

dependencies { implementation 'com.squareup.moshi:moshi:1.8.0' }

Slide 37

Slide 37 text

dependencies { - implementation 'com.squareup.moshi:moshi:1.8.0' + implementation 'com.squareup.moshi:moshi:1.9.0' }

Slide 38

Slide 38 text

dependencies { - implementation 'com.squareup.moshi:moshi:1.8.0' + implementation 'com.squareup.moshi:moshi:1.9.0' } STRINGS: old │ new │ diff ───────┼───────┼────────────────── 80383 │ 79444 │ -939 (+91 -1030)

Slide 39

Slide 39 text

STRINGS: old │ new │ diff ───────┼───────┼────────────────── 80383 │ 79444 │ -939 (+91 -1030) + Non-null value '%s' was null at %s + Required value '%s' missing at %s ⋮ - Non-null value 'minFraction' was null at - Non-null value 'minHeight' was null at - Non-null value 'stampName' was null at - Non-null value 'status' was null at - Non-null value 'token' was null at - Non-null value 'transformation' was null at - Required property 'minFraction' missing at - Required property 'minHeight' missing at - Required property 'stampName' missing at - Required property 'status' missing at - Required property 'token' missing at

Slide 40

Slide 40 text

OLD: cashapp-moshi-1.8.apk (signature: none) NEW: cashapp-moshi-1.9.apk (signature: none) │ compressed │ uncompressed ├───────────┬───────────┬───────────┼───────────┬───────────┬──────────── APK │ old │ new │ diff │ old │ new │ diff ──────────┼───────────┼───────────┼───────────┼───────────┼───────────┼──────────── dex │ 4.9 MiB │ 4.8 MiB │ -73.3 KiB │ 12.9 MiB │ 12.6 MiB │ -260.5 KiB arsc │ 618.1 KiB │ 618.1 KiB │ 0 B │ 618 KiB │ 618 KiB │ 0 B manifest │ 4.5 KiB │ 4.5 KiB │ +3 B │ 21.5 KiB │ 21.5 KiB │ 0 B res │ 6.5 MiB │ 6.5 MiB │ +14 B │ 7.6 MiB │ 7.6 MiB │ 0 B native │ 3.4 MiB │ 3.4 MiB │ 0 B │ 8.3 MiB │ 8.3 MiB │ 0 B asset │ 0 B │ 0 B │ 0 B │ 0 B │ 0 B │ 0 B other │ 277.7 KiB │ 277.7 KiB │ 0 B │ 331.7 KiB │ 331.7 KiB │ 0 B ──────────┼───────────┼───────────┼───────────┼───────────┼───────────┼──────────── total │ 15.7 MiB │ 15.6 MiB │ -73.2 KiB │ 29.7 MiB │ 29.4 MiB │ -260.5 KiB

Slide 41

Slide 41 text

OLD: cashapp-moshi-1.8.apk (signature: none) NEW: cashapp-moshi-1.9.apk (signature: none) │ compressed │ uncompressed ├───────────┬───────────┬───────────┼───────────┬───────────┬──────────── APK │ old │ new │ diff │ old │ new │ diff ──────────┼───────────┼───────────┼───────────┼───────────┼───────────┼──────────── dex │ 4.9 MiB │ 4.8 MiB │ -73.3 KiB │ 12.9 MiB │ 12.6 MiB │ -260.5 KiB arsc │ 618.1 KiB │ 618.1 KiB │ 0 B │ 618 KiB │ 618 KiB │ 0 B manifest │ 4.5 KiB │ 4.5 KiB │ +3 B │ 21.5 KiB │ 21.5 KiB │ 0 B res │ 6.5 MiB │ 6.5 MiB │ +14 B │ 7.6 MiB │ 7.6 MiB │ 0 B native │ 3.4 MiB │ 3.4 MiB │ 0 B │ 8.3 MiB │ 8.3 MiB │ 0 B asset │ 0 B │ 0 B │ 0 B │ 0 B │ 0 B │ 0 B other │ 277.7 KiB │ 277.7 KiB │ 0 B │ 331.7 KiB │ 331.7 KiB │ 0 B ──────────┼───────────┼───────────┼───────────┼───────────┼───────────┼──────────── total │ 15.7 MiB │ 15.6 MiB │ -73.2 KiB │ 29.7 MiB │ 29.4 MiB │ -260.5 KiB

Slide 42

Slide 42 text

android { … defaultConfig { applicationId 'com.jakewharton.sdksearch' … } }

Slide 43

Slide 43 text

android { … defaultConfig { applicationId 'com.jakewharton.sdksearch' … resConfigs 'en' } }

Slide 44

Slide 44 text

$ diffuse diff \
 sdk-search-release-no-res-configs.apk \
 sdk-search-release-res-configs.apk

Slide 45

Slide 45 text

$ diffuse diff \
 sdk-search-release-no-res-configs.apk \
 sdk-search-release-res-configs.apk OLD: sdk-search-release-no-res-configs.apk (signature: V2) NEW: sdk-search-release-res-configs.apk (signature: V2) │ compressed │ uncompressed ├───────────┬───────────┬────────────┼───────────┬───────────┬──────────── APK │ old │ new │ diff │ old │ new │ diff ──────────┼───────────┼───────────┼────────────┼───────────┼───────────┼──────────── dex │ 830.2 KiB │ 830.2 KiB │ 0 B │ 1.8 MiB │ 1.8 MiB │ 0 B arsc │ 318.2 KiB │ 201.7 KiB │ -116.5 KiB │ 318.1 KiB │ 201.6 KiB │ -116.5 KiB manifest │ 1.4 KiB │ 1.4 KiB │ 0 B │ 4.2 KiB │ 4.2 KiB │ 0 B res │ 414.5 KiB │ 414.5 KiB │ 0 B │ 488.3 KiB │ 488.3 KiB │ 0 B asset │ 0 B │ 0 B │ 0 B │ 0 B │ 0 B │ 0 B other │ 37.1 KiB │ 37.1 KiB │ 0 B │ 36.3 KiB │ 36.3 KiB │ 0 B ──────────┼───────────┼───────────┼────────────┼───────────┼───────────┼──────────── total │ 1.6 MiB │ 1.5 MiB │ -116.5 KiB │ 2.6 MiB │ 2.5 MiB │ -116.5 KiB DEX │ old │ new │ diff ─────────┼───────┼───────┼─────────── count │ 1 │ 1 │ 0

Slide 46

Slide 46 text

$ diffuse diff \
 sdk-search-release-no-res-configs.apk \
 sdk-search-release-res-configs.apk OLD: sdk-search-release-no-res-configs.apk (signature: V2) NEW: sdk-search-release-res-configs.apk (signature: V2) │ compressed │ uncompressed ├───────────┬───────────┬────────────┼───────────┬───────────┬──────────── APK │ old │ new │ diff │ old │ new │ diff ──────────┼───────────┼───────────┼────────────┼───────────┼───────────┼──────────── dex │ 830.2 KiB │ 830.2 KiB │ 0 B │ 1.8 MiB │ 1.8 MiB │ 0 B arsc │ 318.2 KiB │ 201.7 KiB │ -116.5 KiB │ 318.1 KiB │ 201.6 KiB │ -116.5 KiB manifest │ 1.4 KiB │ 1.4 KiB │ 0 B │ 4.2 KiB │ 4.2 KiB │ 0 B res │ 414.5 KiB │ 414.5 KiB │ 0 B │ 488.3 KiB │ 488.3 KiB │ 0 B asset │ 0 B │ 0 B │ 0 B │ 0 B │ 0 B │ 0 B other │ 37.1 KiB │ 37.1 KiB │ 0 B │ 36.3 KiB │ 36.3 KiB │ 0 B ──────────┼───────────┼───────────┼────────────┼───────────┼───────────┼──────────── total │ 1.6 MiB │ 1.5 MiB │ -116.5 KiB │ 2.6 MiB │ 2.5 MiB │ -116.5 KiB DEX │ old │ new │ diff ─────────┼───────┼───────┼─────────── count │ 1 │ 1 │ 0

Slide 47

Slide 47 text

arsc │ 318.2 KiB │ 201.7 KiB │ -116.5 KiB │ 318.1 KiB │ 201.6 KiB │ -116.5 KiB manifest │ 1.4 KiB │ 1.4 KiB │ 0 B │ 4.2 KiB │ 4.2 KiB │ 0 B res │ 414.5 KiB │ 414.5 KiB │ 0 B │ 488.3 KiB │ 488.3 KiB │ 0 B asset │ 0 B │ 0 B │ 0 B │ 0 B │ 0 B │ 0 B other │ 37.1 KiB │ 37.1 KiB │ 0 B │ 36.3 KiB │ 36.3 KiB │ 0 B ──────────┼───────────┼───────────┼────────────┼───────────┼───────────┼──────────── total │ 1.6 MiB │ 1.5 MiB │ -116.5 KiB │ 2.6 MiB │ 2.5 MiB │ -116.5 KiB DEX │ old │ new │ diff ─────────┼───────┼───────┼─────────── count │ 1 │ 1 │ 0 strings │ 17036 │ 17036 │ 0 (+0 -0) types │ 2632 │ 2632 │ 0 (+0 -0) classes │ 1887 │ 1887 │ 0 (+0 -0) methods │ 14296 │ 14296 │ 0 (+0 -0) fields │ 5291 │ 5291 │ 0 (+0 -0) ARSC │ old │ new │ diff ─────────┼──────┼──────┼────────────── configs │ 136 │ 51 │ -85 (+0 -85) entries │ 1950 │ 1950 │ 0 ================= ==== APK ====

Slide 48

Slide 48 text

DEX │ old │ new │ diff ─────────┼───────┼───────┼─────────── count │ 1 │ 1 │ 0 strings │ 17036 │ 17036 │ 0 (+0 -0) types │ 2632 │ 2632 │ 0 (+0 -0) classes │ 1887 │ 1887 │ 0 (+0 -0) methods │ 14296 │ 14296 │ 0 (+0 -0) fields │ 5291 │ 5291 │ 0 (+0 -0) ARSC │ old │ new │ diff ─────────┼──────┼──────┼────────────── configs │ 136 │ 51 │ -85 (+0 -85) entries │ 1950 │ 1950 │ 0 ================= ==== APK ==== ================= compressed │ uncompressed │ ───────────┬────────────┼───────────┬────────────┤ size │ diff │ size │ diff │ path ───────────┼────────────┼───────────┼────────────┼────────────────── 201.7 KiB │ -116.5 KiB │ 201.6 KiB │ -116.5 KiB │ ∆ resources.arsc ───────────┼────────────┼───────────┼────────────┼────────────────── 201.7 KiB │ -116.5 KiB │ 201.6 KiB │ -116.5 KiB │ (total)

Slide 49

Slide 49 text

ARSC │ old │ new │ diff ─────────┼──────┼──────┼────────────── configs │ 136 │ 51 │ -85 (+0 -85) entries │ 1950 │ 1950 │ 0 ================= ==== APK ==== ================= compressed │ uncompressed │ ───────────┬────────────┼───────────┬────────────┤ size │ diff │ size │ diff │ path ───────────┼────────────┼───────────┼────────────┼────────────────── 201.7 KiB │ -116.5 KiB │ 201.6 KiB │ -116.5 KiB │ ∆ resources.arsc ───────────┼────────────┼───────────┼────────────┼────────────────── 201.7 KiB │ -116.5 KiB │ 201.6 KiB │ -116.5 KiB │ (total) ================== ==== ARSC ==== ================== CONFIGS: old │ new │ diff

Slide 50

Slide 50 text

================== ==== ARSC ==== ================== CONFIGS: old │ new │ diff ─────┼─────┼────────────── 136 │ 51 │ -85 (+0 -85) - string-af - string-am - string-ar - string-as - string-az - string-be - string-bg - string-bn - string-bs - string-ca - string-cs - string-da - string-de - string-el

Slide 51

Slide 51 text

- string-pt-rBR - string-pt-rPT - string-ro - string-ru - string-si - string-sk - string-sl - string-sq - string-sr - string-sr - string-sv - string-sw - string-ta - string-te - string-th - string-tl - string-tr - string-uk - string-ur - string-uz - string-vi - string-zh-rCN - string-zh-rHK - string-zh-rTW - string-zu

Slide 52

Slide 52 text

android { … defaultConfig { minSdkVersion 23 … } }

Slide 53

Slide 53 text

android { … defaultConfig { - minSdkVersion 23 + minSdkVersion 24 … } }

Slide 54

Slide 54 text

$ diffuse diff \
 sdk-search-release-min-sdk-23.apk \
 sdk-search-release-min-sdk-24.apk

Slide 55

Slide 55 text

$ diffuse diff \
 sdk-search-release-min-sdk-23.apk \
 sdk-search-release-min-sdk-24.apk OLD: sdk-search-release-min-sdk-23.apk (signature: V1, V2) NEW: sdk-search-release-min-sdk-24.apk (signature: V2) │ compressed │ uncompressed ├───────────┬───────────┬───────────┼───────────┬───────────┬──────────── APK │ old │ new │ diff │ old │ new │ diff ──────────┼───────────┼───────────┼───────────┼───────────┼───────────┼──────────── dex │ 830.4 KiB │ 830.2 KiB │ -192 B │ 1.8 MiB │ 1.8 MiB │ -268 B arsc │ 203.8 KiB │ 201.7 KiB │ -2.1 KiB │ 203.7 KiB │ 201.6 KiB │ -2.1 KiB manifest │ 1.4 KiB │ 1.4 KiB │ 0 B │ 4.2 KiB │ 4.2 KiB │ 0 B res │ 414.5 KiB │ 414.5 KiB │ -6 B │ 488.3 KiB │ 488.3 KiB │ 0 B asset │ 0 B │ 0 B │ 0 B │ 0 B │ 0 B │ 0 B other │ 74.6 KiB │ 37.1 KiB │ -37.5 KiB │ 152.6 KiB │ 36.3 KiB │ -116.3 KiB ──────────┼───────────┼───────────┼───────────┼───────────┼───────────┼──────────── total │ 1.5 MiB │ 1.5 MiB │ -39.8 KiB │ 2.6 MiB │ 2.5 MiB │ -118.7 KiB DEX │ old │ new │ diff ─────────┼───────┼───────┼──────────── count │ 1 │ 1 │ 0

Slide 56

Slide 56 text

$ diffuse diff \
 sdk-search-release-min-sdk-23.apk \
 sdk-search-release-min-sdk-24.apk OLD: sdk-search-release-min-sdk-23.apk (signature: V1, V2) NEW: sdk-search-release-min-sdk-24.apk (signature: V2) │ compressed │ uncompressed ├───────────┬───────────┬───────────┼───────────┬───────────┬──────────── APK │ old │ new │ diff │ old │ new │ diff ──────────┼───────────┼───────────┼───────────┼───────────┼───────────┼──────────── dex │ 830.4 KiB │ 830.2 KiB │ -192 B │ 1.8 MiB │ 1.8 MiB │ -268 B arsc │ 203.8 KiB │ 201.7 KiB │ -2.1 KiB │ 203.7 KiB │ 201.6 KiB │ -2.1 KiB manifest │ 1.4 KiB │ 1.4 KiB │ 0 B │ 4.2 KiB │ 4.2 KiB │ 0 B res │ 414.5 KiB │ 414.5 KiB │ -6 B │ 488.3 KiB │ 488.3 KiB │ 0 B asset │ 0 B │ 0 B │ 0 B │ 0 B │ 0 B │ 0 B other │ 74.6 KiB │ 37.1 KiB │ -37.5 KiB │ 152.6 KiB │ 36.3 KiB │ -116.3 KiB ──────────┼───────────┼───────────┼───────────┼───────────┼───────────┼──────────── total │ 1.5 MiB │ 1.5 MiB │ -39.8 KiB │ 2.6 MiB │ 2.5 MiB │ -118.7 KiB DEX │ old │ new │ diff ─────────┼───────┼───────┼──────────── count │ 1 │ 1 │ 0

Slide 57

Slide 57 text

res │ 414.5 KiB │ 414.5 KiB │ -6 B │ 488.3 KiB │ 488.3 KiB │ 0 B asset │ 0 B │ 0 B │ 0 B │ 0 B │ 0 B │ 0 B other │ 74.6 KiB │ 37.1 KiB │ -37.5 KiB │ 152.6 KiB │ 36.3 KiB │ -116.3 KiB ──────────┼───────────┼───────────┼───────────┼───────────┼───────────┼──────────── total │ 1.5 MiB │ 1.5 MiB │ -39.8 KiB │ 2.6 MiB │ 2.5 MiB │ -118.7 KiB DEX │ old │ new │ diff ─────────┼───────┼───────┼──────────── count │ 1 │ 1 │ 0 strings │ 17038 │ 17036 │ -2 (+1 -3) types │ 2634 │ 2632 │ -2 (+0 -2) classes │ 1889 │ 1887 │ -2 (+0 -2) methods │ 14295 │ 14296 │ +1 (+3 -2) fields │ 5291 │ 5291 │ 0 (+0 -0) ARSC │ old │ new │ diff ─────────┼──────┼──────┼──────────── configs │ 52 │ 51 │ -1 (+0 -1) entries │ 1950 │ 1950 │ 0 ================= ==== APK ==== =================

Slide 58

Slide 58 text

count │ 1 │ 1 │ 0 strings │ 17038 │ 17036 │ -2 (+1 -3) types │ 2634 │ 2632 │ -2 (+0 -2) classes │ 1889 │ 1887 │ -2 (+0 -2) methods │ 14295 │ 14296 │ +1 (+3 -2) fields │ 5291 │ 5291 │ 0 (+0 -0) ARSC │ old │ new │ diff ─────────┼──────┼──────┼──────────── configs │ 52 │ 51 │ -1 (+0 -1) entries │ 1950 │ 1950 │ 0 ================= ==== APK ==== ================= compressed │ uncompressed │ ───────────┬───────────┼───────────┬────────────┤ size │ diff │ size │ diff │ path ───────────┼───────────┼───────────┼────────────┼──────────────────────────────────────── │ -19.9 KiB │ │ -57.6 KiB │ - META-INF/CERT.SF 206 B │ -16.5 KiB │ 94 B │ -57.4 KiB │ ∆ META-INF/MANIFEST.MF 201.7 KiB │ -2.1 KiB │ 201.6 KiB │ -2.1 KiB │ ∆ resources.arsc │ -1.2 KiB │ │ -1.3 KiB │ - META-INF/CERT.RSA 830.2 KiB │ -192 B │ 1.8 MiB │ -268 B │ ∆ classes.dex

Slide 59

Slide 59 text

entries │ 1950 │ 1950 │ 0 ================= ==== APK ==== ================= compressed │ uncompressed │ ───────────┬───────────┼───────────┬────────────┤ size │ diff │ size │ diff │ path ───────────┼───────────┼───────────┼────────────┼──────────────────────────────────────────────────────── │ -19.9 KiB │ │ -57.6 KiB │ - META-INF/CERT.SF 206 B │ -16.5 KiB │ 94 B │ -57.4 KiB │ ∆ META-INF/MANIFEST.MF 201.7 KiB │ -2.1 KiB │ 201.6 KiB │ -2.1 KiB │ ∆ resources.arsc │ -1.2 KiB │ │ -1.3 KiB │ - META-INF/CERT.RSA 830.2 KiB │ -192 B │ 1.8 MiB │ -268 B │ ∆ classes.dex 470 B │ -6 B │ 272 B │ 0 B │ ∆ res/drawable-hdpi-v4/abc_ab_share_pack_mtrl_alpha.9.p ───────────┼───────────┼───────────┼────────────┼──────────────────────────────────────────────────────── 1 MiB │ -39.8 KiB │ 2 MiB │ -118.7 KiB │ (total) SIGNATURES │ old │ new ────────────┼──────────────────────────────────────────┼────────────────────────────────────────── V1 │ abbd3cd5f23b986a66a40afae4931e063e32f112 │ V2 │ abbd3cd5f23b986a66a40afae4931e063e32f112 │ abbd3cd5f23b986a66a40afae4931e063e32f112 ====================== ==== MANIFEST ====

Slide 60

Slide 60 text

SIGNATURES │ old │ new ────────────┼──────────────────────────────────────────┼───────────────────────────────── V1 │ abbd3cd5f23b986a66a40afae4931e063e32f112 │ V2 │ abbd3cd5f23b986a66a40afae4931e063e32f112 │ abbd3cd5f23b986a66a40afae4931e06 ====================== ==== MANIFEST ==== ====================== @@ -13,3 +13,3 @@

Slide 61

Slide 61 text

================= ==== DEX ==== ================= STRINGS: old │ new │ diff ───────┼───────┼──────────── 17038 │ 17036 │ -2 (+1 -3) + ~~R8{"compilation-mode":"release","min-api":24,"pg-map-id":"943932c","version":"1.6.3 - L$r8$backportedMethods$utility$Boolean$1$hashCode; - L$r8$backportedMethods$utility$Long$1$hashCode; - ~~R8{"compilation-mode":"release","min-api":23,"pg-map-id":"151f4fb","version":"1.6.3 TYPES: old │ new │ diff ──────┼──────┼──────────── 2634 │ 2632 │ -2 (+0 -2) - L$r8$backportedMethods$utility$Boolean$1$hashCode;

Slide 62

Slide 62 text

- ~~R8{"compilation-mode":"release","min-api":23,"pg-map-id":"151f4fb","version":"1.6.3 TYPES: old │ new │ diff ──────┼──────┼──────────── 2634 │ 2632 │ -2 (+0 -2) - L$r8$backportedMethods$utility$Boolean$1$hashCode; - L$r8$backportedMethods$utility$Long$1$hashCode; METHODS: old │ new │ diff ───────┼───────┼──────────── 14295 │ 14296 │ +1 (+3 -2) + java.lang.Boolean hashCode(boolean) → int + java.lang.Integer hashCode(int) → int + java.lang.Long hashCode(long) → int - $r8$backportedMethods$utility$Boolean$1$hashCode hashCode(boolean) → int - $r8$backportedMethods$utility$Long$1$hashCode hashCode(long) → int

Slide 63

Slide 63 text

+ java.lang.Integer hashCode(int) → int + java.lang.Long hashCode(long) → int - $r8$backportedMethods$utility$Boolean$1$hashCode hashCode(boolean) → int - $r8$backportedMethods$utility$Long$1$hashCode hashCode(long) → int ================== ==== ARSC ==== ================== CONFIGS: old │ new │ diff ─────┼─────┼──────────── 52 │ 51 │ -1 (+0 -1) - style-v24

Slide 64

Slide 64 text

$ diffuse diff \ 
 plaid-base.aab \
 plaid-min-sdk-24.aab

Slide 65

Slide 65 text

$ diffuse diff --aab \ 
 plaid-base.aab \
 plaid-min-sdk-24.aab

Slide 66

Slide 66 text

$ diffuse diff --aab \
 plaid-base.aab \
 plaid-min-sdk-24.aab OLD: plaid-base.aab NEW: plaid-min-sdk-24.aab MODULES │ old │ new ──────────────┼─────┼───── base │ ✓ │ ✓ about │ ✓ │ ✓ designernews │ ✓ │ ✓ dribbble │ ✓ │ ✓ search │ ✓ │ ✓ =================== ==== about ==== =================== STRINGS:

Slide 67

Slide 67 text

$ diffuse diff --aab \
 plaid-base.aab \
 plaid-min-sdk-24.aab OLD: plaid-base.aab NEW: plaid-min-sdk-24.aab MODULES │ old │ new ──────────────┼─────┼───── base │ ✓ │ ✓ about │ ✓ │ ✓ designernews │ ✓ │ ✓ dribbble │ ✓ │ ✓ search │ ✓ │ ✓ =================== ==== about ==== =================== STRINGS:

Slide 68

Slide 68 text

=================== ==== about ==== =================== STRINGS: old │ new │ diff ──────┼──────┼─────────── 1620 │ 1620 │ 0 (+1 -1) + ~~D8{"compilation-mode":"release","min-api":24,"sha-1":"b1002e674a56adf24681a7c2a4454 - ~~D8{"compilation-mode":"release","min-api":23,"sha-1":"b1002e674a56adf24681a7c2a4454 @@ -14,3 +14,3 @@

Slide 69

Slide 69 text

========================== ==== designernews ==== ========================== STRINGS: old │ new │ diff ──────┼──────┼──────────── 2374 │ 2372 │ -2 (+1 -3) + ~~D8{"compilation-mode":"release","min-api":24,"sha-1":"b1002e674a56adf24681a7c2a4454 - L$r8$backportedMethods$utility$Integer$1$hashCode; - L$r8$backportedMethods$utility$Long$1$hashCode; - ~~D8{"compilation-mode":"release","min-api":23,"sha-1":"b1002e674a56adf24681a7c2a4454 TYPES: old │ new │ diff ─────┼─────┼──────────── 571 │ 569 │ -2 (+0 -2)

Slide 70

Slide 70 text

- ~~D8{"compilation-mode":"release","min-api":23,"sha-1":"b1002e674a56adf24681a7c2a4454 TYPES: old │ new │ diff ─────┼─────┼──────────── 571 │ 569 │ -2 (+0 -2) - L$r8$backportedMethods$utility$Integer$1$hashCode; - L$r8$backportedMethods$utility$Long$1$hashCode; METHODS: old │ new │ diff ──────┼──────┼─────────── 1631 │ 1631 │ 0 (+2 -2) + java.lang.Integer hashCode(int) → int + java.lang.Long hashCode(long) → int - $r8$backportedMethods$utility$Integer$1$hashCode hashCode(int) → int - $r8$backportedMethods$utility$Long$1$hashCode hashCode(long) → int

Slide 71

Slide 71 text

old │ new │ diff ──────┼──────┼─────────── 1631 │ 1631 │ 0 (+2 -2) + java.lang.Integer hashCode(int) → int + java.lang.Long hashCode(long) → int - $r8$backportedMethods$utility$Integer$1$hashCode hashCode(int) → int - $r8$backportedMethods$utility$Long$1$hashCode hashCode(long) → int @@ -14,3 +14,3 @@

Slide 72

Slide 72 text

====================== ==== dribbble ==== ====================== STRINGS: old │ new │ diff ──────┼──────┼──────────── 1076 │ 1074 │ -2 (+1 -3) + ~~D8{"compilation-mode":"release","min-api":24,"sha-1":"b1002e674a56adf24681a7c2a4454 - L$r8$backportedMethods$utility$Integer$1$hashCode; - L$r8$backportedMethods$utility$Long$1$hashCode; - ~~D8{"compilation-mode":"release","min-api":23,"sha-1":"b1002e674a56adf24681a7c2a4454 TYPES: old │ new │ diff ─────┼─────┼──────────── 279 │ 277 │ -2 (+0 -2)

Slide 73

Slide 73 text

==================== ==== search ==== ==================== STRINGS: old │ new │ diff ───────┼───────┼─────────── 13117 │ 13117 │ 0 (+1 -1) + ~~D8{"compilation-mode":"release","min-api":24,"sha-1":"b1002e674a56adf24681a7c2a4454 - ~~D8{"compilation-mode":"release","min-api":23,"sha-1":"b1002e674a56adf24681a7c2a4454 @@ -14,3 +14,3 @@

Slide 74

Slide 74 text

$ diffuse diff --aar \
 rxbinding-2.1.0.aar \
 rxbinding-2.1.1.aar

Slide 75

Slide 75 text

$ diffuse diff --aar \
 rxbinding-2.1.0.aar \
 rxbinding-2.1.1.aar OLD: rxbinding-2.1.0.aar NEW: rxbinding-2.1.1.aar AAR │ old │ new │ diff ──────────┼───────────┼───────────┼──────── jar │ 203.7 KiB │ 203.1 KiB │ -583 B manifest │ 212 B │ 212 B │ 0 B res │ 0 B │ 0 B │ 0 B native │ 0 B │ 0 B │ 0 B other │ 0 B │ 110 B │ +110 B ──────────┼───────────┼───────────┼──────── total │ 203.9 KiB │ 203.4 KiB │ -473 B JAR │ old │ new │ diff ─────────┼──────┼──────┼──────────── classes │ 210 │ 209 │ -1 (+0 -1) methods │ 1023 │ 1022 │ -1 (+0 -1) fields │ 294 │ 288 │ -6 (+0 -6)

Slide 76

Slide 76 text

$ diffuse diff --aar \
 rxbinding-2.1.0.aar \
 rxbinding-2.1.1.aar OLD: rxbinding-2.1.0.aar NEW: rxbinding-2.1.1.aar AAR │ old │ new │ diff ──────────┼───────────┼───────────┼──────── jar │ 203.7 KiB │ 203.1 KiB │ -583 B manifest │ 212 B │ 212 B │ 0 B res │ 0 B │ 0 B │ 0 B native │ 0 B │ 0 B │ 0 B other │ 0 B │ 110 B │ +110 B ──────────┼───────────┼───────────┼──────── total │ 203.9 KiB │ 203.4 KiB │ -473 B JAR │ old │ new │ diff ─────────┼──────┼──────┼──────────── classes │ 210 │ 209 │ -1 (+0 -1) methods │ 1023 │ 1022 │ -1 (+0 -1) fields │ 294 │ 288 │ -6 (+0 -6)

Slide 77

Slide 77 text

manifest │ 212 B │ 212 B │ 0 B res │ 0 B │ 0 B │ 0 B native │ 0 B │ 0 B │ 0 B other │ 0 B │ 110 B │ +110 B ──────────┼───────────┼───────────┼──────── total │ 203.9 KiB │ 203.4 KiB │ -473 B JAR │ old │ new │ diff ─────────┼──────┼──────┼──────────── classes │ 210 │ 209 │ -1 (+0 -1) methods │ 1023 │ 1022 │ -1 (+0 -1) fields │ 294 │ 288 │ -6 (+0 -6) ================= ==== AAR ==== ================= size │ diff │ path ───────────┼────────┼──────────────── 110 B │ +110 B │ + proguard.txt 203.1 KiB │ -583 B │ ∆ classes.jar ───────────┼────────┼──────────────── 203.2 KiB │ -473 B │ (total)

Slide 78

Slide 78 text

fields │ 294 │ 288 │ -6 (+0 -6) ================= ==== AAR ==== ================= size │ diff │ path ───────────┼────────┼──────────────── 110 B │ +110 B │ + proguard.txt 203.1 KiB │ -583 B │ ∆ classes.jar ───────────┼────────┼──────────────── 203.2 KiB │ -473 B │ (total) ================= ==== JAR ==== ================= CLASSES: old │ new │ diff ─────┼─────┼──────────── 210 │ 209 │ -1 (+0 -1) - com.jakewharton.rxbinding2.BuildConfig

Slide 79

Slide 79 text

================= ==== JAR ==== ================= CLASSES: old │ new │ diff ─────┼─────┼──────────── 210 │ 209 │ -1 (+0 -1) - com.jakewharton.rxbinding2.BuildConfig METHODS: old │ new │ diff ──────┼──────┼──────────── 1023 │ 1022 │ -1 (+0 -1) - com.jakewharton.rxbinding2.BuildConfig () FIELDS:

Slide 80

Slide 80 text

- com.jakewharton.rxbinding2.BuildConfig METHODS: old │ new │ diff ──────┼──────┼──────────── 1023 │ 1022 │ -1 (+0 -1) - com.jakewharton.rxbinding2.BuildConfig () FIELDS: old │ new │ diff ─────┼─────┼──────────── 294 │ 288 │ -6 (+0 -6) - com.jakewharton.rxbinding2.BuildConfig APPLICATION_ID: String - com.jakewharton.rxbinding2.BuildConfig BUILD_TYPE: String - com.jakewharton.rxbinding2.BuildConfig DEBUG: boolean - com.jakewharton.rxbinding2.BuildConfig FLAVOR: String - com.jakewharton.rxbinding2.BuildConfig VERSION_CODE: int - com.jakewharton.rxbinding2.BuildConfig VERSION_NAME: String

Slide 81

Slide 81 text

$ diffuse diff --jar \
 okhttp-4.0.0.jar \
 okhttp-4.1.0.jar

Slide 82

Slide 82 text

$ diffuse diff --jar \
 okhttp-4.0.0.jar \
 okhttp-4.1.0.jar OLD: okhttp-4.0.0.jar NEW: okhttp-4.1.0.jar JAR │ old │ new │ diff ───────┼──────────┼──────────┼────────── class │ 1.2 MiB │ 1.2 MiB │ +4.5 KiB other │ 36.8 KiB │ 36.8 KiB │ 0 B ───────┼──────────┼──────────┼────────── total │ 1.3 MiB │ 1.3 MiB │ +4.5 KiB CLASSES │ old │ new │ diff ─────────┼──────┼──────┼────────────── classes │ 264 │ 264 │ 0 (+0 -0) methods │ 3075 │ 3085 │ +10 (+10 -0) fields │ 1204 │ 1206 │ +2 (+2 -0) ================= ==== JAR ====

Slide 83

Slide 83 text

$ diffuse diff --jar \
 okhttp-4.0.0.jar \
 okhttp-4.1.0.jar OLD: okhttp-4.0.0.jar NEW: okhttp-4.1.0.jar JAR │ old │ new │ diff ───────┼──────────┼──────────┼────────── class │ 1.2 MiB │ 1.2 MiB │ +4.5 KiB other │ 36.8 KiB │ 36.8 KiB │ 0 B ───────┼──────────┼──────────┼────────── total │ 1.3 MiB │ 1.3 MiB │ +4.5 KiB CLASSES │ old │ new │ diff ─────────┼──────┼──────┼────────────── classes │ 264 │ 264 │ 0 (+0 -0) methods │ 3075 │ 3085 │ +10 (+10 -0) fields │ 1204 │ 1206 │ +2 (+2 -0) ================= ==== JAR ====

Slide 84

Slide 84 text

───────┼──────────┼──────────┼────────── class │ 1.2 MiB │ 1.2 MiB │ +4.5 KiB other │ 36.8 KiB │ 36.8 KiB │ 0 B ───────┼──────────┼──────────┼────────── total │ 1.3 MiB │ 1.3 MiB │ +4.5 KiB CLASSES │ old │ new │ diff ─────────┼──────┼──────┼────────────── classes │ 264 │ 264 │ 0 (+0 -0) methods │ 3075 │ 3085 │ +10 (+10 -0) fields │ 1204 │ 1206 │ +2 (+2 -0) ================= ==== JAR ==== ================= size │ diff │ path ───────────┼──────────┼────────────────────────────────────────────────────────────────── 8.6 KiB │ +2.2 KiB │ ∆ okhttp3/ResponseBody.class 4.6 KiB │ +39 B │ ∆ okhttp3/internal/cache/DiskLruCache$snapshots$1.class 8.2 KiB │ +184 B │ ∆ okhttp3/internal/connection/RouteSelector.class 1.4 KiB │ +82 B │ ∆ okhttp3/internal/connection/RealConnectionPool$cleanupRunnable$ 10.5 KiB │ +10 B │ ∆ okhttp3/internal/connection/ExchangeFinder.class 14.8 KiB │ -2 B │ ∆ okhttp3/internal/http2/Http2Connection$ReaderRunnable.class 7.9 KiB │ +387 B │ ∆ okhttp3/internal/http/HttpHeaders.class

Slide 85

Slide 85 text

fields │ 1204 │ 1206 │ +2 (+2 -0) ================= ==== JAR ==== ================= size │ diff │ path ───────────┼──────────┼────────────────────────────────────────────────────────────────── 8.6 KiB │ +2.2 KiB │ ∆ okhttp3/ResponseBody.class 4.6 KiB │ +39 B │ ∆ okhttp3/internal/cache/DiskLruCache$snapshots$1.class 8.2 KiB │ +184 B │ ∆ okhttp3/internal/connection/RouteSelector.class 1.4 KiB │ +82 B │ ∆ okhttp3/internal/connection/RealConnectionPool$cleanupRunnable$ 10.5 KiB │ +10 B │ ∆ okhttp3/internal/connection/ExchangeFinder.class 14.8 KiB │ -2 B │ ∆ okhttp3/internal/http2/Http2Connection$ReaderRunnable.class 7.9 KiB │ +387 B │ ∆ okhttp3/internal/http/HttpHeaders.class 27.7 KiB │ +434 B │ ∆ okhttp3/OkHttpClient$Builder.class 18.6 KiB │ +585 B │ ∆ okhttp3/OkHttpClient.class 6.3 KiB │ +580 B │ ∆ okhttp3/EventListener.class 10.5 KiB │ -33 B │ ∆ okhttp3/ConnectionSpec.class ───────────┼──────────┼────────────────────────────────────────────────────────────────── 119.3 KiB │ +4.5 KiB │ (total) ===================== ==== CLASSES ====

Slide 86

Slide 86 text

===================== ==== CLASSES ==== ===================== METHODS: old │ new │ diff ──────┼──────┼────────────── 3075 │ 3085 │ +10 (+10 -0) + okhttp3.EventListener proxySelectEnd(Call, HttpUrl, List) + okhttp3.EventListener proxySelectStart(Call, HttpUrl) + okhttp3.OkHttpClient x509TrustManager() → X509TrustManager + okhttp3.OkHttpClient$Builder getX509TrustManagerOrNull$okhttp() → X509TrustManager + okhttp3.OkHttpClient$Builder setX509TrustManagerOrNull$okhttp(X509TrustManager) + okhttp3.ResponseBody byteString() → ByteString + okhttp3.ResponseBody consumeSource(Function1, Function1) → Object + okhttp3.internal.http.HttpHeaders hasBody(Response) → boolean + java.lang.Number intValue() → int + okio.BufferedSource readByteString() → ByteString FIELDS:

Slide 87

Slide 87 text

+ okhttp3.EventListener proxySelectStart(Call, HttpUrl) + okhttp3.OkHttpClient x509TrustManager() → X509TrustManager + okhttp3.OkHttpClient$Builder getX509TrustManagerOrNull$okhttp() → X509TrustManager + okhttp3.OkHttpClient$Builder setX509TrustManagerOrNull$okhttp(X509TrustManager) + okhttp3.ResponseBody byteString() → ByteString + okhttp3.ResponseBody consumeSource(Function1, Function1) → Object + okhttp3.internal.http.HttpHeaders hasBody(Response) → boolean + java.lang.Number intValue() → int + okio.BufferedSource readByteString() → ByteString FIELDS: old │ new │ diff ──────┼──────┼──────────── 1204 │ 1206 │ +2 (+2 -0) + okhttp3.OkHttpClient x509TrustManager: X509TrustManager + okhttp3.OkHttpClient$Builder x509TrustManagerOrNull: X509TrustManager

Slide 88

Slide 88 text

$ diffuse diff \
 sdk-search-release-gradle.apk \
 sdk-search-release-recompressed.apk

Slide 89

Slide 89 text

$ diffuse diff \
 sdk-search-release-gradle.apk \
 sdk-search-release-recompressed.apk OLD: sdk-search-release-gradle.apk (signature: V2) NEW: sdk-search-release-recompressed.apk (signature: V2) │ compressed │ uncompressed ├───────────┬───────────┬────────────┼───────────┬───────────┬────── APK │ old │ new │ diff │ old │ new │ diff ──────────┼───────────┼───────────┼────────────┼───────────┼───────────┼────── dex │ 830.3 KiB │ 833.8 KiB │ +3.5 KiB │ 1.8 MiB │ 1.8 MiB │ 0 B arsc │ 201.7 KiB │ 42.1 KiB │ -159.6 KiB │ 201.6 KiB │ 201.6 KiB │ 0 B manifest │ 1.4 KiB │ 1.5 KiB │ +51 B │ 4.2 KiB │ 4.2 KiB │ 0 B res │ 414.5 KiB │ 435.2 KiB │ +20.8 KiB │ 488.3 KiB │ 488.3 KiB │ 0 B asset │ 0 B │ 0 B │ 0 B │ 0 B │ 0 B │ 0 B other │ 37.1 KiB │ 38.2 KiB │ +1.1 KiB │ 36.3 KiB │ 36.3 KiB │ 0 B ──────────┼───────────┼───────────┼────────────┼───────────┼───────────┼────── total │ 1.5 MiB │ 1.3 MiB │ -134.2 KiB │ 2.5 MiB │ 2.5 MiB │ 0 B

Slide 90

Slide 90 text

$ diffuse diff \
 sdk-search-release-gradle.apk \
 sdk-search-release-recompressed.apk OLD: sdk-search-release-gradle.apk (signature: V2) NEW: sdk-search-release-recompressed.apk (signature: V2) │ compressed │ uncompressed ├───────────┬───────────┬────────────┼───────────┬───────────┬────── APK │ old │ new │ diff │ old │ new │ diff ──────────┼───────────┼───────────┼────────────┼───────────┼───────────┼────── dex │ 830.3 KiB │ 833.8 KiB │ +3.5 KiB │ 1.8 MiB │ 1.8 MiB │ 0 B arsc │ 201.7 KiB │ 42.1 KiB │ -159.6 KiB │ 201.6 KiB │ 201.6 KiB │ 0 B manifest │ 1.4 KiB │ 1.5 KiB │ +51 B │ 4.2 KiB │ 4.2 KiB │ 0 B res │ 414.5 KiB │ 435.2 KiB │ +20.8 KiB │ 488.3 KiB │ 488.3 KiB │ 0 B asset │ 0 B │ 0 B │ 0 B │ 0 B │ 0 B │ 0 B other │ 37.1 KiB │ 38.2 KiB │ +1.1 KiB │ 36.3 KiB │ 36.3 KiB │ 0 B ──────────┼───────────┼───────────┼────────────┼───────────┼───────────┼────── total │ 1.5 MiB │ 1.3 MiB │ -134.2 KiB │ 2.5 MiB │ 2.5 MiB │ 0 B

Slide 91

Slide 91 text

$ diffuse diff \
 sdk-search-release-gradle.apk \
 sdk-search-release-recompressed.apk OLD: sdk-search-release-gradle.apk (signature: V2) NEW: sdk-search-release-recompressed.apk (signature: V2) NOTICES ───────────────────────────────────────────────────────────────────────────────── ! resources.arsc changed from correctly uncompressed to incorrectly compressed │ compressed │ uncompressed ├───────────┬───────────┬────────────┼───────────┬───────────┬────── APK │ old │ new │ diff │ old │ new │ diff ──────────┼───────────┼───────────┼────────────┼───────────┼───────────┼────── dex │ 830.3 KiB │ 833.8 KiB │ +3.5 KiB │ 1.8 MiB │ 1.8 MiB │ 0 B arsc │ 201.7 KiB │ 42.1 KiB │ -159.6 KiB │ 201.6 KiB │ 201.6 KiB │ 0 B manifest │ 1.4 KiB │ 1.5 KiB │ +51 B │ 4.2 KiB │ 4.2 KiB │ 0 B res │ 414.5 KiB │ 435.2 KiB │ +20.8 KiB │ 488.3 KiB │ 488.3 KiB │ 0 B asset │ 0 B │ 0 B │ 0 B │ 0 B │ 0 B │ 0 B other │ 37.1 KiB │ 38.2 KiB │ +1.1 KiB │ 36.3 KiB │ 36.3 KiB │ 0 B ──────────┼───────────┼───────────┼────────────┼───────────┼───────────┼────── total │ 1.5 MiB │ 1.3 MiB │ -134.2 KiB │ 2.5 MiB │ 2.5 MiB │ 0 B

Slide 92

Slide 92 text

Productionizing

Slide 93

Slide 93 text

On Master and Branch Success

Slide 94

Slide 94 text

$ cp app/build/outputs/apk/release/*.apk /shared/project/$GIT_SHA.apk For Single, Shared Machine: On Master and Branch Success

Slide 95

Slide 95 text

$ cp app/build/outputs/apk/release/*.apk /shared/project/$GIT_SHA.apk For Single, Shared Machine: For Cloud Workers: $ curl -X PUT \
 -T app/build/outputs/apk/release/*.apk \
 -H "Authorization: ..." \
 https://some-bucket.s3.amazonaws.com/${GIT_SHA}.apk On Master and Branch Success

Slide 96

Slide 96 text

$ find /shared/project -mtime +20 -exec rm {} \; For Single, Shared Machine:

Slide 97

Slide 97 text

$ find /shared/project -mtime +20 -exec rm {} \; For Single, Shared Machine: For Cloud Workers: $ curl ...list objects... $ curl ...delete objects...

Slide 98

Slide 98 text

master

Slide 99

Slide 99 text

jw/whoooops master

Slide 100

Slide 100 text

jw/whoooops master

Slide 101

Slide 101 text

jw/whoooops master

Slide 102

Slide 102 text

master jw/whoooops

Slide 103

Slide 103 text

master jw/whoooops

Slide 104

Slide 104 text

master jw/whoooops

Slide 105

Slide 105 text

master jw/whoooops

Slide 106

Slide 106 text

jw/whoooops

Slide 107

Slide 107 text

jw/whoooops $ git fetch origin master

Slide 108

Slide 108 text

origin/master jw/whoooops $ git fetch origin master

Slide 109

Slide 109 text

origin/master jw/whoooops $ git merge-base --all $GIT_SHA origin/master $ git fetch origin master

Slide 110

Slide 110 text

origin/master jw/whoooops 0d2eef7a2f54ac3e505f11f978cfa097d8bfed14 $ git merge-base --all $GIT_SHA origin/master $ git fetch origin master

Slide 111

Slide 111 text

origin/master jw/whoooops $ git fetch origin master $ git merge-base --all $GIT_SHA origin/master 0d2eef7a2f54ac3e505f11f978cfa097d8bfed14

Slide 112

Slide 112 text

$ diffuse diff \
 /shared/project/$MERGE_BASE_SHA.apk app/build/outputs/apk/release/*.apk For Single, Shared Machine:

Slide 113

Slide 113 text

$ diffuse diff \
 /shared/project/$MERGE_BASE_SHA.apk app/build/outputs/apk/release/*.apk For Single, Shared Machine: For Cloud Workers: $ curl -H "Authorization: ..." \
 https://some-bucket.s3.amazonaws.com/$MERGE_BASE_SHA.apk
 > merge-base.apk $ diffuse diff \
 merge-base.apk app/build/outputs/apk/release/*.apk

Slide 114

Slide 114 text

val apkPath = …

Slide 115

Slide 115 text

val apkPath = … val declaredCount = apkPath.asInput()

Slide 116

Slide 116 text

val apkPath = … val declaredCount = apkPath.asInput() .toApk()

Slide 117

Slide 117 text

val apkPath = … val declaredCount = apkPath.asInput() .toApk() .dexes

Slide 118

Slide 118 text

val apkPath = … val declaredCount = apkPath.asInput() .toApk() .dexes .flatMap { it.declaredMembers }

Slide 119

Slide 119 text

val apkPath = … val declaredCount = apkPath.asInput() .toApk() .dexes .flatMap { it.declaredMembers } .size

Slide 120

Slide 120 text

val apkPath = … val declaredCount = apkPath.asInput() .toApk() .dexes .flatMap { it.declaredMembers } .size // toAab() // toAar() // toJar()

Slide 121

Slide 121 text

val apkPath = … val declaredCount = apkPath.asInput() .toApk() .dexes .flatMap { it.declaredMembers } .size // toAab() // toAar() // toJar() // Send to analytics, reporting, etc…

Slide 122

Slide 122 text

val apkPath = … val declaredCount = apkPath.asInput() .toApk() .dexes .flatMap { it.declaredMembers } .size // toAab() // toAar() // toJar() // Send to analytics, reporting, etc… // Fail the change on lint errors…

Slide 123

Slide 123 text

│ compressed │ uncompressed ├───────────┬───────────┬────────────┼───────────┬───────────┬──────────── APK │ old │ new │ diff │ old │ new │ diff ──────────┼───────────┼───────────┼────────────┼───────────┼───────────┼──────────── dex │ 830.2 KiB │ 830.2 KiB │ 0 B │ 1.8 MiB │ 1.8 MiB │ 0 B arsc │ 318.2 KiB │ 201.7 KiB │ -116.5 KiB │ 318.1 KiB │ 201.6 KiB │ -116.5 KiB manifest │ 1.4 KiB │ 1.4 KiB │ 0 B │ 4.2 KiB │ 4.2 KiB │ 0 B res │ 414.5 KiB │ 414.5 KiB │ 0 B │ 488.3 KiB │ 488.3 KiB │ 0 B asset │ 0 B │ 0 B │ 0 B │ 0 B │ 0 B │ 0 B other │ 37.1 KiB │ 37.1 KiB │ 0 B │ 36.3 KiB │ 36.3 KiB │ 0 B ──────────┼───────────┼───────────┼────────────┼───────────┼───────────┼──────────── total │ 1.6 MiB │ 1.5 MiB │ -116.5 KiB │ 2.6 MiB │ 2.5 MiB │ -116.5 KiB

Slide 124

Slide 124 text

│ compressed │ uncompressed ├───────────┬───────────┬────────────┼───────────┬───────────┬──────────── APK │ old │ new │ diff │ old │ new │ diff ──────────┼───────────┼───────────┼────────────┼───────────┼───────────┼──────────── dex │ 830.2 KiB │ 830.2 KiB │ 0 B │ 1.8 MiB │ 1.8 MiB │ 0 B arsc │ 318.2 KiB │ 201.7 KiB │ -116.5 KiB │ 318.1 KiB │ 201.6 KiB │ -116.5 KiB manifest │ 1.4 KiB │ 1.4 KiB │ 0 B │ 4.2 KiB │ 4.2 KiB │ 0 B res │ 414.5 KiB │ 414.5 KiB │ 0 B │ 488.3 KiB │ 488.3 KiB │ 0 B asset │ 0 B │ 0 B │ 0 B │ 0 B │ 0 B │ 0 B other │ 37.1 KiB │ 37.1 KiB │ 0 B │ 36.3 KiB │ 36.3 KiB │ 0 B ──────────┼───────────┼───────────┼────────────┼───────────┼───────────┼──────────── total │ 1.6 MiB │ 1.5 MiB │ -116.5 KiB │ 2.6 MiB │ 2.5 MiB │ -116.5 KiB

Slide 125

Slide 125 text

│ compressed │ uncompressed ├───────────┬───────────┬────────────┼───────────┬───────────┬──────────── APK │ old │ new │ diff │ old │ new │ diff ──────────┼───────────┼───────────┼────────────┼───────────┼───────────┼──────────── dex │ 830.2 KiB │ 830.2 KiB │ 0 B │ 1.8 MiB │ 1.8 MiB │ 0 B arsc │ 318.2 KiB │ 201.7 KiB │ -116.5 KiB │ 318.1 KiB │ 201.6 KiB │ -116.5 KiB manifest │ 1.4 KiB │ 1.4 KiB │ 0 B │ 4.2 KiB │ 4.2 KiB │ 0 B res │ 414.5 KiB │ 414.5 KiB │ 0 B │ 488.3 KiB │ 488.3 KiB │ 0 B asset │ 0 B │ 0 B │ 0 B │ 0 B │ 0 B │ 0 B other │ 37.1 KiB │ 37.1 KiB │ 0 B │ 36.3 KiB │ 36.3 KiB │ 0 B ──────────┼───────────┼───────────┼────────────┼───────────┼───────────┼──────────── total │ 1.6 MiB │ 1.5 MiB │ -116.5 KiB │ 2.6 MiB │ 2.5 MiB │ -116.5 KiB

Slide 126

Slide 126 text

│ compressed │ uncompressed ├───────────┬───────────┬────────────┼───────────┬───────────┬──────────── APK │ old │ new │ diff │ old │ new │ diff ──────────┼───────────┼───────────┼────────────┼───────────┼───────────┼──────────── dex │ 830.2 KiB │ 830.2 KiB │ 0 B │ 1.8 MiB │ 1.8 MiB │ 0 B arsc │ 318.2 KiB │ 201.7 KiB │ -116.5 KiB │ 318.1 KiB │ 201.6 KiB │ -116.5 KiB manifest │ 1.4 KiB │ 1.4 KiB │ 0 B │ 4.2 KiB │ 4.2 KiB │ 0 B res │ 414.5 KiB │ 414.5 KiB │ 0 B │ 488.3 KiB │ 488.3 KiB │ 0 B asset │ 0 B │ 0 B │ 0 B │ 0 B │ 0 B │ 0 B other │ 37.1 KiB │ 37.1 KiB │ 0 B │ 36.3 KiB │ 36.3 KiB │ 0 B ──────────┼───────────┼───────────┼────────────┼───────────┼───────────┼──────────── total │ 1.6 MiB │ 1.5 MiB │ -116.5 KiB │ 2.6 MiB │ 2.5 MiB │ -116.5 KiB

Slide 127

Slide 127 text

│ compressed │ uncompressed ├───────────┬───────────┬────────────┼───────────┬───────────┬──────────── APK │ old │ new │ diff │ old │ new │ diff ──────────┼───────────┼───────────┼────────────┼───────────┼───────────┼──────────── dex │ 830.2 KiB │ 830.2 KiB │ 0 B │ 1.8 MiB │ 1.8 MiB │ 0 B arsc │ 318.2 KiB │ 201.7 KiB │ -116.5 KiB │ 318.1 KiB │ 201.6 KiB │ -116.5 KiB manifest │ 1.4 KiB │ 1.4 KiB │ 0 B │ 4.2 KiB │ 4.2 KiB │ 0 B res │ 414.5 KiB │ 414.5 KiB │ 0 B │ 488.3 KiB │ 488.3 KiB │ 0 B asset │ 0 B │ 0 B │ 0 B │ 0 B │ 0 B │ 0 B other │ 37.1 KiB │ 37.1 KiB │ 0 B │ 36.3 KiB │ 36.3 KiB │ 0 B ──────────┼───────────┼───────────┼────────────┼───────────┼───────────┼──────────── total │ 1.6 MiB │ 1.5 MiB │ -116.5 KiB │ 2.6 MiB │ 2.5 MiB │ -116.5 KiB

Slide 128

Slide 128 text

│ compressed │ uncompressed ├───────────┬───────────┬────────────┼───────────┬───────────┬──────────── APK │ old │ new │ diff │ old │ new │ diff ──────────┼───────────┼───────────┼────────────┼───────────┼───────────┼──────────── dex │ 830.2 KiB │ 830.2 KiB │ 0 B │ 1.8 MiB │ 1.8 MiB │ 0 B arsc │ 318.2 KiB │ 201.7 KiB │ -116.5 KiB │ 318.1 KiB │ 201.6 KiB │ -116.5 KiB manifest │ 1.4 KiB │ 1.4 KiB │ 0 B │ 4.2 KiB │ 4.2 KiB │ 0 B res │ 414.5 KiB │ 414.5 KiB │ 0 B │ 488.3 KiB │ 488.3 KiB │ 0 B asset │ 0 B │ 0 B │ 0 B │ 0 B │ 0 B │ 0 B other │ 37.1 KiB │ 37.1 KiB │ 0 B │ 36.3 KiB │ 36.3 KiB │ 0 B ──────────┼───────────┼───────────┼────────────┼───────────┼───────────┼──────────── total │ 1.6 MiB │ 1.5 MiB │ -116.5 KiB │ 2.6 MiB │ 2.5 MiB │ -116.5 KiB

Slide 129

Slide 129 text

│ compressed │ uncompressed ├───────────┬───────────┬────────────┼───────────┬───────────┬──────────── APK │ old │ new │ diff │ old │ new │ diff ──────────┼───────────┼───────────┼────────────┼───────────┼───────────┼──────────── dex │ 830.2 KiB │ 830.2 KiB │ 0 B │ 1.8 MiB │ 1.8 MiB │ 0 B arsc │ 318.2 KiB │ 201.7 KiB │ -116.5 KiB │ 318.1 KiB │ 201.6 KiB │ -116.5 KiB manifest │ 1.4 KiB │ 1.4 KiB │ 0 B │ 4.2 KiB │ 4.2 KiB │ 0 B res │ 414.5 KiB │ 414.5 KiB │ 0 B │ 488.3 KiB │ 488.3 KiB │ 0 B asset │ 0 B │ 0 B │ 0 B │ 0 B │ 0 B │ 0 B other │ 37.1 KiB │ 37.1 KiB │ 0 B │ 36.3 KiB │ 36.3 KiB │ 0 B ──────────┼───────────┼───────────┼────────────┼───────────┼───────────┼──────────── total │ 1.6 MiB │ 1.5 MiB │ -116.5 KiB │ 2.6 MiB │ 2.5 MiB │ -116.5 KiB

Slide 130

Slide 130 text

github.com/JakeWharton/picnic │ compressed │ uncompressed ├───────────┬───────────┬────────────┼───────────┬───────────┬──────────── APK │ old │ new │ diff │ old │ new │ diff ──────────┼───────────┼───────────┼────────────┼───────────┼───────────┼──────────── dex │ 830.2 KiB │ 830.2 KiB │ 0 B │ 1.8 MiB │ 1.8 MiB │ 0 B arsc │ 318.2 KiB │ 201.7 KiB │ -116.5 KiB │ 318.1 KiB │ 201.6 KiB │ -116.5 KiB manifest │ 1.4 KiB │ 1.4 KiB │ 0 B │ 4.2 KiB │ 4.2 KiB │ 0 B res │ 414.5 KiB │ 414.5 KiB │ 0 B │ 488.3 KiB │ 488.3 KiB │ 0 B asset │ 0 B │ 0 B │ 0 B │ 0 B │ 0 B │ 0 B other │ 37.1 KiB │ 37.1 KiB │ 0 B │ 36.3 KiB │ 36.3 KiB │ 0 B ──────────┼───────────┼───────────┼────────────┼───────────┼───────────┼──────────── total │ 1.6 MiB │ 1.5 MiB │ -116.5 KiB │ 2.6 MiB │ 2.5 MiB │ -116.5 KiB

Slide 131

Slide 131 text

github.com/JakeWharton/diffuse

Slide 132

Slide 132 text

github.com/JakeWharton/diffuse TODOs...

Slide 133

Slide 133 text

github.com/JakeWharton/diffuse • Standalone HTML output TODOs...

Slide 134

Slide 134 text

github.com/JakeWharton/diffuse • Standalone HTML output • Pre-formatted GitHub/Stash BitBucket Server comments TODOs...

Slide 135

Slide 135 text

github.com/JakeWharton/diffuse • Standalone HTML output • Pre-formatted GitHub/Stash BitBucket Server comments • Tests TODOs...

Slide 136

Slide 136 text

github.com/JakeWharton/diffuse • Standalone HTML output • Pre-formatted GitHub/Stash BitBucket Server comments • Tests • More lint checks TODOs...

Slide 137

Slide 137 text

Diffusing Changes in Your APK @JakeWharton