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

Nishant Srivastava

April 25, 2017
Tweet

More Decks by Nishant Srivastava

Other Decks in Technology

Transcript

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

    Labs, Inc. Lead Organizer (at) GDG, New Delhi, India Open Source enthusiast @nisrulz
  2. Android Library is... Java code + android resources + android

    manifest stub = Android ARchive (AAR) @nisrulz
  3. Why create an Android Library? Short Answer You don’t have

    to @nisrulz If a solution already exists, use it
  4. 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
  5. 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
  6. 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
  7. 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
  8. 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
  9. Avoid multiple arguments // Do not DO this void init(String

    apikey, int refresh, long interval, String type, String username, String email, String password); @nisrulz
  10. 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?
  11. 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”, “[email protected]”);
  12. 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”, “[email protected]”); // Easy to mess up things here :(
  13. 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);
  14. // 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
  15. 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
  16. // Builder Pattern AwesomeLib awesomelib = new AwesomeLib.AwesomeLibBuilder() .apisecret(mApisecret) .refresh(mRefresh)

    .interval(mInterval) .type(mType) .username(mUsername) .email(mEmail) .password(mPassword) .build(); } @nisrulz
  17. Minimize Permissions Use Intents ◦ Let dedicated apps do the

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

    work for you. Reduce the no. of permissions Check for permission, use fallbacks @nisrulz
  19. 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
  20. 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
  21. 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
  22. Support different versions /* RULE OF THUMB : Support the

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

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

    or use a fallback * based on detected version */ @nisrulz
  25. 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
  26. Do not log in production Use Build Variants Flagged Logging

    ◦ MyAwesomeLibrary.init(apisecret,BuildConfig.DEBUG); @nisrulz
  27. 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
  28. 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
  29. // 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
  30. Catch specific exception @nisrulz // Do not do this try

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

    ... } catch(NullpointerException e) { // ... }
  32. Handle poor network conditions 1. Prepare for unreliable/flaky network conditions

    2. Batch your network calls 3. Prefetch data ahead of time @nisrulz
  33. 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
  34. 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
  35. Do not require dependencies unless you very much have to

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

    Get the developer to provide you those dependencies @nisrulz
  37. 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
  38. Do not require dependencies unless you very much have to

    Enable/disable features based on availability of dependency @nisrulz
  39. 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
  40. Document Everything! 1. Create a Readme.md file 2. Have Javadoc

    comments 3. Bundle a sample app @nisrulz
  41. 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
  42. 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