Slide 1

Slide 1 text

@MOLSJEROEN THE DEFINITIVE GUIDE TO ANDROID LIBRARY DEVELOPMENT

Slide 2

Slide 2 text

@MOLSJEROEN

Slide 3

Slide 3 text

@MOLSJEROEN GOAL OUR FIRST LIBRARY TRANSITIVE DEPENDENCIES MODULARIZATION DEPENDENCY CONFLICTS TIPS & TOOLS

Slide 4

Slide 4 text

@MOLSJEROEN TERMINOLOGY • Software Development Kit (SDK) • Android library

Slide 5

Slide 5 text

GOAL

Slide 6

Slide 6 text

@MOLSJEROEN ANDROID LIBRARIES APP

Slide 7

Slide 7 text

@MOLSJEROEN ANDROID LIBRARIES APP COMPOSE OKHTTP …

Slide 8

Slide 8 text

@MOLSJEROEN ANDROID LIBRARIES APP COMPOSE OKHTTP … MAVEN

Slide 9

Slide 9 text

@MOLSJEROEN ANDROID LIBRARIES COMPOSE OKHTTP … MAVEN APP MODULE 1 MODULE 2

Slide 10

Slide 10 text

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

Slide 11

Slide 11 text

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

Slide 12

Slide 12 text

OUR FIRST LIBRARY

Slide 13

Slide 13 text

ANDROID STUDIO TO THE RESCUE!

Slide 14

Slide 14 text

@MOLSJEROEN

Slide 15

Slide 15 text

TOOLING FOR ANDROID LIBRARIES IS LACKING

Slide 16

Slide 16 text

@MOLSJEROEN ANDROID STUDIO PROJECT PROJECT APP

Slide 17

Slide 17 text

@MOLSJEROEN

Slide 18

Slide 18 text

@MOLSJEROEN ANDROID STUDIO PROJECT LIBRARY APP PROJECT

Slide 19

Slide 19 text

@MOLSJEROEN

Slide 20

Slide 20 text

@MOLSJEROEN

Slide 21

Slide 21 text

@MOLSJEROEN

Slide 22

Slide 22 text

@MOLSJEROEN

Slide 23

Slide 23 text

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

Slide 24

Slide 24 text

@MOLSJEROEN BUILD $ ./gradlew :library:assembleRelease

Slide 25

Slide 25 text

@MOLSJEROEN

Slide 26

Slide 26 text

@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

Slide 27

Slide 27 text

@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

Slide 28

Slide 28 text

@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/

Slide 29

Slide 29 text

TOOLING FOR ANDROID LIBRARIES IS LACKING

Slide 30

Slide 30 text

TRANSITIVE DEPENDENCIES

Slide 31

Slide 31 text

@MOLSJEROEN EXTERNAL DEPENDENCIES LIBRARY APP PROJECT MAVEN OKHTTP

Slide 32

Slide 32 text

@MOLSJEROEN EXTERNAL DEPENDENCIES PROJECT MAVEN CUSTOMER APP LIBRARY

Slide 33

Slide 33 text

@MOLSJEROEN EXTERNAL DEPENDENCIES PROJECT MAVEN OKHTTP CUSTOMER APP LIBRARY

Slide 34

Slide 34 text

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

Slide 35

Slide 35 text

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

Slide 36

Slide 36 text

@MOLSJEROEN EXTERNAL DEPENDENCIES PROJECT MAVEN OKHTTP CUSTOMER APP LIBRARY

Slide 37

Slide 37 text

@MOLSJEROEN POM - XML FILE com.jeroenmols library 1.0.0 com.squareup.okhttp3 okhttp3 4.9.0

Slide 38

Slide 38 text

@MOLSJEROEN POM - XML FILE com.jeroenmols library 1.0.0 com.squareup.okhttp3 okhttp3 4.9.0

Slide 39

Slide 39 text

@MOLSJEROEN POM - XML FILE com.jeroenmols library 1.0.0 com.squareup.okhttp3 okhttp3 4.9.0

Slide 40

Slide 40 text

@MOLSJEROEN

Slide 41

Slide 41 text

ALWAYS TEST LIBRARIES THROUGH MAVEN

Slide 42

Slide 42 text

MODULARIZATION

Slide 43

Slide 43 text

@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

Slide 44

Slide 44 text

@MOLSJEROEN LIBRARY MODULARIZATION LIBRARY APP PROJECT DATABASE UI-COMPONENTS

Slide 45

Slide 45 text

@MOLSJEROEN

Slide 46

Slide 46 text

@MOLSJEROEN

Slide 47

Slide 47 text

@MOLSJEROEN

Slide 48

Slide 48 text

@MOLSJEROEN TEST SETUP // app Library().initialize() // library class Library { fun initialize() = Database().initialize() } // database class Database { fun initialize() = System.out.println(“database ready") }

