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

The definitive guide to Android library development

The definitive guide to Android library development

Video: https://www.droidcon.com/2021/11/10/the-definitive-guide-to-android-library-development/

Android library/SDK development unfortunately is harder than it should be. This is caused by inferior tooling (Why do you need fat AAR?), missing documentation (What causes transitive dependency conflicts?), and different architecture considerations (Should you modularize your SDK?).

Having switched to full-time Android SDK development two years ago, I'm summarizing my lessons learned into a talk I wish would have existed when I got started.

⚠️ This talk is aimed at anyone curious to level up their knowledge of the Android ecosystem, not just at beginning/seasoned SDK developers!

---------------------------

Further reads:
- Maintaining compatibility in Kotlin libraries by Márton Braun
- The hidden Kotlin gem: Deprecations with ReplaceWith by Marc Reichelt
- Publishing libraries to Maven Central in 2021 by Marton Braun
- Java interoperability policy for major version updates by Jake Wharton
- Public API challenges in Kotlin by Jake Wharton
- How to publish and distribute your Android library by Marco Gomiero
- What is a diamond dependency conflict by Google
- All about Opt-in annotationsby Márton Braun

5f57d2d205e77e185986459c1b89a874?s=128

Jeroen Mols

October 20, 2021
Tweet

Transcript

  1. @MOLSJEROEN THE DEFINITIVE GUIDE TO ANDROID LIBRARY DEVELOPMENT

  2. @MOLSJEROEN

  3. @MOLSJEROEN GOAL OUR FIRST LIBRARY TRANSITIVE DEPENDENCIES MODULARIZATION DEPENDENCY CONFLICTS

    TIPS & TOOLS
  4. @MOLSJEROEN TERMINOLOGY • Software Development Kit (SDK) • Android library

  5. GOAL

  6. @MOLSJEROEN ANDROID LIBRARIES APP

  7. @MOLSJEROEN ANDROID LIBRARIES APP COMPOSE OKHTTP …

  8. @MOLSJEROEN ANDROID LIBRARIES APP COMPOSE OKHTTP … MAVEN

  9. @MOLSJEROEN ANDROID LIBRARIES COMPOSE OKHTTP … MAVEN APP MODULE 1

    MODULE 2
  10. @MOLSJEROEN ANDROID LIBRARIES COMPOSE OKHTTP LIBRARY MAVEN APP MODULE 1

    MODULE 2
  11. @MOLSJEROEN ANDROID LIBRARIES dependencies { implementation "com.jeroenmols:library:1.0.0" }

  12. OUR FIRST LIBRARY

  13. ANDROID STUDIO TO THE RESCUE!

  14. @MOLSJEROEN

  15. TOOLING FOR ANDROID LIBRARIES IS LACKING

  16. @MOLSJEROEN ANDROID STUDIO PROJECT PROJECT APP

  17. @MOLSJEROEN

  18. @MOLSJEROEN ANDROID STUDIO PROJECT LIBRARY APP PROJECT

  19. @MOLSJEROEN

  20. @MOLSJEROEN

  21. @MOLSJEROEN

  22. @MOLSJEROEN

  23. @MOLSJEROEN RUN & TEST $./gradlew :app:installDebu g $ ./gradlew :library:testDebugUnitTes

    t $ ./gradlew :library:connectedAndroidTest
  24. @MOLSJEROEN BUILD $ ./gradlew :library:assembleRelease

  25. @MOLSJEROEN

  26. @MOLSJEROEN APK •Compiled code •Processed resources •Android manifest •Compiled transitive

    dependencies •Can be run on Android device •Signed JAR •Compiled code •Cannot be run on Android device •Unsigned
  27. @MOLSJEROEN APK •Compiled code •Processed resources •Android manifest •Compiled transitive

    dependencies •Can be run on Android device •Signed AAR •Compiled code •Processed resources •Android manifest •Cannot be run on Android device •Unsigned
  28. @MOLSJEROEN DISTRIBUTE - STEPS 1.Build a release (see before) 2.Generate

    and publish PGP key 3.Sign build 4.Upload to Maven central => Tutorial by Márton Braun: 
 https://getstream.io/blog/publishing-libraries-to-mavencentral-2021/
  29. TOOLING FOR ANDROID LIBRARIES IS LACKING

  30. TRANSITIVE DEPENDENCIES

  31. @MOLSJEROEN EXTERNAL DEPENDENCIES LIBRARY APP PROJECT MAVEN OKHTTP

  32. @MOLSJEROEN EXTERNAL DEPENDENCIES PROJECT MAVEN CUSTOMER APP LIBRARY

  33. @MOLSJEROEN EXTERNAL DEPENDENCIES PROJECT MAVEN OKHTTP CUSTOMER APP LIBRARY

  34. @MOLSJEROEN EXTERNAL DEPENDENCIES dependencies { implementation "com.jeroenmols:library:1.0.0" implementation "com.squareup.okhttp3:okhttp:4.9.2" }

  35. @MOLSJEROEN TRANSITIVE DEPENDENCIES dependencies { implementation "com.jeroenmols:library:1.0.0" }

  36. @MOLSJEROEN EXTERNAL DEPENDENCIES PROJECT MAVEN OKHTTP CUSTOMER APP LIBRARY

  37. @MOLSJEROEN POM - XML FILE <project xmlns="http://maven.apache.org/POM/4.0.0" > <groupId>com.jeroenmols</groupId> <artifactId>library</artifactId>

    <version>1.0.0</version> <dependencies> <dependency> <groupId>com.squareup.okhttp3</groupId> <artifactId>okhttp3</artifactId> <version>4.9.0</version> </dependency> </dependencies> </project>
  38. @MOLSJEROEN POM - XML FILE <project xmlns="http://maven.apache.org/POM/4.0.0" > <groupId>com.jeroenmols</groupId> <artifactId>library</artifactId>

    <version>1.0.0</version> <dependencies > <dependency > <groupId>com.squareup.okhttp3</groupId > <artifactId>okhttp3</artifactId > <version>4.9.0</version > </dependency > </dependencies > </project>
  39. @MOLSJEROEN POM - XML FILE <project xmlns="http://maven.apache.org/POM/4.0.0" > <groupId>com.jeroenmols</groupId >

    <artifactId>library</artifactId > <version>1.0.0</version > <dependencies> <dependency> <groupId>com.squareup.okhttp3</groupId> <artifactId>okhttp3</artifactId> <version>4.9.0</version> </dependency> </dependencies > </project>
  40. @MOLSJEROEN

  41. ALWAYS TEST LIBRARIES THROUGH MAVEN

  42. MODULARIZATION

  43. @MOLSJEROEN APP MODULARISATION APP FEATURE 2 FEATURE 3 FEATURE 4

    FEATURE 5 FEATURE 6 CORE 4 CORE 4 CORE 2 CORE 3 FEATURE 1 CORE 1
  44. @MOLSJEROEN LIBRARY MODULARIZATION LIBRARY APP PROJECT DATABASE UI-COMPONENTS

  45. @MOLSJEROEN

  46. @MOLSJEROEN

  47. @MOLSJEROEN

  48. @MOLSJEROEN TEST SETUP // app Library().initialize() // library class Library

    { fun initialize() = Database().initialize() } // database class Database { fun initialize() = System.out.println(“database ready") }
  49. PROBLEM #1 
 SUBMODULES NOT INCLUDED IN AAR

  50. @MOLSJEROEN LIBRARY SUBMODULE TEST ./gradlew :library:assembleRelease

  51. @MOLSJEROEN LIBRARY SUBMODULE TEST ./gradlew :library:assembleReleas e // App build.gradl

    e dependencies { // implementation project(':library') implementation fi les('../library/build/outputs/aar/library-release.aar') ... }
  52. @MOLSJEROEN

  53. @MOLSJEROEN

  54. TOOLING FOR ANDROID LIBRARIES IS LACKING

  55. @MOLSJEROEN

  56. @MOLSJEROEN SUBMODULES NOT INCLUDED IN AAR 1. Release submodules to

    Maven 2. Fat AAR 3. Single module SDK
  57. @MOLSJEROEN 1. RELEASE SUBMODULES TO MAVEN COMPOSE LIBRARY MAVEN APP

    UI-COMPONENTS DATABASE
  58. @MOLSJEROEN 1. RELEASE SUBMODULES TO MAVEN // Library build.gradl e

    dependencies { implementation "com.jeroenmols:database:1.0.0" implementation "com.jeroenmols:ui-components:1.0.0" }
  59. @MOLSJEROEN 2. FAT AAR apply plugin: 'com.kezong.fat-aar' ... dependencies {

    embed project(path: ':modules:database', con fi guration:'default') embed project(path: ':modules:ui-components', con fi guration:'default') }
  60. @MOLSJEROEN 3. SINGLE MODULE SDK LIBRARY APP PROJECT

  61. PROBLEM #2 
 PUBLIC INTERFACE SUBMODULES EXPOSED

  62. @MOLSJEROEN KOTLIN VISIBILITY MODIFIERS • private: visible inside this class

    only • protected: same as private + visible in subclasses too • internal: visible to all classes inside this module • public: visible to all classes
  63. @MOLSJEROEN 1

  64. @MOLSJEROEN PUBLIC INTERFACE SUBMODULES EXPOSED 1. Internal package 2. Obfuscate

    non-public classes 3. Single module SDK
  65. @MOLSJEROEN 1. INTERNAL PACKAGE package com.jeroenmols.internal.database

  66. @MOLSJEROEN 2. OBFUSCATE NON-PUBLIC CLASSES package a.a.a

  67. @MOLSJEROEN 2. OBFUSCATE NON-PUBLIC CLASSES // proguard-rules.pr o repackageclasses com.jeroenmols.internal


    
 
 package com.jeroenmols.internal.a
  68. @MOLSJEROEN 3. SINGLE MODULE SDK LIBRARY APP PROJECT

  69. RECOMMENDATION LIBRARY MODULARIZATION

  70. @MOLSJEROEN MODULARIZATION RECOMMENDATION • Modularizing SDKs is tedious • Single

    module for small and mid sized SDKs • Spin off reusable maven artefacts for larger SDKs • Reduce public API surface • Tooling is lacking
  71. TRANSITIVE DEPENDENCY CONFLICTS

  72. @MOLSJEROEN TRANSITIVE DEPENDENCY CONFLICTS PROJECT MAVEN TRANSITIVE DEPENDENCY 1 CUSTOMER

    APP ANOTHER LIBRARY
  73. @MOLSJEROEN TRANSITIVE DEPENDENCY CONFLICTS PROJECT MAVEN TRANSITIVE DEPENDENCY 1 CUSTOMER

    APP ANOTHER LIBRARY LIBRARY TRANSITIVE DEPENDENCY 2 TRANSITIVE DEPENDENCY 3
  74. @MOLSJEROEN TRANSITIVE DEPENDENCY CONFLICTS 1. con fl icting transitive dependency

    versions 2. incompatible transitive dependencies
  75. PROBLEM #1 TRANSITIVE DEPENDENCY CONFLICTS

  76. @MOLSJEROEN CONFLICTING DEPENDENCY VERSIONS dependencies { implementation "com.jeroenmols:library:1.0.0" implementation "com.example:anotherlibrary:2.0.0"

    }
  77. @MOLSJEROEN TRANSITIVE DEPENDENCY CONFLICTS PROJECT MAVEN OKHTTP V3 CUSTOMER APP

    ANOTHER LIBRARY LIBRARY OKHTTP V4
  78. @MOLSJEROEN TRANSITIVE DEPENDENCY CONFLICTS PROJECT MAVEN OKHTTP V3 CUSTOMER APP

    ANOTHER LIBRARY LIBRARY OKHTTP V4
  79. @MOLSJEROEN

  80. @MOLSJEROEN CONFLICT RESOLUTION 1.Force dependency resolution in CustomerApp 2.Loosen dependency

    requirements in library 3.Remove transitive dependency from library
  81. @MOLSJEROEN 1. FORCE DEPENDENCY IN CUSTOMERAPP implementation('com.jeroenmols:library:1.0.0') { exclude group:

    'com.squareup.okhttp3', module: 'okhttp' }
  82. @MOLSJEROEN 1. FORCE DEPENDENCY IN CUSTOMERAPP con fi gurations.all {

    resolutionStrategy { force 'com.squareup.okhttp3:okhttp:3.12.0' } }
  83. @MOLSJEROEN 1. FORCE DEPENDENCY IN CUSTOMERAPP • No library update

    required • Force untested combinations of dependencies • Burden for SDK customers
  84. @MOLSJEROEN CASE STUDY: BREAKING API CHANGES PROJECT MAVEN OKHTTP V2

    CUSTOMER APP ANOTHER LIBRARY LIBRARY OKHTTP V3
  85. @MOLSJEROEN OkHtttp v2 OkHttp v3

  86. @MOLSJEROEN CASE STUDY: BREAKING API CHANGES package com.square.okhttp 3 implementation

    ‘com.squareup.okhttp3:okhttp3:4.9.0'
  87. PROBLEM #2 INCOMPATIBLE TRANSITIVE DEPENDENCIES

  88. @MOLSJEROEN INCOMPATIBLE TRANSITIVE DEPENDENCIES PROJECT MAVEN PROTOBUF-JAVA CUSTOMER APP ANOTHER

    LIBRARY LIBRARY PROTOBUF-JAVALITE
  89. @MOLSJEROEN INCOMPATIBLE TRANSITIVE DEPENDENCIES PROJECT MAVEN PROTOBUF-JAVA CUSTOMER APP ANOTHER

    LIBRARY LIBRARY PROTOBUF-JAVALITE
  90. @MOLSJEROEN INCOMPATIBLE TRANSITIVE DEPENDENCIES $ ./gradlew clean assembleDebug > Task

    :app:checkDebugDuplicateClasses FAILED FAILURE: Build failed with an exception. * What went wrong: Execution failed for task ':myproject:checkReleaseDuplicateClasses'. > 1 exception was raised by workers: java.lang.RuntimeException: Duplicate class com.google.protobuf.AbstractMessageLite found in modules protobuf-java-3.11.1.jar (com.google.protobuf:protobuf-java:3.11.1) and protobuf-javalite-3.11.0.jar (com.google.protobuf:protobuf-javalite:3.11.0) Duplicate class com.google.protobuf.AbstractMessageLite$Builder found in modules protobuf-java-3.11.1.jar (com.google.protobuf:protobuf-java:3.11.1) and protobuf-javalite-3.11.0.jar (com.google.protobuf:protobuf-javalite:3.11.0) Duplicate class com.google.protobuf.AbstractMessageLite$Builder$LimitedInputStream found in modules protobuf-java-3.11.1.jar (com.google.protobuf:protobuf-java:3.11.1) and protobuf-javalite-3.11.0.jar (com.google.protobuf:protobuf-javalite:3.11.0) ...
  91. @MOLSJEROEN INCOMPATIBLE TRANSITIVE DEPENDENCIES +--- com.google. fi rebase: fi rebase-perf:19.0.7

    | +--- com.google. fi rebase: fi rebase-con fi g:19.0.4 | | +--- com.google. fi rebase: fi rebase-abt:19.0.0 | | | \--- com.google.protobuf:protobuf-lite:3.0.1
  92. @MOLSJEROEN INCOMPATIBILITY RESOLUTION 1.Substitute dependency in CustomerApp 2.Remove dependency from

    transitive dependency of library 3.Remove transitive dependency from library
  93. @MOLSJEROEN 2. REMOVE FROM TRANSITIVE DEPENDENCY PROJECT MAVEN PROTOBUF-JAVALITE CUSTOMER

    APP ANOTHER LIBRARY LIBRARY PBANDK PROTOBUF-JAVA
  94. @MOLSJEROEN 2. REMOVE FROM TRANSITIVE DEPENDENCY PROJECT MAVEN PROTOBUF-JAVALITE CUSTOMER

    APP ANOTHER LIBRARY LIBRARY PBANDK PROTOBUF-JAVA
  95. @MOLSJEROEN 2. REMOVE FROM TRANSITIVE DEPENDENCY .. . <dependency> <groupId>pro.streem.pbandk</groupId

    > <artifactId>pbandk-runtime-jvm</artifactId> <version>0.9.0</version> <exclusions> <exclusion> <groupId>com.google.protobuf</groupId> <artifactId>protobuf-java</artifactId> </exclusion> </exclusions> </dependency>
  96. @MOLSJEROEN 2. REMOVE FROM TRANSITIVE DEPENDENCY .. . <dependency >

    <groupId>pro.streem.pbandk</groupId > <artifactId>pbandk-runtime-jvm</artifactId > <version>0.9.0</version > <exclusions> <exclusion> <groupId>com.google.protobuf</groupId> <artifactId>protobuf-java</artifactId> </exclusion> </exclusions > </dependency>
  97. @MOLSJEROEN 2. REMOVE FROM TRANSITIVE DEPENDENCY pom.withXml { def dependencies

    = asNode().appendNode('dependencies') con fi gurations.getByName(“releaseCompileClasspath").getResolvedCon fi guration( ) .getFirstLevelModuleDependencies().each { ... def dependency = dependencies.appendNode(‘dependency’ ) if (it.moduleName.contains("pbandk")) { def exclusions = dependency.appendNode(‘exclusions' ) def protobufExclusion = exclusions.appendNode('exclusion') protobufExclusion.appendNode('groupId', "com.google.protobuf") protobufExclusion.appendNode('artifactId', "protobuf-java") } } }
  98. @MOLSJEROEN 2. REMOVE FROM TRANSITIVE DEPENDENCY pom.withXml { def dependencies

    = asNode().appendNode('dependencies' ) con fi gurations.getByName(“releaseCompileClasspath").getResolvedCon fi guration( ) .getFirstLevelModuleDependencies().each { .. . def dependency = dependencies.appendNode(‘dependency’ ) if (it.moduleName.contains("pbandk")) { def exclusions = dependency.appendNode(‘exclusions' ) def protobufExclusion = exclusions.appendNode('exclusion') protobufExclusion.appendNode('groupId', "com.google.protobuf") protobufExclusion.appendNode('artifactId', "protobuf-java") } } }
  99. @MOLSJEROEN 2. REMOVE FROM TRANSITIVE DEPENDENCY PROJECT MAVEN PROTOBUF-JAVALITE CUSTOMER

    APP ANOTHER LIBRARY LIBRARY PBANDK
  100. @MOLSJEROEN 2. REMOVE FROM TRANSITIVE DEPENDENCY PROJECT MAVEN CUSTOMER APP

    LIBRARY PBANDK
  101. @MOLSJEROEN 2. REMOVE FROM TRANSITIVE DEPENDENCY PROJECT MAVEN PROTOBUF-JAVALITE CUSTOMER

    APP ANOTHER LIBRARY LIBRARY PBANDK PROTOBUF- JAVALITE
  102. RECOMMENDATION TRANSITIVE DEPENDENCIES

  103. @MOLSJEROEN TRANSITIVE DEPENDENCY RECOMMENDATION 1. Minimize transitive dependencies 2. Use

    stable versions 3. Use versions without known vulnerabilities 4. Don’t use latest dependency versions 5. Prefer exact versions over ranges 6. Only use libraries that handle breaking changes => Put exceptions in release notes
  104. @MOLSJEROEN INVESTIGATE DEPENDENCY CONFLICTS ./gradlew :library:dependencie s $ ./gradlew --console

    plain :app:dependencies --con fi guration releaseRuntimeClasspath > Task :app:dependencies ------------------------------------------------------------ Project :app ------------------------------------------------------------ releaseRuntimeClasspath - Runtime classpath of compilation 'release' (target (androidJvm)). +--- org.jetbrains.kotlin:kotlin-stdlib:1.3.72 | +--- org.jetbrains.kotlin:kotlin-stdlib-common:1.3.72 | \--- org.jetbrains:annotations:13.0 +--- androidx.core:core-ktx:1.3.2 | +--- org.jetbrains.kotlin:kotlin-stdlib:1.3.71 -> 1.3.72 (*) | +--- androidx.annotation:annotation:1.1.0 | \--- androidx.core:core:1.3.2 | \--- ... +--- androidx.appcompat:appcompat:1.2.0 | +--- androidx.annotation:annotation:1.1.0
  105. LAST SDK INTEGRATED WILL GET THE BLAME

  106. TIPS & TOOLS

  107. @MOLSJEROEN 2. LIBRARY RESOURCES

  108. @MOLSJEROEN 2. LIBRARY RESOURCES - HIDE <!-- library/src/main/res/values/public.xml --> <?xml

    version="1.0" encoding="utf-8"?> <resources> <public name="library_name" type="string"/> </resources>
  109. @MOLSJEROEN 2. LIBRARY RESOURCES - UNIQUE NAME // library/build.gradle android

    { ... resourcePre fi x 'mylib_' }
  110. @MOLSJEROEN 3. COMPATIBILITY: SOURCE PROJECT MAVEN CUSTOMER APP LIBRARY V1

  111. @MOLSJEROEN 3. COMPATIBILITY: SOURCE PROJECT MAVEN CUSTOMER APP LIBRARY V2

  112. @MOLSJEROEN 3. COMPATIBILITY: SOURCE class CustomerApp { fun useLibrary() =

    Library().initialize( ) } // Library v1 class Library { fun initialize() = Database().initialize() }
  113. @MOLSJEROEN 3. COMPATIBILITY: SOURCE class CustomerApp { fun useLibrary() =

    Library().initialize( ) } // Library v2 class Library { fun initialize(useCaching: Boolean) = Database().initialize() }
  114. @MOLSJEROEN 3. COMPATIBILITY: SOURCE class CustomerApp { fun useLibrary() =

    Library().initialize() } // Library v2 class Library { fun initialize(useCaching: Boolean) = Database().initialize() } no value passed for parameter useCaching
  115. @MOLSJEROEN 3. COMPATIBILITY: SOURCE class CustomerApp { fun useLibrary() =

    Library().initialize() } // Library v2 class Library { fun initialize(useCaching: Boolean = true) = Database().initialize() }
  116. @MOLSJEROEN 3. COMPATIBILITY: BINARY // Bytecode library v1 public fi

    nal class com/jeroenmols/library/Library { public fi nal static initialize() V } // Bytecode library v2 public fi nal class com/jeroenmols/library/Library { public fi nal static initialize(Z) V public static synthetic initialize$default(ZILjava/lang/Object;) V }
  117. @MOLSJEROEN 3. COMPATIBILITY: BINARY // Bytecode library v 1 public

    fi nal class com/jeroenmols/library/Library { public fi nal static initialize() V } // Bytecode library v 2 public fi nal class com/jeroenmols/library/Library { public fi nal static initialize(Z) V public static synthetic initialize$default(ZILjava/lang/Object;) V }
  118. @MOLSJEROEN 3. COMPATIBILITY: BINARY // Bytecode library v 1 public

    fi nal class com/jeroenmols/library/Library { public fi nal static initialize() V } // Bytecode library v 2 public fi nal class com/jeroenmols/library/Library { public fi nal static initialize(Z) V public static synthetic initialize$default(ZILjava/lang/Object;) V }
  119. @MOLSJEROEN 3. COMPATIBILITY: BINARY OTHER LIBRARY MAVEN CUSTOMER APP LIBRARY

    V1 LIBRARY V2
  120. @MOLSJEROEN 3. COMPATIBILITY: BINARY OTHER LIBRARY MAVEN APP < FORCED

    > 
 LIBRARY V2 LIBRARY V2
  121. @MOLSJEROEN 3. COMPATIBILITY: BINARY Maintaining Compatibility in Kotlin libraries by

    Márton Braun 
 https://zsmb.co/maintaining-compatibility-in-kotlin-libraries/ Public API challenges in Kotlin by Jake Wharton https://jakewharton.com/public-api-challenges-in-kotlin/
  122. @MOLSJEROEN 3. COMPATIBILITY: GRADLE PLUGIN // top level build.gradle plugins

    { id 'org.jetbrains.kotlinx.binary-compatibility-validator' version '0.8.0-RC' } apiValidation { ignoredPackages += ["com.jeroenmols.library.internal", “com.jeroenmols.library.databinding"] ignoredClasses += ["com.jeroenmols.library.BuildCon fi g"] ignoredProjects += ["app"] }
  123. @MOLSJEROEN 3. COMPATIBILITY: GRADLE PLUGIN // Snapshot current API into

    api subfolder $ ./gradlew apiDum p // Verify current API against snapshot $ ./gradlew apiCheck
  124. @MOLSJEROEN 4. MINIMIZING API SURFACE • Easy to learn •

    Hard to make mistakes • Reduce maintenance • Avoid deprecation • Easier to change
  125. @MOLSJEROEN 4. MINIMIZE API SURFACE // build.gradle fi le of

    each module android { ... kotlinOptions { freeCompilerArgs += '-Xexplicit-api=strict' } } // library class Library { fun initialize() { ... } } Visibility must be specified in explicit API mode
  126. @MOLSJEROEN 4. MINIMIZE API SURFACE // build.gradle fi le of

    each module android { ... kotlinOptions { freeCompilerArgs += '-Xexplicit-api=strict' } } // librar y class Library { fun initialize() { ... } }
  127. @MOLSJEROEN 4. MINIMIZE API SURFACE // build.gradle fi le of

    each modul e android { .. . kotlinOptions { freeCompilerArgs += '-Xexplicit-api=strict ' } } // library class Library { fun initialize() { ... } } Visibility must be specified in explicit API mode
  128. @MOLSJEROEN 5. EXPERIMENTAL APIS @RequiresOptIn(level = RequiresOptIn.Level.ERROR, message = "This

    is an experimental API.") @Retention(AnnotationRetention.BINARY) @Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION) public annotation class ExperimentalMyLibraryApi
  129. @MOLSJEROEN 5. EXPERIMENTAL APIS @RequiresOptIn(level = RequiresOptIn.Level.ERROR, message = "This

    is an experimental API.") @Retention(AnnotationRetention.BINARY ) @Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION ) public annotation class ExperimentalMyLibraryApi
  130. @MOLSJEROEN 5. EXPERIMENTAL APIS // library @ExperimentalMyLibraryApi fun doSomething() //

    ap p @OptIn(ExperimentalMyLibraryApi::class ) override fun myFunction() { doSomething( ) }
  131. @MOLSJEROEN 5. EXPERIMENTAL APIS // librar y @ExperimentalMyLibraryAp i fun

    doSomething( ) // app @OptIn(ExperimentalMyLibraryApi::class) override fun myFunction() { doSomething( ) }
  132. @MOLSJEROEN 5. EXPERIMENTAL APIS @kotlin.RequiresOptIn( level = kotlin.RequiresOptIn.Level.ERROR, ) public

    annotation class ExperimentalMyLibraryAp i @androidx.annotation.RequiresOptIn( level = androidx.annotation.RequiresOptIn.Level.ERROR, ) public annotation class ExperimentalMyLibraryApi
  133. @MOLSJEROEN 6. DEPRECATION - REPLACE class Library { @Deprecated(message =

    “Please use the version with caching options”, replaceWith = ReplaceWith(“initialize(true)")) fun initialize( ) fun initialize(useCaching: Boolean ) }
  134. @MOLSJEROEN 6. DEPRECATION - HIDE class Library { @Deprecated(message =

    “Please use the version with caching options”, level = DeprecationLevel.HIDDEN) fun initialize( ) fun initialize(useCaching: Boolean ) }
  135. @MOLSJEROEN 7. PROGUARD android { defaultCon fi g { ...

    consumerProguardFiles 'consumer-rules.pro' } }
  136. WRAP UP

  137. @MOLSJEROEN DRIVE INNOVATION TOOLS ARE LACKING MINIMIZE API SURFACE LIMIT

    MODULARISATION REDUCE DEPENDENCIES
  138. @MOLSJEROEN HTTPS://JEROENMOLS.COM/BLOG

  139. @MOLSJEROEN IMAGE CREDITS Welcome image by James A. Molnar https://unsplash.com/photos/R8t7MjLXy2s

    Font awesome https://fontawesome.com/
  140. @MOLSJEROEN FURTHER READS Maintaining compatibility in Kotlin libraries by Márton

    Braun The hidden Kotlin gem: Deprecations with ReplaceWith by Marc Reichelt Publishing libraries to Maven Central in 2021 by Marton Braun Java interoperability policy for major version updates by Jake Wharton Public API challenges in Kotlin by Jake Wharton How to publish and distribute your Android library by Marco Gomiero What is a diamond dependency con fl ict by Google All about Opt-in annotations by Márton Braun
  141. MOLSJEROEN