Slide 1

Slide 1 text

Things I wish I knew when I started building android SDK/libraries Nishant Srivastava

Slide 2

Slide 2 text

Nishant Srivastava @nisrulz

Slide 3

Slide 3 text

@nisrulz #droidconDE Sensey https://github.com/nisrulz/sensey EasyDeviceInfo https://github.com/nisrulz/easydeviceinfo

Slide 4

Slide 4 text

Wait... what is an Android Library? @nisrulz #droidconDE

Slide 5

Slide 5 text

Android Library is... @nisrulz #droidconDE

Slide 6

Slide 6 text

Android Library is... + + = @nisrulz #droidconDE

Slide 7

Slide 7 text

Android Library is... Java code + + = @nisrulz #droidconDE

Slide 8

Slide 8 text

Android Library is... Java code + Android resources + = @nisrulz #droidconDE

Slide 9

Slide 9 text

Android Library is... Java code + Android resources + Android Manifest stub = @nisrulz #droidconDE

Slide 10

Slide 10 text

Android Library is... Java code + Android resources + Android Manifest stub = Android ARchive (AAR) @nisrulz #droidconDE

Slide 11

Slide 11 text

Why create an Android Library? @nisrulz #droidconDE

Slide 12

Slide 12 text

Why create an Android Library? Short Answer @nisrulz #droidconDE

Slide 13

Slide 13 text

Why create an Android Library? Short Answer You don’t have to… @nisrulz #droidconDE

Slide 14

Slide 14 text

Why create an Android Library? Short Answer You don’t have to… ...unless a solution already exists. Then use that. @nisrulz #droidconDE

Slide 15

Slide 15 text

Best Practices for building android libraries... ...that said, let us move on to @nisrulz #droidconDE

Slide 16

Slide 16 text

Ease of use @nisrulz #droidconDE

Slide 17

Slide 17 text

Ease of use Intuitive @nisrulz #droidconDE

Slide 18

Slide 18 text

Ease of use Intuitive Consistent @nisrulz #droidconDE

Slide 19

Slide 19 text

Ease of use Intuitive Consistent Easy to use, Hard to misuse @nisrulz #droidconDE

Slide 20

Slide 20 text

Avoid multiple arguments // Do not DO this void init(String apikey, int refresh, long interval, String type, String username, String email, String password); @nisrulz #droidconDE

Slide 21

Slide 21 text

Avoid multiple arguments // Do not DO this void init(String apikey, int refresh, long interval, String type, String username, String email, String password); // WHY? void init(“0123456789”,“prod”, 1000, 1, “nishant”, ”1234”, “nisrulz@gmail.com”); // Passing arguments in right order is easy to mess up here :( @nisrulz #droidconDE

Slide 22

Slide 22 text

Avoid multiple arguments // Do this void init(ApiSecret apisecret); @nisrulz #droidconDE

Slide 23

Slide 23 text

Avoid multiple arguments // Do this void init(ApiSecret apisecret); // where ApiSecret is public class ApiSecret{ String apikey; int refresh; long interval; String type; String name; String email; String pass; // constructor // validation checks(such as type safety) // setter and getters } @nisrulz #droidconDE

Slide 24

Slide 24 text

Avoid multiple arguments // Or use Builder Pattern AwesomeLib awesomelib = new AwesomeLib.AwesomeLibBuilder() .apisecret(mApisecret).refresh(mRefresh) .interval(mInterval).type(mType) .username(mUsername).email(mEmail).password(mPassword) .build(); } @nisrulz #droidconDE

Slide 25

Slide 25 text

Minimize Permissions @nisrulz #droidconDE

Slide 26

Slide 26 text

Minimize Permissions Use intents @nisrulz #droidconDE

Slide 27

Slide 27 text

Minimize Permissions Use intents Reduce req. permissions @nisrulz #droidconDE

Slide 28

Slide 28 text

Minimize Permissions Use intents Reduce req. permissions Check permission, use fallbacks @nisrulz #droidconDE

Slide 29

Slide 29 text

Minimize Permissions Use intents Reduce req. permissions Check permission, use fallbacks public boolean hasPermission(Context context, String permission) { int result = context.checkCallingOrSelfPermission(permission); return result == PackageManager.PERMISSION_GRANTED; } @nisrulz #droidconDE

Slide 30

Slide 30 text

Minimize Feature Requisite // Do not do this @nisrulz #droidconDE

Slide 31

Slide 31 text

Minimize Feature Requisite // Do not do this // Runtime feature detection String feature = PackageManager.FEATURE_BLUETOOTH; public boolean isFeatureAvailable(Context context, String feature) { return context.getPackageManager().hasSystemFeature(feature); } // Enable/Disable the functionality depending on availability of feature @nisrulz #droidconDE

Slide 32

Slide 32 text

Support different versions // RULE OF THUMB : Support the full spectrum of android versions @nisrulz #droidconDE

Slide 33

Slide 33 text

Support different versions // RULE OF THUMB : Support the full spectrum of android versions android { ... defaultConfig { .. minSdkVersion 9 targetSdkVersion 26 .. } } @nisrulz #droidconDE

