Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Build.Better.­Android.Libraries

 Build.Better.­Android.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.

Working Gif Version: https://goo.gl/HQFX7n

Ab4fa54bccd8073d0c0b4d4a2dd4193f?s=128

Nishant Srivastava

April 25, 2017
Tweet

More Decks by Nishant Srivastava

Other Decks in Technology

Transcript

  1. Build.Better. Android.Libraries Nishant Srivastava @nisrulz

  2. About me Nishant Srivastava Software Engineer/Founding Team Member (at) Omni

    Labs, Inc. Lead Organizer (at) GDG, New Delhi, India Open Source enthusiast @nisrulz
  3. Before we begin... @nisrulz

  4. What Is an Android Library? @nisrulz

  5. Android Library is... ...simply put, pre-written reusable logic in code,

    for android apps... @nisrulz
  6. Android Library is... ...simply put, pre-written reusable logic in code,

    for android apps... @nisrulz
  7. Android Library is... Java code + <secret ingredient> + <secret

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

    ingredient> = @nisrulz
  9. Android Library is... Java code + android resources + android

    manifest stub = @nisrulz
  10. Android Library is... Java code + android resources + android

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

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

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

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

    to @nisrulz If a solution already exists, use it
  15. Best Practices for building android libraries... @nisrulz ...with that, let

    us move on to
  16. Ease of use Intuitive @nisrulz

  17. Ease of use Intuitive ◦ It should do what the

    user of android library expects it to do without having to look up the documentation. @nisrulz
  18. Ease of use Intuitive ◦ It should do what the

    user of android library expects it to do without having to look up the documentation. Consistent @nisrulz
  19. Ease of use Intuitive ◦ It should do what the

    user of android library expects it to do without having to look up the documentation. Consistent ◦ The code for the android library should be well thought and should not change drastically between versions @nisrulz
  20. Ease of use Intuitive ◦ It should do what the

    user of android library expects it to do without having to look up the documentation. Consistent ◦ The code for the android library should be well thought and should not change drastically between versions Easy to use, hard to misuse @nisrulz
  21. Ease of use Intuitive ◦ It should do what the

    user of android library expects it to do without having to look up the documentation. Consistent ◦ The code for the android library should be well thought and should not change drastically between versions Easy to use, hard to misuse ◦ Validation checks, sane defaults, handle errors @nisrulz
  22. Avoid multiple arguments @nisrulz

  23. Avoid multiple arguments // Do not DO this void init(String

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

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

    apikey, int refresh, long interval, String type, String username, String email, String password); @nisrulz // WHY? void init(“0123456789”, true, 1000, “prod”, “nishant”, ”1234”, “nisrulz@gmail.com”);
  26. Avoid multiple arguments // Do not DO this void init(String

    apikey, int refresh, long interval, String type, String username, String email, String password); @nisrulz // WHY? void init(“0123456789”, true, 1000, “prod”, “nishant”, ”1234”, “nisrulz@gmail.com”); // Easy to mess up things here :(
  27. Avoid multiple arguments // Do not DO this void init(String

    apikey, int refresh, long interval, String type, String username, String email, String password); @nisrulz // DO this void init(ApiSecret apisecret);
  28. // where ApiSecret public class ApiSecret{ String apikey; int refresh;

    long interval; String type; String name; String email; String pass; // constructor /* you can define proper checks(such as type safety) and * conditions to validate data before it gets set */ // setter and getters } @nisrulz
  29. Avoid multiple arguments // Do not DO this boolean init(String

    apikey, int refresh, long interval, String type, String username, String email, String password); @nisrulz // DO this boolean init(ApiSecret apisecret); // Or use a Builder Pattern
  30. // Builder Pattern AwesomeLib awesomelib = new AwesomeLib.AwesomeLibBuilder() .apisecret(mApisecret) .refresh(mRefresh)

    .interval(mInterval) .type(mType) .username(mUsername) .email(mEmail) .password(mPassword) .build(); } @nisrulz
  31. Minimize Permissions Use Intents @nisrulz

  32. Minimize Permissions Use Intents ◦ Let dedicated apps do the

    work for you. @nisrulz
  33. Minimize Permissions Use Intents ◦ Let dedicated apps do the

    work for you. Reduce the no. of permissions @nisrulz
  34. Minimize Permissions Use Intents ◦ Let dedicated apps do the

    work for you. Reduce the no. of permissions Check for permission, use fallbacks @nisrulz
  35. Minimize Permissions Use Intents ◦ Let dedicated apps do the

    work for you. Reduce the no. of permissions Check for permission, use fallbacks ◦ public boolean hasPermission(Context context, String permission) { int result = context.checkCallingOrSelfPermission(permission); return result == PackageManager.PERMISSION_GRANTED; } @nisrulz
  36. Minimize Requisites // Do not do this <uses-feature android:name="android.hardware.bluetooth" />

    @nisrulz
  37. Minimize Requisites // Do not do this <uses-feature android:name="android.hardware.bluetooth" />

    // Use this String feature = PackageManager.FEATURE_BLUETOOTH; public boolean isFeatureAvailable(Context context, String feature) { return context.getPackageManager().hasSystemFeature(feature); } @nisrulz
  38. Minimize Requisites // Do not do this <uses-feature android:name="android.hardware.bluetooth" />

    // Use this String feature = PackageManager.FEATURE_BLUETOOTH; public boolean isFeatureAvailable(Context context, String feature) { return context.getPackageManager().hasSystemFeature(feature); } // Enable/Disable the functionality dependent on the // feature as per requirement @nisrulz
  39. Support different versions /* RULE OF THUMB : Support the

    full spectrum of android * versions */ @nisrulz
  40. Support different versions /* RULE OF THUMB : Support the

    full spectrum of android * versions */ android { ... defaultConfig { .. minSdkVersion 9 targetSdkVersion 25 .. } } @nisrulz
  41. Support different versions /* RULE OF THUMB : Enable/Disable features

    or use a fallback * based on detected version */ @nisrulz
  42. Support different versions /* RULE OF THUMB : Enable/Disable features

    or use a fallback * based on detected version */ // Method to check if the Android Version on the device is greater than or equal to Marshmallow. public boolean isMarshmallow(){ return Build.VERSION.SDK_INT>= Build.VERSION_CODES.M; } @nisrulz
  43. Do not log in production @nisrulz

  44. Do not log in production @nisrulz ...just Don’t. Seriously don’t.

  45. Do not log in production Use Build Variants @nisrulz

  46. Do not log in production Use Build Variants Flagged Logging

    @nisrulz
  47. Do not log in production Use Build Variants Flagged Logging

    ◦ MyAwesomeLibrary.init(apisecret,BuildConfig.DEBUG); @nisrulz
  48. Do not log in production Use proguard // add to

    your proguard file -assumenosideeffects class android.util.Log { public static boolean isLoggable(java.lang.String, int); public static int v(...); public static int i(...); public static int w(...); public static int d(...); public static int e(...); } @nisrulz
  49. Do not log in production Use proguard // enable proguard

    in build.gradle, switch to proguard-android-optimize .txt android { ... buildTypes { release { ... minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android-optimize .txt'), 'proguard-rules.pro' } } } @nisrulz
  50. … we do not want this to happen! @nisrulz

  51. Do not crash silently and fail fast @nisrulz Log Errors

    and Exception
  52. // 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
  53. Degrade gracefully in an event of an error @nisrulz Don’t

    crash the app, Disable functionality
  54. Catch specific exception @nisrulz // Do not do this try

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

    ... } catch(NullpointerException e) { // ... }
  56. @nisrulz

  57. Handle poor network conditions @nisrulz

  58. Handle poor network conditions 1. Prepare for unreliable/flaky network conditions

    @nisrulz
  59. Handle poor network conditions 1. Prepare for unreliable/flaky network conditions

    2. Batch your network calls @nisrulz
  60. Handle poor network conditions 1. Prepare for unreliable/flaky network conditions

    2. Batch your network calls 3. Prefetch data ahead of time @nisrulz
  61. Handle poor network conditions 1. Prepare for unreliable/flaky network conditions

    2. Batch your network calls 3. Prefetch data ahead of time 4. Replace JSON/XML with flatbuffers @nisrulz
  62. Handle poor network conditions 1. Prepare for unreliable/flaky network conditions

    2. Batch your network calls 3. Prefetch data ahead of time 4. Replace JSON/XML with flatbuffers @nisrulz
  63. @nisrulz

  64. @nisrulz

  65. @nisrulz

  66. Reluctance to include large libraries as dependencies @nisrulz

  67. Reluctance to include large libraries as dependencies WHY ? @nisrulz

  68. Reluctance to include large libraries as dependencies WHY ? Methods

    Counts! @nisrulz
  69. Do not require dependencies unless you very much have to

    Avoid bloating the library with dependencies @nisrulz
  70. Do not require dependencies unless you very much have to

    Get the developer to provide you those dependencies @nisrulz
  71. Do not require dependencies unless you very much have to

    Get the developer to provide you those dependencies dependencies { // for gradle version 2.12 and below provided 'com.squareup.okhttp3:okhttp:3.7.0' // or for gradle version 2.12+ compileOnly 'com.squareup.okhttp3:okhttp:3.7.0' } @nisrulz
  72. Do not require dependencies unless you very much have to

    Enable/disable features based on availability of dependency @nisrulz
  73. Do not require dependencies unless you very much have to

    Enable/disable features based on availability of dependency private boolean hasOKHttpOnClasspath() { try { Class.forName("com.squareup.okhttp3.OkHttpClient"); return true; } catch (ClassNotFoundException ex) { ex.printStackTrace(); } return false; } @nisrulz
  74. Try not to hog the startup @nisrulz

  75. Try not to hog the startup @nisrulz

  76. Remove features and functionalities gracefully @nisrulz

  77. Remove features and functionalities gracefully Mark @Deprecated before removing a

    public API
  78. Make your code testable @nisrulz

  79. Document Everything! @nisrulz

  80. Document Everything! 1. Create a Readme.md file @nisrulz

  81. Document Everything! 1. Create a Readme.md file 2. Have Javadoc

    comments @nisrulz
  82. Document Everything! 1. Create a Readme.md file 2. Have Javadoc

    comments 3. Bundle a sample app @nisrulz
  83. Document Everything! 1. Create a Readme.md file 2. Have Javadoc

    comments 3. Bundle a sample app 4. Keep a detailed changelog of releases @nisrulz
  84. Document Everything! @nisrulz

  85. Provide a most minimalistic sample app @nisrulz

  86. Consider putting up a license @nisrulz https://choosealicense.com/

  87. Get feedback, lots of them @nisrulz

  88. As a rule of thumb follow the rule of SPOIL-ing

    your Library Simple — Briefly and Clearly expressed Purposeful — Having or showing resolve Opensource — Universal Access, Free license Idiomatic — Natural to the native environment Logical — Clear, Sound Reasoning @nisrulz
  89. References BlogPost: https://android.jlelse.eu/things-i-wish-i-knew-when-i-started-bu ilding-android-sdk-libraries-dba1a524d619 Open Source android libraries I have

    made: https://github.com/nisrulz/nisrulz.github.io#android-librariessdk @nisrulz
  90. Thank You Questions? @nisrulz