[Droidcon Berlin '17] Things I wish I knew when I started building Android sdk/libraries

[Droidcon Berlin '17] Things I wish I knew when I started building Android sdk/libraries

As more and more people start building Android Libraries, the whole process of building a better API for developers is getting bloated and everyone is coming up with their own ideas. However, if android library developers follow a certain standard with a rationale they can avoid most of the pitfalls. Building an android library is easy, but building one that keeps in mind developer happiness is rare but definitely not hard. The session would cover how one can build android libraries taking in consideration to exposing more informative API, making sure the best resources are utilized efficiently and that one does not force the app developer with redundant dependencies and complexities.

Animated Gif Version: https://goo.gl/WNeR4A

Video: https://www.youtube.com/watch?v=RAZEIrmtUPo

Link to blog post: https://android.jlelse.eu/things-i-wish-i-knew-when-i-started-building-android-sdk-libraries-dba1a524d619

Sketchnotes by:
Chiu-Ki Chan: https://twitter.com/chiuki/status/905046880723329024
Garima Jain: https://twitter.com/ragdroid/status/905053186318368770
Miriam Busch: https://twitter.com/miphoni/status/905174390312239105

Ab4fa54bccd8073d0c0b4d4a2dd4193f?s=128

Nishant Srivastava

September 05, 2017
Tweet

Transcript

  1. Things I wish I knew when I started building android

    SDK/libraries Nishant Srivastava
  2. Nishant Srivastava @nisrulz

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

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

  5. Android Library is... @nisrulz #droidconDE

  6. Android Library is... <secret ingredient> + <secret ingredient> + <secret

    ingredient> = <Android Library> @nisrulz #droidconDE
  7. Android Library is... Java code + <secret ingredient> + <secret

    ingredient> = <Android Library> @nisrulz #droidconDE
  8. Android Library is... Java code + Android resources + <secret

    ingredient> = <Android Library> @nisrulz #droidconDE
  9. Android Library is... Java code + Android resources + Android

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

    Manifest stub = Android ARchive (AAR) @nisrulz #droidconDE
  11. Why create an Android Library? @nisrulz #droidconDE

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

  13. Why create an Android Library? Short Answer You don’t have

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

    to… ...unless a solution already exists. Then use that. @nisrulz #droidconDE
  15. Best Practices for building android libraries... ...that said, let us

    move on to @nisrulz #droidconDE
  16. Ease of use @nisrulz #droidconDE

  17. Ease of use Intuitive @nisrulz #droidconDE

  18. Ease of use Intuitive Consistent @nisrulz #droidconDE

  19. Ease of use Intuitive Consistent Easy to use, Hard to

    misuse @nisrulz #droidconDE
  20. 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
  21. 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
  22. Avoid multiple arguments // Do this void init(ApiSecret apisecret); @nisrulz

    #droidconDE
  23. 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
  24. 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
  25. Minimize Permissions @nisrulz #droidconDE

  26. Minimize Permissions Use intents @nisrulz #droidconDE

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

  28. Minimize Permissions Use intents Reduce req. permissions Check permission, use

    fallbacks @nisrulz #droidconDE
  29. 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
  30. Minimize Feature Requisite // Do not do this <uses-feature android:name="android.hardware.bluetooth"

    /> @nisrulz #droidconDE
  31. Minimize Feature Requisite // Do not do this <uses-feature android:name="android.hardware.bluetooth"

    /> // 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
  32. Support different versions // RULE OF THUMB : Support the

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

    full spectrum of android versions android { ... defaultConfig { .. minSdkVersion 9 targetSdkVersion 26 .. } } @nisrulz #droidconDE
  34. Support different versions // How?? : Detect version and Enable/Disable

    features or use // a fallback @nisrulz #droidconDE
  35. 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
  36. Don’t log in production @nisrulz #droidconDE

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

  38. Don’t log in production ...but log exceptions/errors Provide flagged logging

    support AwesomeLibrary.init(apisecret,BuildConfig.DEBUG); @nisrulz #droidconDE
  39. 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
  40. 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
  41. Degrade gracefully on error @nisrulz #droidconDE

  42. Degrade gracefully on error Do not crash the app @nisrulz

    #droidconDE
  43. Degrade gracefully on error Do not crash the app Disable

    feature/functionality @nisrulz #droidconDE
  44. Catch specific exception // Do not do this try {

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

    } catch(IOException e) { // ... } @nisrulz #droidconDE
  46. Handle poor network conditions @nisrulz #droidconDE

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

  48. Handle poor network conditions Acknowledge unreliable network exists Batch network

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

    calls Prefetch data ahead of time @nisrulz #droidconDE
  50. 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
  51. Implementation/api VS compile Before Gradle 4.0 compile Gradle 4.0+ onwards

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

    @nisrulz #droidconDE
  53. Require min dependencies Let the app developer make the decision

    about inclusion @nisrulz #droidconDE
  54. 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
  55. 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
  56. 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
  57. 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
  58. 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
  59. Lifecycle Arch Components @nisrulz #droidconDE

  60. 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
  61. 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
  62. 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
  63. 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
  64. Do not hog the startup @nisrulz #droidconDE

  65. Do not hog the startup @nisrulz #droidconDE

  66. Do not hog the startup You do not need to

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

    initialize everything, Try to do lazy initialization @nisrulz #droidconDE
  68. Remove functionality gracefully /** * @deprecated As of release 2.0,

    replaced by {@link #getPreferredSize()} */ @Deprecated public Dimension preferredSize() { return getPreferredSize(); } @nisrulz #droidconDE
  69. Document everything Provide Readme.md @nisrulz #droidconDE

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

  71. Document everything Provide Readme.md Include javadocs in code Bundle a

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

    sample app Maintain a changelog http://keepachangelog.com @nisrulz #droidconDE
  73. Document everything @nisrulz #droidconDE

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

  75. 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
  76. Versioning Strategy Define a versioning scheme i.e MAJOR.MINOR.PATCH http://semver.org/ @nisrulz

    #droidconDE
  77. Versioning Strategy To make 2 versions coexist, release under a

    new group ID @nisrulz #droidconDE
  78. 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
  79. Proguard, wait… what? @nisrulz #droidconDE

  80. Proguard, wait… what? Proguard rules can be shipped in an

    android library @nisrulz #droidconDE
  81. 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
  82. Proguard, wait… what? @nisrulz #droidconDE

  83. Proguard, wait… what? @nisrulz #droidconDE

  84. Proguard, wait… what? @nisrulz #droidconDE

  85. 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
  86. Credits Emoji Icons designed by Freepik from Flaticon

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

  88. Things I wish I knew when I started building android

    SDK/libraries twitter.com/ nisrulz github.com/ nisrulz .com