Slide 1

Slide 1 text

1

Slide 2

Slide 2 text

OSS Android libraries developed 2

Slide 3

Slide 3 text

Side A 1. How does Gradle process Android Libraries 2. Android Archive(AAR) 3. Why doesn’t my AAR download transitive dependencies? 4. Maven Artifact 5. POM? 6. Bundled Proguard Configs Side B 7. Modularization 8. Avoiding Resource Name Conflicts 9. minSdkVersion Restriction 10. Access Visibility vs Code Organization 11. Lifecycle Aware Android Library 12. Auto Init Android Library 3 @nisrulz

Slide 4

Slide 4 text

How does Gradle process Android Libraries @nisrulz 4

Slide 5

Slide 5 text

How does Gradle process Android Libraries repositories{ jCenter() } dependencies { implementation 'com.example.myawesomelib:1.0.0' ... } 5 @nisrulz

Slide 6

Slide 6 text

How does Gradle process Android Libraries ● implementation 6 @nisrulz

Slide 7

Slide 7 text

● api How does Gradle process Android Libraries 7 @nisrulz

Slide 8

Slide 8 text

How does Gradle process Android Libraries ● compileOnly 8 @nisrulz

Slide 9

Slide 9 text

Android ARchive(AAR) @nisrulz 9

Slide 10

Slide 10 text

AAR = Java ARchive(JAR) + Resources 10 @nisrulz

Slide 11

Slide 11 text

AAR = Java ARchive(JAR) + Resources Sensey: https://github.com/nisrulz/sensey 11 @nisrulz

Slide 12

Slide 12 text

AAR = Java ARchive(JAR) + Resources @nisrulz 12

Slide 13

Slide 13 text