Slide 34

Slide 34 text

Support different versions // How?? : Detect version and Enable/Disable features or use // a fallback @nisrulz #droidconDE

Slide 35

Slide 35 text

Support different versions // How?? : Detect version and Enable/Disable features or use // a fallback public boolean isOreoAndAbove(){ return Build.VERSION.SDK_INT>= Build.VERSION_CODES.O; } @nisrulz #droidconDE

Slide 36

Slide 36 text

Don’t log in production @nisrulz #droidconDE

Slide 37

Slide 37 text

Don’t log in production ...but log exceptions/errors @nisrulz #droidconDE

Slide 38

Slide 38 text

Don’t log in production ...but log exceptions/errors Provide flagged logging support AwesomeLibrary.init(apisecret,BuildConfig.DEBUG); @nisrulz #droidconDE

Slide 39

Slide 39 text

Don’t log in production // Provide flexibility to log when debug flag is true void init(ApiSecret apisecret,boolean debuggable){ try{ ... } catch(Exception ex){ if (debuggable){ // This is printed only when debuggable is true ex.printStackTrace(); } } } @nisrulz #droidconDE

Slide 40

Slide 40 text

Don’t log in production // Provide flexibility to log when debug flag is true void init(ApiSecret apisecret,boolean debuggable){ try{ ... } catch(Exception ex){ if (debuggable){ // This is printed only when debuggable is true ex.printStackTrace(); } } } @nisrulz #droidconDE

Slide 41

Slide 41 text

Degrade gracefully on error @nisrulz #droidconDE

Slide 42

Slide 42 text

Degrade gracefully on error Do not crash the app @nisrulz #droidconDE

Slide 43

Slide 43 text

Degrade gracefully on error Do not crash the app Disable feature/functionality @nisrulz #droidconDE

Slide 44

Slide 44 text

Catch specific exception // Do not do this try { // ... } catch(Exception e) { // ... } @nisrulz #droidconDE

Slide 45

Slide 45 text

Catch specific exception // Do this try { // ... } catch(IOException e) { // ... } @nisrulz #droidconDE

Slide 46

Slide 46 text

Handle poor network conditions @nisrulz #droidconDE

Slide 47

Slide 47 text

Handle poor network conditions Acknowledge unreliable network exists @nisrulz #droidconDE

Slide 48

Slide 48 text

Handle poor network conditions Acknowledge unreliable network exists Batch network calls @nisrulz #droidconDE

Slide 49

Slide 49 text

Handle poor network conditions Acknowledge unreliable network exists Batch network calls Prefetch data ahead of time @nisrulz #droidconDE

Slide 50

Slide 50 text

Handle poor network conditions Acknowledge unreliable network exists Batch network calls Prefetch data ahead of time Use better data structures such as flatbuffers @nisrulz #droidconDE

Slide 51

Slide 51 text

Implementation/api VS compile Before Gradle 4.0 compile Gradle 4.0+ onwards implementation api @nisrulz #droidconDE

Slide 52

Slide 52 text

Require min dependencies Keep a check on method count http://www.methodscount.com/plugins @nisrulz #droidconDE

Slide 53

Slide 53 text

Require min dependencies Let the app developer make the decision about inclusion @nisrulz #droidconDE

Slide 54

Slide 54 text

