Save 37% off PRO during our Black Friday Sale! »

How to Build Awesome Android Libraries (Droidcon Webinar)

How to Build Awesome Android Libraries (Droidcon Webinar)

This talk is a collection of advice about building Android libraries or SDKs, highlighting some of the less obvious things you can do to make your library great.

Many of the recommendations will also make your life easier in any multi-module project, even if you're not publishing libraries anywhere.

All of this is based on my own open-source library development work - which I do both in my free time and at my day job working on the Stream Chat Android SDK.

More info and resources: https://zsmb.co/appearances/droidcon-webinar-june-2021/

4047c64e3a1e2f81addd4ba675ddc451?s=128

Marton Braun

June 17, 2021
Tweet

Transcript

  1. zsmb.co zsmb13 How to Build Awesome Android Libraries Márton Braun

  2. Introduction

  3. Introduction MaterialDrawerKt zsmb13/MaterialDrawerKt

  4. Introduction RainbowCake rainbowcake/rainbowcake MaterialDrawerKt zsmb13/MaterialDrawerKt

  5. Introduction RainbowCake rainbowcake/rainbowcake Krate AutSoft/Krate MaterialDrawerKt zsmb13/MaterialDrawerKt

  6. Introduction RainbowCake rainbowcake/rainbowcake Krate AutSoft/Krate MaterialDrawerKt zsmb13/MaterialDrawerKt requireKTX zsmb13/requireKTX

  7. GetStream/stream-chat-android › Open source chat SDK

  8. GetStream/stream-chat-android › Open source chat SDK › Low-level client with

    real-time events
  9. GetStream/stream-chat-android › Open source chat SDK › Low-level client with

    real-time events
  10. GetStream/stream-chat-android › Open source chat SDK › Low-level client with

    real-time events › Offline support › Pre-built UI components
  11. GetStream/stream-chat-android › Open source chat SDK › Low-level client with

    real-time events › Offline support › Pre-built UI components
  12. GetStream/stream-chat-android › Open source chat SDK › Low-level client with

    real-time events › Offline support › Pre-built UI components › Kotlin-first APIs
  13. GetStream/stream-chat-android › Open source chat SDK › Low-level client with

    real-time events › Offline support › Pre-built UI components › Kotlin-first APIs › Free for makers!
  14. GetStream/stream-chat-android

  15. TL;DW Minimize ALL the things!

  16. TL;DW Minimize ALL the things! › Features of the library

  17. TL;DW Minimize ALL the things! › Features of the library

    › Public API
  18. TL;DW Minimize ALL the things! › Features of the library

    › Public API › Dependencies
  19. TL;DW Minimize ALL the things! › Features of the library

    › Public API › Dependencies › Performance impact
  20. TL;DW Minimize ALL the things! › Features of the library

    › Public API › Dependencies › Performance impact › Enabled features by default
  21. TL;DW Minimize ALL the things! › Features of the library

    › Public API › Dependencies › Performance impact › Enabled features by default › Requirements
  22. Public API

  23. Public API › Minimal API

  24. Public API › Minimal API Item 15: Minimize the accessibility

    of classes and members
  25. Public API › Minimal API › Deprecations

  26. Public API › Minimal API › Deprecations

  27. Public API › Minimal API › Deprecations › Easy to

    use
  28. Public API › Minimal API › Deprecations › Easy to

    use › Hard to misuse
  29. Public API zsmb.co/talks/mastering-api-visibility/ › Minimal API › Deprecations › Easy

    to use › Hard to misuse › Controlling visibility
  30. Public API › Minimal API › Deprecations › Easy to

    use › Hard to misuse › Controlling visibility › Validating
  31. Public API › Minimal API › Deprecations › Easy to

    use › Hard to misuse › Controlling visibility › Validating
  32. Public API › Minimal API › Deprecations › Easy to

    use › Hard to misuse › Controlling visibility › Validating
  33. Public API › Minimal API › Deprecations › Easy to

    use › Hard to misuse › Controlling visibility › Validating
  34. Public API › Minimal API › Deprecations › Easy to

    use › Hard to misuse › Controlling visibility › Validating › Dependencies interface ChatClient { fun sendMessage(message: Message): Message }
  35. Public API › Minimal API › Deprecations › Easy to

    use › Hard to misuse › Controlling visibility › Validating › Dependencies interface ChatClient { suspend fun sendMessage(message: Message): Message }
  36. Public API › Minimal API › Deprecations › Easy to

    use › Hard to misuse › Controlling visibility › Validating › Dependencies interface ChatClient { fun sendMessage(message: Message): Single<Message> }
  37. Public API › Minimal API › Deprecations › Easy to

    use › Hard to misuse › Controlling visibility › Validating › Dependencies public interface Call<T> { public fun execute(): Result<T> public fun enqueue(callback: Callback<T>) } public suspend fun <T> Call<T>.await(): Result<T>
  38. Dependencies

  39. Dependencies › Minimal dependencies

  40. Dependencies › Minimal dependencies › Size

  41. Dependencies Install conversion rate increase per 10MB decrease in APK

    size by select market (Google internal data, late 2017) › Minimal dependencies › Size
  42. Dependencies › Minimal dependencies › Size › Many libraries per

    app Install conversion rate increase per 10MB decrease in APK size by select market (Google internal data, late 2017)
  43. Dependencies › Minimal dependencies › Size › Many libraries per

    app › Library present in multiple apps
  44. Dependencies › Minimal dependencies › Size › Many libraries per

    app › Library present in multiple apps › Complexity
  45. Dependencies › Minimal dependencies › Size › Many libraries per

    app › Library present in multiple apps › Complexity › Version conflicts
  46. Dependencies Library 2 Library 1 Appcompat 1.4 alpha Appcompat 1.2

    App › Minimal dependencies › Size › Many libraries per app › Library present in multiple apps › Complexity › Version conflicts
  47. Dependencies › Minimal dependencies › Size › Many libraries per

    app › Library present in multiple apps › Complexity › Version conflicts Library 2 Library 1 Appcompat 1.4 alpha Appcompat 1.2 App
  48. Dependencies › Minimal dependencies › Size › Many libraries per

    app › Library present in multiple apps › Complexity › Version conflicts Library 1 Appcompat 1.4 alpha Appcompat 1.2 App Library 2
  49. Version updates

  50. Version updates

  51. implementation vs api Library 1 App

  52. implementation vs api Library 1 Library 2 App implementation

  53. implementation vs api Library 1 Library 2 App api Library

    1 Library 2 App implementation
  54. library.aar

  55. library.aar resources layout.xml values.xml

  56. library.aar resources layout.xml values.xml AndroidManifest.xml

  57. library.aar resources layout.xml values.xml AndroidManifest.xml classes.jar

  58. library.aar resources layout.xml values.xml AndroidManifest.xml classes.jar R.txt

  59. library.aar resources layout.xml values.xml AndroidManifest.xml classes.jar R.txt library- sources.jar library-

    javadoc.jar *.kt *.html
  60. The POM file library.pom <?xml version="1.0" encoding="UTF-8"?> <project> <groupId>io.getstream</groupId> <artifactId>stream-chat-android-client</artifactId>

    <version>4.12.0</version> <packaging>aar</packaging> <name>stream-chat-android-client</name> <dependencies> <dependency> <groupId>org.jetbrains.kotlin</groupId> <artifactId>kotlin-stdlib</artifactId> <version>1.5.10</version> <scope>runtime</scope> </dependency> ... </dependencies> </project> library.aar resources layout.xml values.xml AndroidManifest.xml classes.jar R.txt library- sources.jar library- javadoc.jar *.kt *.html
  61. The POM file library.pom <?xml version="1.0" encoding="UTF-8"?> <project> <groupId>io.getstream</groupId> <artifactId>stream-chat-android-client</artifactId>

    <version>4.12.0</version> <packaging>aar</packaging> <name>stream-chat-android-client</name> <dependencies> <dependency> <groupId>org.jetbrains.kotlin</groupId> <artifactId>kotlin-stdlib</artifactId> <version>1.5.10</version> <scope>runtime</scope> </dependency> ... </dependencies> </project>
  62. The POM file library.pom <?xml version="1.0" encoding="UTF-8"?> <project> <groupId>io.getstream</groupId> <artifactId>stream-chat-android-client</artifactId>

    <version>4.12.0</version> <packaging>aar</packaging> <name>stream-chat-android-client</name> <dependencies> <dependency> <groupId>org.jetbrains.kotlin</groupId> <artifactId>kotlin-stdlib</artifactId> <version>1.5.10</version> <scope>runtime</scope> </dependency> ... </dependencies> </project>
  63. The POM file library.pom <?xml version="1.0" encoding="UTF-8"?> <project> <groupId>io.getstream</groupId> <artifactId>stream-chat-android-client</artifactId>

    <version>4.12.0</version> <packaging>aar</packaging> <name>stream-chat-android-client</name> <dependencies> <dependency> <groupId>org.jetbrains.kotlin</groupId> <artifactId>kotlin-stdlib</artifactId> <version>1.5.10</version> <scope>runtime</scope> </dependency> ... </dependencies> </project>
  64. Repositories MavenCentral Library 1

  65. Repositories MavenCentral Jitpack Jcenter Library 3 Library 2 Library 1

  66. Repositories MavenCentral Jitpack Jcenter Library 3 Library 2 Library 1

  67. Repositories App MavenCentral Jitpack Jcenter Library 3 Library 2 Library

    1
  68. Repositories App MavenCentral Jitpack Jcenter Library 3 Library 2 Library

    1
  69. Repositories App MavenCentral Jitpack Jcenter Library 3 Library 2 Library

    1
  70. Repositories App MavenCentral Jitpack Jcenter Library 3 Library 2 Library

    1
  71. Multi-module libraries my-awesome-lib

  72. Multi-module libraries my-awesome-lib

  73. Multi-module libraries my-awesome-lib my-awesome-lib-plus my-awesome-lib-core

  74. Multi-module libraries my-awesome-lib-plus my-awesome-lib-core my-awesome-lib

  75. rx Multi-module libraries my-awesome-lib-plus my-awesome-lib-core

  76. Multi-module libraries plus rxjava my-awesome-lib-rx my-awesome-lib-core

  77. Fat AARs ui-components core offline client

  78. Fat AARs ui-components core offline client App

  79. Fat AARs ui-components core offline client App

  80. Fat AARs ui-components core offline client App

  81. Fat AARs

  82. Fat AARs

  83. Fat AARs

  84. Fat AARs

  85. Fat AARs "At the moment we are talking with Gradle

    about being able to merge dependencies from multiple projects (that are being bundled), as that part is a problem in the JVM ecosystem as well. Once that is in, we can focus on the Android-specific features (Android resources, manifest etc.)." 2020-12-02
  86. Fat AARs android-fat-aar adwiv/android-fat-aar

  87. Fat AARs android-fat-aar adwiv/android-fat-aar

  88. Fat AARs fat-aar-plugin vigidroid/fat-aar-plugin android-fat-aar adwiv/android-fat-aar

  89. Fat AARs fat-aar-plugin vigidroid/fat-aar-plugin android-fat-aar adwiv/android-fat-aar

  90. Fat AARs fat-aar-plugin vigidroid/fat-aar-plugin fataar-gradle-plugin Mobbeel/fataar-gradle-plugin android-fat-aar adwiv/android-fat-aar

  91. Fat AARs fat-aar-plugin vigidroid/fat-aar-plugin fataar-gradle-plugin Mobbeel/fataar-gradle-plugin android-fat-aar adwiv/android-fat-aar

  92. Fat AARs fat-aar-plugin vigidroid/fat-aar-plugin fataar-gradle-plugin Mobbeel/fataar-gradle-plugin fat-aar-android kezong/fat-aar-android android-fat-aar adwiv/android-fat-aar

  93. Startup impact

  94. Startup impact › Don’t hog startup › Competing with other

    libraries
  95. Startup impact › Don’t hog startup › Competing with other

    libraries › Initialize on-demand
  96. Startup impact › Don’t hog startup › Competing with other

    libraries › Initialize on-demand › App Startup
  97. Logging

  98. Logging › Don’t log by default

  99. Logging › Don’t log by default val client = ChatClient.Builder("apiKey",

    context) .logLevel(ChatLogLevel.ALL) .build()
  100. Logging › Don’t log by default › Don’t enable any

    feature by default val client = ChatClient.Builder("apiKey", context) .logLevel(ChatLogLevel.ALL) .build()
  101. Performance › Minimize your impact › You’re in the inner

    loop › You’re in a lot of apps
  102. Requirements › Minimal requirements › Make integrating your library easy

    › Don’t force things on your clients
  103. API level App Library 1 Library 2 Library 3 API

    21 API 21 API 19 API 15
  104. API level App Library 1 Library 2 Library 3 API

    21 API 21 API 19 API 15
  105. API level App Library 1 Library 2 Library 3 API

    21 API 21 API 23 API 15
  106. API level App Library 1 Library 2 Library 3 API

    23 API 21 API 23 API 15
  107. Permissions & features library.aar resources layout.xml values.xml AndroidManifest.xml classes.jar R.txt

  108. Permissions & features <?xml version="1.0" encoding="utf-8"?> <manifest> <uses-sdk android:minSdkVersion="21" android:targetSdkVersion="29"

    /> <uses-feature android:name="android.hardware.bluetooth" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.CAMERA" /> <application> <provider /> <activity /> <activity /> </application> </manifest> library.aar resources layout.xml values.xml AndroidManifest.xml classes.jar R.txt
  109. Permissions & features <?xml version="1.0" encoding="utf-8"?> <manifest> <uses-sdk android:minSdkVersion="21" android:targetSdkVersion="29"

    /> <uses-feature android:name="android.hardware.bluetooth" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.CAMERA" /> <application> <provider /> <activity /> <activity /> </application> </manifest> AndroidManifest.xml
  110. <?xml version="1.0" encoding="utf-8"?> <manifest> <uses-sdk android:minSdkVersion="21" android:targetSdkVersion="29" /> <uses-feature android:name="android.hardware.bluetooth"

    /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.CAMERA" /> <application> <provider /> <activity /> <activity /> </application> </manifest> Permissions & features AndroidManifest.xml
  111. <?xml version="1.0" encoding="utf-8"?> <manifest> <uses-sdk android:minSdkVersion="21" android:targetSdkVersion="29" /> <uses-feature android:name="android.hardware.bluetooth"

    /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.CAMERA" /> <application> <provider /> <activity /> <activity /> </application> </manifest> Permissions & features AndroidManifest.xml
  112. <?xml version="1.0" encoding="utf-8"?> <manifest> <uses-sdk android:minSdkVersion="21" android:targetSdkVersion="29" /> <uses-feature android:name="android.hardware.bluetooth"

    /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.CAMERA" /> <application> <provider /> <activity /> <activity /> </application> </manifest> Permissions & features AndroidManifest.xml
  113. Resource prefixes android { resourcePrefix 'stream_ui_' }

  114. Resource prefixes <?xml version="1.0" encoding="utf-8"?> <resources> <color name="stream_ui_accent_blue">#005FFF</color> <color name="stream_ui_accent_red">#FF3742</color>

    <color name="stream_ui_ ">#20E070</color> </resources> accent_green android { resourcePrefix 'stream_ui_' }
  115. Resource prefixes android { resourcePrefix 'stream_ui_' } <?xml version="1.0" encoding="utf-8"?>

    <resources> <color name="stream_ui_accent_blue">#005FFF</color> <color name="stream_ui_accent_red">#FF3742</color> <color name=" ">#20E070</color> </resources> accent_green
  116. Resource prefixes android { resourcePrefix 'stream_ui_' } <?xml version="1.0" encoding="utf-8"?>

    <resources> <color name="stream_ui_accent_blue">#005FFF</color> <color name="stream_ui_accent_red">#FF3742</color> <color name=" ">#20E070</color> </resources> accent_green Resource named 'accent_green' does not start with the project's resource prefix 'stream_ui_'; rename to 'stream_ui_accent_green' ?
  117. Resource prefixes android { resourcePrefix 'stream_ui_' } <?xml version="1.0" encoding="utf-8"?>

    <resources> <declare-styleable name="MessageInputView"> <attr name="streamUiAttachButtonEnabled" format="boolean" /> <attr name="streamUiAttachButtonIcon" format="reference" /> <attr name="streamUiMentionsEnabled" format="boolean" /> <attr name="streamUiMentionsIcon" format="reference" /> <attr name="streamUiAttachmentMaxFileSizeMb" format="integer" /> </declare-styleable> </resources>
  118. Resource prefixes android { resourcePrefix 'stream_ui_' }

  119. Private resources

  120. Private resources <?xml version="1.0" encoding="utf-8"?> <resources> <public name="mylib_app_name" type="string" />

    <public name="mylib_public_string" type="string" /> </resources>
  121. Explicitly public resources <?xml version="1.0" encoding="utf-8"?> <resources> <public name="mylib_app_name" type="string"

    /> <public name="mylib_public_string" type="string" /> </resources>
  122. Proguard library.aar resources layout.xml values.xml AndroidManifest.xml classes.jar R.txt

  123. Proguard ## Stream Chat Android Client Proguard Rules -keep class

    io.getstream.chat.android.client.api.* { *; } -keep class io.getstream.chat.android.client.api.models.* { *; } -keep class io.getstream.chat.android.client.api2.model.** { *; } -keep class io.getstream.chat.android.client.errors.* { *; } -keep class io.getstream.chat.android.client.events.* { *; } -keep class io.getstream.chat.android.client.models.* { *; } -keep class io.getstream.chat.android.client.parser.* { *; } -keep class io.getstream.chat.android.client.socket.* { *; } -keep class io.getstream.chat.android.client.utils.Result { *; } -keep class io.getstream.chat.android.client.utils.SyncStatus { *; } library.aar resources layout.xml values.xml AndroidManifest.xml classes.jar R.txt proguard.txt
  124. Proguard ## Stream Chat Android Client Proguard Rules -keep class

    io.getstream.chat.android.client.api.* { *; } -keep class io.getstream.chat.android.client.api.models.* { *; } -keep class io.getstream.chat.android.client.api2.model.** { *; } -keep class io.getstream.chat.android.client.errors.* { *; } -keep class io.getstream.chat.android.client.events.* { *; } -keep class io.getstream.chat.android.client.models.* { *; } -keep class io.getstream.chat.android.client.parser.* { *; } -keep class io.getstream.chat.android.client.socket.* { *; } -keep class io.getstream.chat.android.client.utils.Result { *; } -keep class io.getstream.chat.android.client.utils.SyncStatus { *; } proguard.txt
  125. Proguard ## Stream Chat Android Client Proguard Rules -keep class

    io.getstream.chat.android.client.api.* { *; } -keep class io.getstream.chat.android.client.api.models.* { *; } -keep class io.getstream.chat.android.client.api2.model.** { *; } -keep class io.getstream.chat.android.client.errors.* { *; } -keep class io.getstream.chat.android.client.events.* { *; } -keep class io.getstream.chat.android.client.models.* { *; } -keep class io.getstream.chat.android.client.parser.* { *; } -keep class io.getstream.chat.android.client.socket.* { *; } -keep class io.getstream.chat.android.client.utils.Result { *; } -keep class io.getstream.chat.android.client.utils.SyncStatus { *; } -dontoptimize -dontshrink proguard.txt
  126. Proguard android { buildTypes { release { proguardFiles getDefaultProguardFile('proguard-android-optimize.txt’), 'proguard-rules.pro'

    consumerProguardFiles 'consumer-proguard-rules.pro' } debug { consumerProguardFiles 'consumer-proguard-rules.pro' } } }
  127. Proguard android { buildTypes { release { proguardFiles getDefaultProguardFile('proguard-android-optimize.txt’), 'proguard-rules.pro'

    consumerProguardFiles 'consumer-proguard-rules.pro' } debug { consumerProguardFiles 'consumer-proguard-rules.pro' } } }
  128. Proguard android { buildTypes { release { proguardFiles getDefaultProguardFile('proguard-android-optimize.txt’), 'proguard-rules.pro'

    consumerProguardFiles 'consumer-proguard-rules.pro' } debug { consumerProguardFiles 'consumer-proguard-rules.pro' } } }
  129. Testing

  130. Testing › Lots of responsibility

  131. Testing › Lots of responsibility › Diverse environments

  132. Testing › Lots of responsibility › Diverse environments › Can’t

    assume anything
  133. Testing › Lots of responsibility › Diverse environments › Can’t

    assume anything › Devices, architectures, OS versions, stores
  134. Testing › Lots of responsibility › Diverse environments › Can’t

    assume anything › Devices, architectures, OS versions, stores › Other frameworks and libraries
  135. Testing › Lots of responsibility › Diverse environments › Can’t

    assume anything › Devices, architectures, OS versions, stores › Other frameworks and libraries › Your code is not final
  136. Documentation

  137. Documentation › Have documentation

  138. Documentation › Have documentation › README

  139. Documentation › Have documentation › README › What it does

  140. Documentation › Have documentation › README › What it does

    › Setup instructions
  141. Documentation › Have documentation › README › What it does

    › Setup instructions › Screenshots
  142. Documentation › Have documentation › README › Code comments

  143. Documentation › Have documentation › README › Code comments

  144. Documentation › Have documentation › README › Code comments

  145. Documentation › Have documentation › README › Code comments ›

    Sample app
  146. Documentation › Have documentation › README › Code comments ›

    Sample app › Update strategy
  147. Publishing

  148. Publishing › Maven repositories

  149. Publishing › Maven repositories › Main options

  150. Publishing › Maven repositories › Main options › Jcenter

  151. Publishing › Maven repositories › Main options › Jcenter

  152. Publishing › Maven repositories › Main options › Jcenter

  153. Publishing › Maven repositories › Main options › Jcenter

  154. Publishing › Maven repositories › Main options › Jcenter ›

    Jitpack
  155. Publishing › Maven repositories › Main options › Jcenter ›

    Jitpack
  156. Publishing › Maven repositories › Main options › Jcenter ›

    Jitpack › Maven Central
  157. Publishing › Maven repositories › Main options › Jcenter ›

    Jitpack › Maven Central
  158. Publishing › Coordinates

  159. Publishing › Coordinates io.getstream:stream-chat-android-client:4.12.0

  160. Publishing › Coordinates io.getstream : stream-chat-android-client : 4.12.0 Group ID

    Version Artifact ID
  161. Publishing Group ID io.getstream : stream-chat-android-client : 4.12.0 Version Artifact

    ID › Coordinates
  162. Publishing › Coordinates io.getstream : stream-chat-android-client : 4.12.0 Group ID

    Version Artifact ID
  163. Publishing › Coordinates › Versioning io.getstream : stream-chat-android-client : 4.12.0

    Group ID Version Artifact ID
  164. Publishing › Coordinates › Versioning semver.org io.getstream : stream-chat-android-client :

    4.12.0 Group ID Version Artifact ID
  165. Publishing › Coordinates › Versioning › License

  166. Publishing › Coordinates › Versioning › License tldrlegal.com

  167. Release checklist

  168. Community

  169. Community › Open source vs source available

  170. Community › Open source vs source available › Address issues

    and discussions
  171. Community › Open source vs source available › Address issues

    and discussions › Take PR contributions
  172. Community › Open source vs source available › Address issues

    and discussions › Take PR contributions › Be open for feedback*
  173. Community › Open source vs source available › Address issues

    and discussions › Take PR contributions › Be open for feedback* “You're supposed to side with the community, but you should also have a say in what you're building” – Filip Babić
  174. Resources • Nishant Srivastava’s excellent talks  Things I wish

    I knew when I started building Android SDK/Libraries  https://www.youtube.com/watch?v=G-x9wRWwICo  Things I wish I knew when I started building Android Libraries Vol 2  https://www.youtube.com/watch?v=jQyt3HSmx2I • Mastering API Visibility in Kotlin  https://zsmb.co/talks/mastering-api-visibility/  Kotlin/binary-compatibility-validator  https://github.com/Kotlin/binary-compatibility-validator • Publishing Android libraries to MavenCentral in 2021  https://proandroiddev.com/publishing-android-libraries-to-mavencentral-in-2021-8ac9975c3e52
  175. Resources • Jeroen Mols’ library development articles  https://jeroenmols.com/blog/2020/10/28/library-gettingstarted/ 

    What is a library and how is it deployed  https://jeroenmols.com/blog/2020/11/04/library-modularization/  Publishing submodules, fat AARs, controlling access  https://jeroenmols.com/blog/2020/11/11/library-dependencies/  Dependency conflicts and version incompatibilities • More on fat AARs  Sam Edwards’ article  https://handstandsam.com/2018/07/13/why-we-need-fat-aars-for-android-libraries/  Open issue on Google’s issue tracker  https://issuetracker.google.com/issues/62121508
  176. zsmb13 zsmb.co/talks

  177. How to Build Awesome Android Libraries zsmb.co/talks zsmb13 Márton Braun

    › Minimize all the things! › Public API › Dependencies › Size and impact › Publishing and releases › Don’t forget the docs!