Sensey’s build.gradle dependencies { ... // Other testing dependencies // Transitive dependency: Support Compat library implementation "com.android.support:support-compat:27.0.2" } 13 @nisrulz

Slide 14

Slide 14 text

Using an AAR as dependency @nisrulz 14

Slide 15

Slide 15 text

Using an AAR as dependency repositories{ flatDir{ dirs 'libs' } } dependencies { implementation(name:'nameOfYourAARFileWithoutExtension', ext:'aar') } @nisrulz 15

Slide 16

Slide 16 text

Using an AAR as dependency repositories{ flatDir{ dirs 'libs' } } dependencies { implementation(name:'nameOfYourAARFileWithoutExtension', ext:'aar') } // No transitive dependencies of the library are downloaded 16 @nisrulz

Slide 17

Slide 17 text

Why doesn’t my AAR download transitive dependencies? @nisrulz 17

Slide 18

Slide 18 text

Sensey’s AAR 18 @nisrulz

Slide 19

Slide 19 text

Sensey’s AAR No build.gradle file 19 @nisrulz

Slide 20

Slide 20 text

Maven Artifact 20 @nisrulz

Slide 21

Slide 21 text

Maven Artifact 21 @nisrulz

Slide 22

Slide 22 text

POM? 22 @nisrulz

Slide 23

Slide 23 text

POM ● Project Object Model ● XML file ● Configuration details used by Maven to build the project 23 @nisrulz

Slide 24

Slide 24 text

POM POM of Sensey Android Library 4.0.0 com.github.nisrulzsensey1.8.0 aarsensey Android library which makes playing with sensor events & detecting gestures a breeze. https://github.com/nisrulz/sensey The Apache Software License, Version 2.0http://www.apache.org/licenses/LICENSE-2.0.txt nisrulzNishant Srivastavanisrulz@gmail.com https://github.com/nisrulz/sensey.git https://github.com/nisrulz/sensey.git https://github.com/nisrulz/sensey com.android.support support-compat27.0.2 runtime ... 24 @nisrulz

Slide 25

Slide 25 text

POM POM of Sensey Android Library 4.0.0 com.github.nisrulzsensey1.8.0 aarsensey Android library which makes playing with sensor events & detecting gestures a breeze. https://github.com/nisrulz/sensey The Apache Software License, Version 2.0http://www.apache.org/licenses/LICENSE-2.0.txt nisrulzNishant Srivastavanisrulz@gmail.com https://github.com/nisrulz/sensey.git https://github.com/nisrulz/sensey.git https://github.com/nisrulz/sensey com.android.support support-compat27.0.2 runtime ... 25 @nisrulz

Slide 26

Slide 26 text

POM POM of Sensey Android Library ... com.android.support support-compat27.0.2 runtime ... 26 @nisrulz

Slide 27

Slide 27 text

Bundled Proguard Configs 27 @nisrulz

Slide 28

Slide 28 text

Bundled Proguard Configs android { release { minifyEnabled true // Rules to be used during the AAR generation proguardFiles 'proguard-rules-for-building-library.pro' // Rules appended to the integrating app consumerProguardFiles 'proguard-rules-for-using-library.pro' } ... } 28 @nisrulz

Slide 29

Slide 29 text

Bundled Proguard Configs Fuel: https://github.com/kittinunf/Fuel 29 @nisrulz

Slide 30

Slide 30 text

Bundled Proguard Configs 30 @nisrulz

Slide 31

Slide 31 text

Bundled Proguard Configs # Fuel’s bundled Proguard file # Without specifically keeping this class, # callbacks on android don't function properly. -keep class com.github.kittinunf.fuel.android.util.AndroidEnvironment 31 @nisrulz

Slide 32

Slide 32 text

Bundled Proguard Configs # To check the merged configuration # Add the below to your current config -printconfiguration proguard-merged-config.txt 32 @nisrulz

Slide 33

Slide 33 text

Bundled Proguard Configs # DON'T DO THIS -dontobfuscate -optimizations !code/allocation/variable # Effectively no optimizations -keep public class * { public protected *; } 33 @nisrulz

Slide 34

Slide 34 text

Bundled Proguard Configs # DON'T DO THIS # Adding the below in library proguard rules disables # the optimizations in the Android app -dontoptimize 34 @nisrulz

Slide 35

Slide 35 text

Modularization 35 @nisrulz

Slide 36

Slide 36 text

Modularization 36 @nisrulz

Slide 37

Slide 37 text

Modularization EasyDeviceInfo: https://github.com/nisrulz/easydeviceinfo 37 @nisrulz

Slide 38

Slide 38 text

Modularization dependencies { def libVer = {latest_version} // Base + Ads Bundled Library implementation "com.github.nisrulz:easydeviceinfo:$libVer" // Base Library implementation "com.github.nisrulz:easydeviceinfo-base:$libVer" // Ads Library implementation "com.github.nisrulz:easydeviceinfo-ads:$libVer" } 38 @nisrulz

Slide 39

Slide 39 text

Modularization ... com.github.nisrulz easydeviceinfo-ads 2.5.0 compile com.github.nisrulz easydeviceinfo-base 2.5.0 compile ... 39 @nisrulz

Slide 40

Slide 40 text

Modularization ... com.github.nisrulz easydeviceinfo-ads 2.5.0 compile com.github.nisrulz easydeviceinfo-base 2.5.0 compile ... 40 @nisrulz

Slide 41

Slide 41 text

Modularization ... com.github.nisrulz easydeviceinfo-ads 2.5.0 compile com.github.nisrulz easydeviceinfo-base 2.5.0 compile ... 41 @nisrulz

Slide 42

Slide 42 text

Modularization ... com.github.nisrulz easydeviceinfo-common2.5.0 compile com.google.android.gms play-services-ads-identifier16.0.0 runtime ... 42 @nisrulz

Slide 43

Slide 43 text

Modularization ... com.github.nisrulz easydeviceinfo-common2.5.0 compile com.google.android.gms play-services-ads-identifier16.0.0 runtime ... 43 @nisrulz

Slide 44

Slide 44 text

Avoiding Resource Name Conflicts 44 @nisrulz

Slide 45

Slide 45 text

Conflict occurs between a library & app resource > Project will not compile What happens when... 45 @nisrulz

Slide 46

Slide 46 text

Conflict occurs between 2 libraries integrated in the app > Resources from library defined first in build.gradle gets included What happens when... 46 @nisrulz

Slide 47

Slide 47 text

Solution? 47 @nisrulz

Slide 48

Slide 48 text

Add a prefix to all your resources. Solution? 48 @nisrulz

Slide 49

Slide 49 text

Add a prefix to all your resources. How? Solution? 49 @nisrulz

Slide 50

Slide 50 text

Add a prefix to all your resources. How? ● Enforce this in Android Studio Solution? 50 @nisrulz

Slide 51

Slide 51 text

Add a prefix to all your resources. How? ● Enforce this in Android Studio ● Declare in build.gradle of library android { resourcePrefix 'YOUR_PREFIX_' // i.e 'sensey_' } Solution? 51 @nisrulz

Slide 52

Slide 52 text

Solution? Resource named ‘app_name’ does not start with the project’s resource prefix ‘sensey_’; Rename to `sensey_app_name`? 52 @nisrulz

Slide 53

Slide 53 text

minSdkVersion Restriction 53 @nisrulz

Slide 54

Slide 54 text

minSdkVersion of app >= minSdkVersion of library minSdk Restriction 54 @nisrulz

Slide 55

Slide 55 text

minSdk Restriction 55 @nisrulz

Slide 56

Slide 56 text

Manifest merger failed : uses-sdk:minSdkVersion 14 cannot be smaller than version 21 declared in library [:sensey] Suggestion: + Use a compatible library with a minSdk of at most 14 + Increase this project's minSdk version to at least 21 + Use tools:overrideLibrary="com.github.nisrulz.sensey" to force usage (may lead to runtime failures) minSdk Restriction 56 @nisrulz

Slide 57

Slide 57 text

Manifest merger failed : uses-sdk:minSdkVersion 14 cannot be smaller than version 21 declared in library [:sensey] Suggestion: + Use a compatible library with a minSdk of at most 14 + Increase this project's minSdk version to at least 21 + Use tools:overrideLibrary="com.github.nisrulz.sensey" to force usage (may lead to runtime failures) minSdk Restriction 57 @nisrulz

Slide 58

Slide 58 text

Manifest merger failed : uses-sdk:minSdkVersion 14 cannot be smaller than version 21 declared in library [:sensey] Suggestion: + Use a compatible library with a minSdk of at most 14 + Increase this project's minSdk version to at least 21 + Use tools:overrideLibrary="com.github.nisrulz.sensey" to force usage (may lead to runtime failures) minSdk Restriction 58 @nisrulz

Slide 59

Slide 59 text

... minSdk Restriction 59 @nisrulz

Slide 60

Slide 60 text

... minSdk Restriction 60 @nisrulz

Slide 61

Slide 61 text

Access Visibility vs Code Organization 61 @nisrulz

Slide 62

Slide 62 text

Visibility vs Organization 62 @nisrulz

Slide 63

Slide 63 text

Visibility vs Organization ● Code organized in individual packages; everything is public 63 @nisrulz

Slide 64

Slide 64 text

Visibility vs Organization ● Code organized inside one package; everything is package private and only public on demand 64 @nisrulz

Slide 65

Slide 65 text

Visibility vs Organization ● Code organized inside the module i.e individual packages; everything is internal and only public on demand (in Kotlin land) ● Drawback ○ Need dependency on kotlin std library 65 @nisrulz

Slide 66

Slide 66 text

Visibility vs Organization // file name: exampleLibrary.kt // module name: example package com.example.library 66 @nisrulz

Slide 67

Slide 67 text

Visibility vs Organization // file name: exampleLibrary.kt // module name: example package com.example.library // visible inside exampleLibrary.kt private fun setup() { ... } 67 @nisrulz

Slide 68

Slide 68 text

Visibility vs Organization // file name: exampleLibrary.kt // module name: example package com.example.library // visible inside exampleLibrary.kt private fun setup() { ... } // property is visible everywhere public var name: String = "ExampleLib" // setter is visible only in exampleLibrary.kt private set{...} 68 @nisrulz

Slide 69

Slide 69 text

Visibility vs Organization // file name: exampleLibrary.kt // module name: example package com.example.library // visible inside exampleLibrary.kt private fun setup() { ... } // property is visible everywhere public var name: String = "ExampleLib" // setter is visible only in exampleLibrary.kt private set{...} // visible inside the module i.e example internal val debugTag = "Example-Debug" 69 @nisrulz

Slide 70

Slide 70 text

Lifecycle-Aware Android Library 70 @nisrulz

Slide 71

Slide 71 text

Lifecycle Components Classes designed to help deal with Android lifecycle ● Lifecycle ● LifecycleOwner ● LifecycleObserver 71 @nisrulz

Slide 72

Slide 72 text

Lifecycle Components Classes designed to help deal with Android lifecycle 72 @nisrulz

Slide 73

Slide 73 text

Lifecycle Components Classes designed to help deal with Android lifecycle i.e Activity, Fragment, Service, Custom 73 @nisrulz

Slide 74

Slide 74 text

Lifecycle class MainActivity extends AppCompatActivity() {...} 74 @nisrulz

Slide 75

Slide 75 text

Lifecycle class MainActivity extends AppCompatActivity() {...} public class AppCompatActivity extends FragmentActivity{...} 75 @nisrulz

Slide 76

Slide 76 text

Lifecycle class MainActivity extends AppCompatActivity() {...} public class AppCompatActivity extends FragmentActivity{...} public class FragmentActivity extends SupportActivity { ... public Lifecycle getLifecycle() { return super.getLifecycle(); } ... } 76 @nisrulz

Slide 77

Slide 77 text

LifecycleObserver dependencies { def lifecycleVer = "2.0.0" // Runtime implementation "androidx.lifecycle:lifecycle-runtime:$lifecycleVer" // Annotation Support annotationProcessor "androidx.lifecycle:lifecycle-compiler:$lifecycleVer" ... } 77 @nisrulz

Slide 78

Slide 78 text

LifecycleObserver public class AwesomeLib implements LifecycleObserver { @OnLifecycleEvent(Lifecycle.Event.ON_CREATE) public void init() { ... } @OnLifecycleEvent(Lifecycle.Event.ON_START) public void libOnStart() { ... } ... @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY) public void cleanup() { ... } } 78 @nisrulz

Slide 79

Slide 79 text

LifecycleOwner class MainActivity : AppCompatActivity() { val awesomeLib = AwesomeLib() override fun onResume() { ... // Add lifecycle observer lifecycle.addObserver(awesomeLib) } override fun onStop() { ... // Remove lifecycle observer lifecycle.removeObserver(awesomeLib) } } 79 @nisrulz

Slide 80

Slide 80 text

LifecycleAware Library 80 @nisrulz

Slide 81

Slide 81 text

ProcessLifecycleOwner Class that tracks the lifecycle of whole application process 81 @nisrulz

Slide 82

Slide 82 text

ProcessLifecycleOwner dependencies { // For ProcessLifecycleOwner implementation "androidx.lifecycle:lifecycle-extensions:2.0.0" ... } 82 @nisrulz

Slide 83

Slide 83 text

ProcessLifecycleOwner Does something weird… 83 @nisrulz

Slide 84

Slide 84 text

ProcessLifecycleOwner Does something weird… Adding lifecycle-extensions artifact > automatically adds element to the merged manifest 84 @nisrulz

Slide 85

Slide 85 text

ProcessLifecycleOwner 85 @nisrulz

Slide 86

Slide 86 text

ProcessLifecycleOwner ... 86 @nisrulz

Slide 87

Slide 87 text

ProcessLifecycleOwner ... 87 @nisrulz

Slide 88

Slide 88 text

ProcessLifecycleOwner ... 88 @nisrulz Pre-AndroidX

Slide 89

Slide 89 text

ProcessLifecycleOwner ... 89 @nisrulz Pre-AndroidX

Slide 90

Slide 90 text

ProcessLifecycleOwner 90 @nisrulz Pre-AndroidX

Slide 91

Slide 91 text

ProcessLifecycleOwner ... 91 @nisrulz AndroidX

Slide 92

Slide 92 text

ProcessLifecycleOwner ... 92 @nisrulz AndroidX

Slide 93

Slide 93 text

ProcessLifecycleOwner // Internal class to initialize Lifecycles. public class ProcessLifecycleOwnerInitializer extends ContentProvider { @Override public boolean onCreate() { ... ProcessLifecycleOwner.init(getContext()); return true; } ... } 93 @nisrulz

Slide 94

Slide 94 text

ProcessLifecycleOwner Why? To invoke ProcessLifecycleOwner as soon as process starts 94 @nisrulz

Slide 95

Slide 95 text

ProcessLifecycleOwner Why? To invoke ProcessLifecycleOwner as soon as process starts Drawback? Initializes ProcessLifecycleOwner even if your app does not use it! 95 @nisrulz

Slide 96

Slide 96 text

ProcessLifecycleOwner How to get rid of it in app? 96 @nisrulz

Slide 97

Slide 97 text

ProcessLifecycleOwner How to get rid of it in app? Use Merge rule marker in app’s AndroidManifest.xml: // Remove marked element from the merged manifest tools:node="remove" 97 @nisrulz

Slide 98

Slide 98 text

ProcessLifecycleOwner ... 98 @nisrulz App’s AndroidManifest.xml

Slide 99

Slide 99 text

ProcessLifecycleOwner ... 99 @nisrulz App’s AndroidManifest.xml

Slide 100

Slide 100 text

ProcessLifecycleOwner ... 100 @nisrulz App’s AndroidManifest.xml

Slide 101

Slide 101 text

ProcessLifecycleOwner ... 101 @nisrulz App’s AndroidManifest.xml

Slide 102

Slide 102 text

Auto Initialize Android Library 102 @nisrulz

Slide 103

Slide 103 text

AutoInit Android Library Android Libraries need Android context to handle simple tasks such as ● Hook into Android Runtime ● Access app resources ● Use System Services ● Register BroadcastReceiver 103 @nisrulz

Slide 104

Slide 104 text

AutoInit Android Library public class MyApplication extends Application { @Override public void onCreate() { super.onCreate(); // Init android library MyAwesomeLibrary.init(this); } } 104 @nisrulz

Slide 105

Slide 105 text

AutoInit Android Library public class MyApplication extends Application { @Override public void onCreate() { super.onCreate(); // Init android library MyAwesomeLibrary.init(this); } } 105 @nisrulz

Slide 106

Slide 106 text

AutoInit Android Library public class MyApplication extends Application { @Override public void onCreate() { super.onCreate(); // Init android library MyAwesomeLibrary.init(this); } } 106 @nisrulz

Slide 107

Slide 107 text

AutoInit Android Library 107 @nisrulz

Slide 108

Slide 108 text

AutoInit Android Library 108 @nisrulz

Slide 109

Slide 109 text

AutoInit Android Library ContentProvider can be used to simplify the process. 109 @nisrulz

Slide 110

Slide 110 text

AutoInit Android Library ContentProvider can be used to simplify the process. Simply because ContentProvider ● Is created and initialized (on the main thread) before all other components ● Participate in manifest merging at build time. 110 @nisrulz

Slide 111

Slide 111 text

AutoInit Android Library public class AwesomeLibInitProvider extends ContentProvider { ... @Override public boolean onCreate() { // get the context (Application context) Context context = getContext(); // initialize AwesomeLib here AwesomeLib.getInstance().init(context); return false; } ... } 111 @nisrulz

Slide 112

Slide 112 text

AutoInit Android Library public class AwesomeLibInitProvider extends ContentProvider { ... @Override public boolean onCreate() { // get the context (Application context) Context context = getContext(); // initialize AwesomeLib here AwesomeLib.getInstance().init(context); return false; } ... } 112 @nisrulz

Slide 113

Slide 113 text

AutoInit Android Library 113 @nisrulz

Slide 114

Slide 114 text

AutoInit Android Library 114 @nisrulz

Slide 115

Slide 115 text

AutoInit Android Library 115 @nisrulz

Slide 116

Slide 116 text

AutoInit Android Library 116 @nisrulz

Slide 117

Slide 117 text

AutoInit Android Library ContentProvider can be used to simplify the process. 117 @nisrulz

Slide 118

Slide 118 text

AutoInit Android Library ContentProvider can be used to simplify the process. Challenges: ● There can be only one Content Provider with a given “authority” string ● Only run on main thread 118 @nisrulz

Slide 119

Slide 119 text

AutoInit Android Library ContentProvider can be used to simplify the process. 119 @nisrulz

Slide 120

Slide 120 text

AutoInit Android Library ContentProvider can be used to simplify the process. Why this is a bad idea: ● Increases startup time ● Bloats applications even when not used ● Abusing functionality of ContentProvider 120 @nisrulz

Slide 121

Slide 121 text

AutoInit Android Library ContentProvider can be used to simplify the process. Why this is a bad idea: ● Increases startup time (Solution: async initialize) ● Bloats applications even when not used ● Abusing functionality of ContentProvider 121 @nisrulz

Slide 122

Slide 122 text

AutoInit Android Library Some android libraries that use this... 122 @nisrulz

Slide 123

Slide 123 text

AutoInit Android Library ProcessLifecycleOwner [androidx.lifecycle:lifecycle-extensions:2.0.0] 123 @nisrulz

Slide 124

Slide 124 text

AutoInit Android Library Firebase [com.google.firebase:firebase-common:16.0.5] 124 @nisrulz

Slide 125

Slide 125 text

AutoInit Android Library Facebook-Core [com.facebook.android:facebook-core:4.34.0] 125 @nisrulz

Slide 126

Slide 126 text

AutoInit Android Library Facebook-Marketing [com.facebook.android:facebook-marketing:4.34.0] 126 @nisrulz

Slide 127

Slide 127 text

AutoInit Android Library Crashlytics [com.crashlytics.sdk.android:crashlytics:2.9.5] 127 @nisrulz

Slide 128

Slide 128 text

AutoInit Android Library Picasso // Pre - v2.71828 Picasso.with(this).load("......").into(imageView); // After - v2.71828 Picasso.get().load("......").into(imageView); 128 @nisrulz

Slide 129

Slide 129 text

AutoInit Android Library Picasso // Pre - v2.71828 Picasso.with(this).load("......").into(imageView); // After - v2.71828 Picasso.get().load("......").into(imageView); 129 @nisrulz

Slide 130

Slide 130 text

AutoInit Android Library Picasso [com.squareup.picasso:picasso:2.71828] 130 @nisrulz

Slide 131

Slide 131 text

Links/References Android Libraries I have built: https://github.com/nisrulz/nisrulz.github.io#open-source-co ntributions Auto initialize android library example: https://github.com/nisrulz/android-examples/tree/develop/Au toInitLibrary Lifecycle Aware android library example: https://github.com/nisrulz/android-examples/tree/develop/Li feCycleCompForLib 131 @nisrulz

Slide 132

Slide 132 text

twitter.com/nisrulz github.com/nisrulz www.nisrulz.com 132

Slide 133

Slide 133 text

twitter.com/nisrulz github.com/nisrulz www.nisrulz.com 133