Slide 49

Slide 49 text

PROBLEM #1 
 SUBMODULES NOT INCLUDED IN AAR

Slide 50

Slide 50 text

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

Slide 51

Slide 51 text

@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') ... }

Slide 52

Slide 52 text

@MOLSJEROEN

Slide 53

Slide 53 text

@MOLSJEROEN

Slide 54

Slide 54 text

TOOLING FOR ANDROID LIBRARIES IS LACKING

Slide 55

Slide 55 text

@MOLSJEROEN

Slide 56

Slide 56 text

@MOLSJEROEN SUBMODULES NOT INCLUDED IN AAR 1. Release submodules to Maven 2. Fat AAR 3. Single module SDK

Slide 57

Slide 57 text

@MOLSJEROEN 1. RELEASE SUBMODULES TO MAVEN COMPOSE LIBRARY MAVEN APP UI-COMPONENTS DATABASE

Slide 58

Slide 58 text

@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" }

Slide 59

Slide 59 text

@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') }

Slide 60

Slide 60 text

@MOLSJEROEN 3. SINGLE MODULE SDK LIBRARY APP PROJECT

Slide 61

Slide 61 text

PROBLEM #2 
 PUBLIC INTERFACE SUBMODULES EXPOSED

Slide 62

Slide 62 text

@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

Slide 63

Slide 63 text

@MOLSJEROEN 1

Slide 64

Slide 64 text

@MOLSJEROEN PUBLIC INTERFACE SUBMODULES EXPOSED 1. Internal package 2. Obfuscate non-public classes 3. Single module SDK

Slide 65

Slide 65 text

@MOLSJEROEN 1. INTERNAL PACKAGE package com.jeroenmols.internal.database

Slide 66

Slide 66 text

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

Slide 67

Slide 67 text

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

Slide 68

Slide 68 text

@MOLSJEROEN 3. SINGLE MODULE SDK LIBRARY APP PROJECT

Slide 69

Slide 69 text

RECOMMENDATION LIBRARY MODULARIZATION

Slide 70

Slide 70 text

@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

Slide 71

Slide 71 text

TRANSITIVE DEPENDENCY CONFLICTS

Slide 72

Slide 72 text

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

Slide 73

Slide 73 text

@MOLSJEROEN TRANSITIVE DEPENDENCY CONFLICTS PROJECT MAVEN TRANSITIVE DEPENDENCY 1 CUSTOMER APP ANOTHER LIBRARY LIBRARY TRANSITIVE DEPENDENCY 2 TRANSITIVE DEPENDENCY 3

Slide 74

Slide 74 text

@MOLSJEROEN TRANSITIVE DEPENDENCY CONFLICTS 1. con fl icting transitive dependency versions 2. incompatible transitive dependencies

Slide 75

Slide 75 text

PROBLEM #1 TRANSITIVE DEPENDENCY CONFLICTS

Slide 76

Slide 76 text

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

Slide 77

Slide 77 text

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

Slide 78

Slide 78 text

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

Slide 79

Slide 79 text

@MOLSJEROEN

Slide 80

Slide 80 text

@MOLSJEROEN CONFLICT RESOLUTION 1.Force dependency resolution in CustomerApp 2.Loosen dependency requirements in library 3.Remove transitive dependency from library

Slide 81

Slide 81 text

@MOLSJEROEN 1. FORCE DEPENDENCY IN CUSTOMERAPP implementation('com.jeroenmols:library:1.0.0') { exclude group: 'com.squareup.okhttp3', module: 'okhttp' }

Slide 82

Slide 82 text

@MOLSJEROEN 1. FORCE DEPENDENCY IN CUSTOMERAPP con fi gurations.all { resolutionStrategy { force 'com.squareup.okhttp3:okhttp:3.12.0' } }

Slide 83

Slide 83 text

@MOLSJEROEN 1. FORCE DEPENDENCY IN CUSTOMERAPP • No library update required • Force untested combinations of dependencies • Burden for SDK customers

Slide 84

Slide 84 text

@MOLSJEROEN CASE STUDY: BREAKING API CHANGES PROJECT MAVEN OKHTTP V2 CUSTOMER APP ANOTHER LIBRARY LIBRARY OKHTTP V3

Slide 85

Slide 85 text

@MOLSJEROEN OkHtttp v2 OkHttp v3

Slide 86

Slide 86 text

@MOLSJEROEN CASE STUDY: BREAKING API CHANGES package com.square.okhttp 3 implementation ‘com.squareup.okhttp3:okhttp3:4.9.0'

Slide 87

Slide 87 text

PROBLEM #2 INCOMPATIBLE TRANSITIVE DEPENDENCIES