Require min dependencies Let the app developer make the decision about inclusion AwesomeLib module: dependencies { // Gradle v2.12 and below provided 'com.squareup.retrofit2:retrofit:2.1.0' // Gradle v2.12+ compileOnly 'com.squareup.retrofit2:retrofit:2.1.0' } @nisrulz #droidconDE

Slide 55

Slide 55 text

Require min dependencies Let the app developer make the decision about inclusion AwesomeLib module: dependencies { // Gradle v2.12 and below provided 'com.squareup.retrofit2:retrofit:2.1.0' // Gradle v2.12+ compileOnly 'com.squareup.retrofit2:retrofit:2.1.0' } @nisrulz #droidconDE

Slide 56

Slide 56 text

Require min dependencies Let the app developer make the decision about inclusion App module: dependencies { // ... implementation 'com.squareup.retrofit2:retrofit:2.1.0' } @nisrulz #droidconDE

Slide 57

Slide 57 text

Require min dependencies Enable/Disable feature based on availability private boolean hasRetrofitOnClasspath() { try { Class.forName("retrofit2.Retrofit"); return true; } catch (ClassNotFoundException ex) { ex.printStackTrace(); } return false; } @nisrulz #droidconDE

Slide 58

Slide 58 text

Require min dependencies Enable/Disable feature based on availability private boolean hasRetrofitOnClasspath() { try { Class.forName("retrofit2.Retrofit"); return true; } catch (ClassNotFoundException ex) { ex.printStackTrace(); } return false; } @nisrulz #droidconDE

Slide 59

Slide 59 text

Lifecycle Arch Components @nisrulz #droidconDE

Slide 60

Slide 60 text

Lifecycle Arch Components public class AwesomeLib implements LifecycleObserver{ @OnLifecycleEvent(Lifecycle.Event.ON_CREATE) public void executeFnOnCreate(){ // do something on create } @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY) public void cleanup(){ // do some cleanup tasks } } @nisrulz #droidconDE

Slide 61

Slide 61 text

Lifecycle Arch Components public class AwesomeLib implements LifecycleObserver{ @OnLifecycleEvent(Lifecycle.Event.ON_CREATE) public void executeFnOnCreate(){ // do something on create } @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY) public void cleanup(){ // do some cleanup tasks } } @nisrulz #droidconDE

Slide 62

Slide 62 text

Lifecycle Arch Components public class MainActivity extends LifecycleActivity { AwesomeLib awesomeLib; @Override protected void onCreate(Bundle savedInstanceState) { // .. awesomeLib = new AwesomeLib(); getLifecycle().addObserver(awesomeLib); } @Override protected void onDestroy() { // ... getLifecycle().removeObserver(awesomeLib); } } @nisrulz #droidconDE

Slide 63

Slide 63 text

Lifecycle Arch Components public class MainActivity extends LifecycleActivity { AwesomeLib awesomeLib; @Override protected void onCreate(Bundle savedInstanceState) { // .. awesomeLib = new AwesomeLib(); getLifecycle().addObserver(awesomeLib); } @Override protected void onDestroy() { // ... getLifecycle().removeObserver(awesomeLib); } } @nisrulz #droidconDE

Slide 64

Slide 64 text

Do not hog the startup @nisrulz #droidconDE

Slide 65

Slide 65 text

Do not hog the startup @nisrulz #droidconDE

Slide 66

Slide 66 text

Do not hog the startup You do not need to initialize everything, @nisrulz #droidconDE

Slide 67

Slide 67 text

Do not hog the startup You do not need to initialize everything, Try to do lazy initialization @nisrulz #droidconDE

Slide 68

Slide 68 text

Remove functionality gracefully /** * @deprecated As of release 2.0, replaced by {@link #getPreferredSize()} */ @Deprecated public Dimension preferredSize() { return getPreferredSize(); } @nisrulz #droidconDE

Slide 69

Slide 69 text

Document everything Provide Readme.md @nisrulz #droidconDE

Slide 70

Slide 70 text

Document everything Provide Readme.md Include javadocs in code @nisrulz #droidconDE

Slide 71

Slide 71 text

Document everything Provide Readme.md Include javadocs in code Bundle a sample app @nisrulz #droidconDE

Slide 72

Slide 72 text

Document everything Provide Readme.md Include javadocs in code Bundle a sample app Maintain a changelog http://keepachangelog.com @nisrulz #droidconDE

Slide 73

Slide 73 text

Document everything @nisrulz #droidconDE

Slide 74

Slide 74 text

License is Important https://choosealicense.com/ @nisrulz #droidconDE

Slide 75

Slide 75 text

License is Important /* * Copyright (C) 2016 Nishant Srivastava * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ @nisrulz #droidconDE

Slide 76

Slide 76 text

Versioning Strategy Define a versioning scheme i.e MAJOR.MINOR.PATCH http://semver.org/ @nisrulz #droidconDE

Slide 77

Slide 77 text

Versioning Strategy To make 2 versions coexist, release under a new group ID @nisrulz #droidconDE

Slide 78

Slide 78 text

Versioning Strategy To make 2 versions coexist, release under a new group ID i.e 1.x = io.reactivex:rxjava:x.y.z 2.x = io.reactivex.rxjava2:rxjava:2.x.y @nisrulz #droidconDE

Slide 79

Slide 79 text

Proguard, wait… what? @nisrulz #droidconDE

Slide 80

Slide 80 text

Proguard, wait… what? Proguard rules can be shipped in an android library @nisrulz #droidconDE

Slide 81

Slide 81 text

Proguard, wait… what? Proguard rules can be shipped in an android library android { ... defaultConfig { ... versionName "1.0.0" ... consumerProguardFiles 'consumer-proguard-rules.pro' } } @nisrulz #droidconDE

Slide 82

Slide 82 text

Proguard, wait… what? @nisrulz #droidconDE

Slide 83

Slide 83 text

Proguard, wait… what? @nisrulz #droidconDE

Slide 84

Slide 84 text

Proguard, wait… what? @nisrulz #droidconDE

Slide 85

Slide 85 text

References BlogPost:https://android.jlelse.eu/things-i-wish-i-knew-when-i-star ted-building-android-sdk-libraries-dba1a524d619 My open sourced android libraries:https://github.com/nisrulz/nisrulz.github.io#open-source- contributions Sensey:https://github.com/nisrulz/sensey EasyDeviceInfo:https://github.com/nisrulz/easydeviceinfo

Slide 86

Slide 86 text

Credits Emoji Icons designed by Freepik from Flaticon

Slide 87

Slide 87 text

Thank You Q & A twitter.com/ nisrulz github.com/ nisrulz .com

Slide 88

Slide 88 text

Things I wish I knew when I started building android SDK/libraries twitter.com/ nisrulz github.com/ nisrulz .com