Diffusing Changes in Your APKs (Droidcon Toronto 2019)

E68309f117985270285ade8082f4877d?s=47 Jake Wharton
November 13, 2019

Diffusing Changes in Your APKs (Droidcon Toronto 2019)

Nearly every change to your project affects the final APK is some way. Whether adding a method, removing a class, updating a dependency, changing the Android Gradle plugin version, importing new translations, or refactoring a layout XML, all of these will change the size of your APK.

But what is actually going on in the APK when you make these changes? Each affects more than you think. Unfortunately, there's little visibility into this aside from birds-eye-view numbers like APK size and method count. Diffuse is a tool which aims to help provide that insight by breaking down the changes based on what is affected and then showing granular diffs.

This talk will go through examples of each of the scenarios above and explore how the tool surfaces what actually changes as a result. With each example, we'll explore what makes up an APK (and other formats like AAR, JAR, and AAB). Finally, we'll talk about how you can integrate diffuse into your development workflow so its reports are available automatically for every change.

Video: coming soon

E68309f117985270285ade8082f4877d?s=128

Jake Wharton

November 13, 2019
Tweet

Transcript

  1. Diffusing Changes in Your APK @JakeWharton

  2. 2½ years ago…

  3. jakes.link/hidden-changes

  4. None
  5. None
  6. None
  7. None
  8. None
  9. 6 months ago…

  10. Analysis Files

  11. Files Analysis

  12. ApkDiffStats:WhateverReleaseApp ApkDiffStats:WhateverDebugApp + + Files Analysis

  13. ApkDiffStats:WhateverDebugApp + Files Analysis + ApkDiffStats:WhateverReleaseApp

  14. 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 +
  15. 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
  16. None
  17. None
  18. Present day

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

  20. $ 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 ─────────┼───────┼───────┼────────────
  21. $ 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 ─────────┼───────┼───────┼────────────
  22. $ 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)
  23. 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 ====
  24. 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)
  25. 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)
  26. ================= ==== 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:
  27. - %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
  28. 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
  29. Why?

  30. $2.79 vs. $2.99

  31. $2.79 vs. $2.99 METHODS: old │ new │ diff ─────┼─────┼──────────────

    279 │ 299 │ +20 (+25 -5)
  32. $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)
  33. jakes.link/generated-economics

  34. jakes.link/generated-economics

  35. jakes.link/dex-ed

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

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

  38. 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)
  39. 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
  40. 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
  41. 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
  42. android { … defaultConfig { applicationId 'com.jakewharton.sdksearch' … } }

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

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

  45. $ 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
  46. $ 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
  47. 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 ====
  48. 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)
  49. 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
  50. ================== ==== 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
  51. - 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
  52. android { … defaultConfig { minSdkVersion 23 … } }

  53. android { … defaultConfig { - minSdkVersion 23 + minSdkVersion

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

  55. $ 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
  56. $ 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
  57. 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 ==== =================
  58. 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
  59. 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 ====
  60. SIGNATURES │ old │ new ────────────┼──────────────────────────────────────────┼───────────────────────────────── V1 │ abbd3cd5f23b986a66a40afae4931e063e32f112 │

    V2 │ abbd3cd5f23b986a66a40afae4931e063e32f112 │ abbd3cd5f23b986a66a40afae4931e06 ====================== ==== MANIFEST ==== ====================== @@ -13,3 +13,3 @@ <uses-sdk - android:minSdkVersion="23" + android:minSdkVersion="24" android:targetSdkVersion="29" ================= ==== DEX ==== ================= STRINGS: old │ new │ diff ───────┼───────┼────────────
  61. ================= ==== 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;
  62. - ~~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
  63. + 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
  64. $ diffuse diff \ 
 plaid-base.aab \
 plaid-min-sdk-24.aab

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

  66. $ 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:
  67. $ 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:
  68. =================== ==== 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 @@ <uses-sdk - android:minSdkVersion="23" + android:minSdkVersion="24" android:targetSdkVersion="28"
  69. ========================== ==== 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)
  70. - ~~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
  71. 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 @@ <uses-sdk - android:minSdkVersion="23" + android:minSdkVersion="24" android:targetSdkVersion="28" ====================== ==== dribbble ==== ======================
  72. ====================== ==== 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)
  73. ==================== ==== 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 @@ <uses-sdk - android:minSdkVersion="23" + android:minSdkVersion="24" android:targetSdkVersion="28"
  74. $ diffuse diff --aar \
 rxbinding-2.1.0.aar \
 rxbinding-2.1.1.aar

  75. $ 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)
  76. $ 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)
  77. 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)
  78. 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
  79. ================= ==== 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 <init>() FIELDS:
  80. - com.jakewharton.rxbinding2.BuildConfig METHODS: old │ new │ diff ──────┼──────┼──────────── 1023

    │ 1022 │ -1 (+0 -1) - com.jakewharton.rxbinding2.BuildConfig <init>() 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
  81. $ diffuse diff --jar \
 okhttp-4.0.0.jar \
 okhttp-4.1.0.jar

  82. $ 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 ====
  83. $ 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 ====
  84. ───────┼──────────┼──────────┼────────── 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
  85. 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 ====
  86. ===================== ==== 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:
  87. + 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
  88. $ diffuse diff \
 sdk-search-release-gradle.apk \
 sdk-search-release-recompressed.apk

  89. $ 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
  90. $ 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
  91. $ 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
  92. Productionizing

  93. On Master and Branch Success

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

    and Branch Success
  95. $ 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
  96. $ find /shared/project -mtime +20 -exec rm {} \; For

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

    Single, Shared Machine: For Cloud Workers: $ curl ...list objects... $ curl ...delete objects...
  98. master

  99. jw/whoooops master

  100. jw/whoooops master

  101. jw/whoooops master

  102. master jw/whoooops

  103. master jw/whoooops

  104. master jw/whoooops

  105. master jw/whoooops

  106. jw/whoooops

  107. jw/whoooops $ git fetch origin master

  108. origin/master jw/whoooops $ git fetch origin master

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

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

    git fetch origin master
  111. origin/master jw/whoooops $ git fetch origin master $ git merge-base

    --all $GIT_SHA origin/master 0d2eef7a2f54ac3e505f11f978cfa097d8bfed14
  112. $ diffuse diff \
 /shared/project/$MERGE_BASE_SHA.apk app/build/outputs/apk/release/*.apk For Single, Shared Machine:

  113. $ 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
  114. val apkPath = …

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

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

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

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

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

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

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

    .flatMap { it.declaredMembers } .size // toAab() // toAar() // toJar() // Send to analytics, reporting, etc…
  122. 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…
  123. │ 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
  124. │ 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
  125. │ 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
  126. │ 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
  127. │ 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
  128. │ 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
  129. │ 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
  130. 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
  131. github.com/JakeWharton/diffuse

  132. github.com/JakeWharton/diffuse TODOs...

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

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

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

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

    comments • Tests • More lint checks TODOs...
  137. Diffusing Changes in Your APK @JakeWharton