Slide 88

Slide 88 text

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

Slide 89

Slide 89 text

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

Slide 90

Slide 90 text

@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) ...

Slide 91

Slide 91 text

@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

Slide 92

Slide 92 text

@MOLSJEROEN INCOMPATIBILITY RESOLUTION 1.Substitute dependency in CustomerApp 2.Remove dependency from transitive dependency of library 3.Remove transitive dependency from library

Slide 93

Slide 93 text

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

Slide 94

Slide 94 text

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

Slide 95

Slide 95 text

@MOLSJEROEN 2. REMOVE FROM TRANSITIVE DEPENDENCY .. . pro.streem.pbandk pbandk-runtime-jvm 0.9.0 com.google.protobuf protobuf-java

Slide 96

Slide 96 text

@MOLSJEROEN 2. REMOVE FROM TRANSITIVE DEPENDENCY .. . pro.streem.pbandk pbandk-runtime-jvm 0.9.0 com.google.protobuf protobuf-java

Slide 97

Slide 97 text

@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") } } }

Slide 98

Slide 98 text

@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") } } }

Slide 99

Slide 99 text

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

Slide 100

Slide 100 text

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

Slide 101

Slide 101 text

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

Slide 102

Slide 102 text

RECOMMENDATION TRANSITIVE DEPENDENCIES

Slide 103

Slide 103 text

@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

Slide 104

Slide 104 text

@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

Slide 105

Slide 105 text

LAST SDK INTEGRATED WILL GET THE BLAME

Slide 106

Slide 106 text

TIPS & TOOLS

Slide 107

Slide 107 text

@MOLSJEROEN 2. LIBRARY RESOURCES

Slide 108

Slide 108 text

@MOLSJEROEN 2. LIBRARY RESOURCES - HIDE

Slide 109

Slide 109 text

@MOLSJEROEN 2. LIBRARY RESOURCES - UNIQUE NAME // library/build.gradle android { ... resourcePre fi x 'mylib_' }

Slide 110

Slide 110 text

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

Slide 111

Slide 111 text

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

Slide 112

Slide 112 text

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

Slide 113

Slide 113 text

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

Slide 114

Slide 114 text

@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

Slide 115

Slide 115 text

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

Slide 116

Slide 116 text

@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 }

Slide 117

Slide 117 text

@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 }

Slide 118

Slide 118 text

@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 }

Slide 119

Slide 119 text

@MOLSJEROEN 3. COMPATIBILITY: BINARY OTHER LIBRARY MAVEN CUSTOMER APP LIBRARY V1 LIBRARY V2

Slide 120

Slide 120 text

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

Slide 121

Slide 121 text

@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/

Slide 122

Slide 122 text

@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"] }

Slide 123

Slide 123 text

@MOLSJEROEN 3. COMPATIBILITY: GRADLE PLUGIN // Snapshot current API into api subfolder $ ./gradlew apiDum p // Verify current API against snapshot $ ./gradlew apiCheck

Slide 124

Slide 124 text

@MOLSJEROEN 4. MINIMIZING API SURFACE • Easy to learn • Hard to make mistakes • Reduce maintenance • Avoid deprecation • Easier to change

Slide 125

Slide 125 text

@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

Slide 126

Slide 126 text

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

Slide 127

Slide 127 text

@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

Slide 128

Slide 128 text

@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

Slide 129

Slide 129 text

@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

Slide 130

Slide 130 text

@MOLSJEROEN 5. EXPERIMENTAL APIS // library @ExperimentalMyLibraryApi fun doSomething() // ap p @OptIn(ExperimentalMyLibraryApi::class ) override fun myFunction() { doSomething( ) }

Slide 131

Slide 131 text

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

Slide 132

Slide 132 text

@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

Slide 133

Slide 133 text

@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 ) }

Slide 134

Slide 134 text

@MOLSJEROEN 6. DEPRECATION - HIDE class Library { @Deprecated(message = “Please use the version with caching options”, level = DeprecationLevel.HIDDEN) fun initialize( ) fun initialize(useCaching: Boolean ) }

Slide 135

Slide 135 text

@MOLSJEROEN 7. PROGUARD android { defaultCon fi g { ... consumerProguardFiles 'consumer-rules.pro' } }

Slide 136

Slide 136 text

WRAP UP

Slide 137

Slide 137 text

@MOLSJEROEN DRIVE INNOVATION TOOLS ARE LACKING MINIMIZE API SURFACE LIMIT MODULARISATION REDUCE DEPENDENCIES

Slide 138

Slide 138 text

@MOLSJEROEN HTTPS://JEROENMOLS.COM/BLOG

Slide 139

Slide 139 text

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

Slide 140

Slide 140 text

@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

Slide 141

Slide 141 text

MOLSJEROEN