Writing Android Libraries

1fa9cb8c7997c8c4d3d251fb5e41f749?s=47 Realm
April 06, 2015
23k

Writing Android Libraries

Presented to the Bay Area Android Group on March 25th 2015

1fa9cb8c7997c8c4d3d251fb5e41f749?s=128

Realm

April 06, 2015
Tweet

Transcript

  1. 2.

    Emanuele Zattin Born and raised in Padova, Italy Living in

    Copenhagen, Denmark since 2005 Automation enthusiast Jenkins CI contributor since 2010 Java developer at Realm About me
  2. 3.

    Embedded on-device mobile database Easy — saves app makers months

    of time Cross-platform — iOS & Android for now. More are coming Fast — way faster than existing solutions About Realm
  3. 8.

    Your code depends on Android idioms: • UI • Looper/Handler

    • Sensors • Native code • Many more! Why writing an Android library?
  4. 9.

    How hard can it be right? Just fire Android Studio

    up and start a new project! Step one: Getting started!
  5. 10.

    Android Studio supports the creation of: Step one: Getting started!

    Application Library New project ✓ ✗ New module ✓ ✓
  6. 11.

    Option 1: Android Studio 1. Create a new application project

    2. Add a library module 3. Remove the application module Step one: Getting started!
  7. 12.

    Option 2: The Command Line $ android create lib-project -t

    1 -k it.droidcon.awesomelib -p . -g -v 1.1.3 -t: target (Use android  list  targets to get a list of target ids) -k: package name -p: path to the project -g: make it a Gradle project (requires SDK >= 19) -v: version of the Android Gradle plugin to use Step one: Getting started!
  8. 15.

    API Design It’s a huge subject that goes far beyond

    this presentation but here are some pointers and reference: Effective Java 2, Joshua Bloch How To Design A Good API and Why it Matters, Joshua Bloch Step two: Code, code, code!
  9. 16.

    Characteristics of a good API (Joshua Bloch) • Easy to

    learn • Easy to use, even without documentation • Hard to misuse • Easy to read and maintain code that uses it • Sufficiently powerful to satisfy requirements • Easy to extend • Appropriate to audience Step two: Code, code, code!
  10. 18.

    Testing is universally important but even more so for libraries

    Testing an Android library is just like testing an Android application Step three: Test
  11. 19.

    Testing is universally important but even more so for libraries

    Testing an Android library is just like testing an Android application Yes, JUnit 3 is not so good and lacks a particularly important feature when testing libraries: parametric tests Step three: Test
  12. 20.

    Testing is universally important but even more so for libraries

    Testing an Android library is just like testing an Android application Yes, JUnit 3 is not so good and lacks a particularly important feature when testing libraries: parametric tests Luckily there’s a solution: Burst Step three: Test
  13. 21.

    Automate your tests! Jenkins is a wonderful tool for this.

    It offers more than one thousand plugins some of which specialised for Android development. Step three: Test
  14. 25.

    Some must-have Jenkins plugins include: • Job Config History plugin

    • Git plugin • Gradle plugin Step three: Test
  15. 26.

    Some must-have Jenkins plugins include: • Job Config History plugin

    • Git plugin • Gradle plugin • Android Emulator plugin Step three: Test
  16. 27.

    Some must-have Jenkins plugins include: • Job Config History plugin

    • Git plugin • Gradle plugin • Android Emulator plugin • Jenkins comes with JUnit and Matrix job support out of the box Step three: Test
  17. 28.

    Another useful way to test your library (and showcase it)

    is to write one or more example apps. Step three: Test
  18. 29.

    Another useful way to test your library (and showcase it)

    is to write one or more example apps. Running monkey on the app ensures it doesn’t suffer from crashes and ANRs Step three: Test
  19. 30.

    Another useful way to test your library (and showcase it)

    is to write one or more example apps. Running monkey on the app ensures it doesn’t suffer from crashes and ANRs A useful Gradle plugin:
 https://github.com/novoda/gradle-android-command-plugin Step three: Test
  20. 32.

    Aar vs Jar • Aar is supported by Gradle and

    Android Studio Step four: Publish
  21. 33.

    Aar vs Jar • Aar is supported by Gradle and

    Android Studio • Aar is not supported by Ant and Eclipse Step four: Publish
  22. 34.

    Aar vs Jar • Aar is supported by Gradle and

    Android Studio • Aar is not supported by Ant and Eclipse • Using local Aar files is not trivial Step four: Publish
  23. 35.

    Aar vs Jar • Aar is supported by Gradle and

    Android Studio • Aar is not supported by Ant and Eclipse • Using local Aar files is not trivial • Do you want to support Eclipse? Use Jar! Step four: Publish
  24. 36.

    The Android Gradle plugin will generate an Aar file How

    to generate a Jar instead?
 The Aar actually contains our Jar already! task generateJar(type: Copy) { group 'Build' description 'blah blah...' dependsOn assemble from 'build/intermediates/bundles/release/classes.jar' into 'build/libs' rename('classes.jar', 'awesome-library.jar') } Step four: Publish
  25. 38.

    Bintray requires a source Jar task androidSourcesJar(type: Jar) { from

    android.sourceSets.main.java.srcDirs } Step four: Publish
  26. 39.

    Bintray also requires a Javadoc Jar android.libraryVariants.all { variant ->

    task("javadoc${variant.name.capitalize()}", type: Javadoc) { description "Generates Javadoc for $variant.name." group 'Docs' source = variant.javaCompile.source ext.androidJar = files(plugins .findPlugin(“com.android.library") .getBootClasspath()) classpath = files(variant.javaCompile.classpath.files) + ext.androidJar exclude '**/BuildConfig.java' exclude '**/R.java' } } Step four: Publish
  27. 40.

    Bintray also provides a Gradle plugin for the actual publishing

    https://github.com/bintray/gradle-bintray-plugin The configuration is not trivial, and in the beginning it might be easier to just do the release manually on the binary website Step four: Publish
  28. 41.

    Annotation processing is a functionality of javac used for scanning

    and processing annotations at compile time Advanced Topics: Annotation Processor
  29. 42.

    Annotation processing is a functionality of javac used for scanning

    and processing annotations at compile time You can write your own annotation processor. Advanced Topics: Annotation Processor
  30. 43.

    Annotation processing is a functionality of javac used for scanning

    and processing annotations at compile time You can write your own annotation processor. Problems that annotation processing is good at solving: Advanced Topics: Annotation Processor
  31. 44.

    Annotation processing is a functionality of javac used for scanning

    and processing annotations at compile time You can write your own annotation processor. Problems that annotation processing is good at solving: • Boilerplate removal Advanced Topics: Annotation Processor
  32. 45.

    Annotation processing is a functionality of javac used for scanning

    and processing annotations at compile time You can write your own annotation processor. Problems that annotation processing is good at solving: • Boilerplate removal • Introspection removal Advanced Topics: Annotation Processor
  33. 49.

    Popular Android libraries using annotation processing: • Dagger • Butter

    Knife • Autovalue/Autoparcel Advanced Topics: Annotation Processor
  34. 50.

    Popular Android libraries using annotation processing: • Dagger • Butter

    Knife • Autovalue/Autoparcel • Realm Advanced Topics: Annotation Processor
  35. 51.

    Bad news! The Android API does not support the 


    javax.annotation.processing package Advanced Topics: Annotation Processor
  36. 52.

    Create two new java sub-projects: • annotations (used both by

    the library and the processor) • annotations processor Advanced Topics: Annotation Processor
  37. 53.

    The Jar task will need to be modified: task androidJar(type:

    Jar) { dependsOn assemble group 'Build' description ‘blah blah’ from zipTree( 'build/intermediates/bundles/release/classes.jar') from zipTree( '../annotations-processor/build/libs/processor.jar') from zipTree( '../annotations/build/libs/annotations.jar') } Advanced Topics: Annotation Processor
  38. 54.

    The javadoc tasks will also have to be modified: android.libraryVariants.all

    { variant -> task("javadoc${variant.name.capitalize()}", type: Javadoc) { description "Generates Javadoc for $variant.name." group 'Docs' source = variant.javaCompile.source source "../annotations/src/main/java" ext.androidJar = files(plugins .findPlugin(“com.android.library") .getBootClasspath()) classpath = files(variant.javaCompile.classpath.files) + ext.androidJar exclude '**/BuildConfig.java' exclude '**/R.java' } } Advanced Topics: Annotation Processor
  39. 57.

    WARNING  [Project:  :lib]   Current  NDK  support  is  deprecated.  

    Alternative  will  be  provided  in  the  future. Advanced Topics: Native code
  40. 59.

    Solution 1 Ignore Google’s warning and keep using the Gradle

    NDK support. It works* but there is one missing feature: no ldFlags ndk  {        moduleName  "sanangeles"        cFlags  "-­‐DANDROID_NDK  -­‐DDISABLE_IMPORTGL"        ldLibs  "GLESv1_CM",  "dl",  "log"        stl  "stlport_static"   }   *for some definition of “works” Advanced Topics: Native code
  41. 60.

    Solution 2 Gradle native plugin Gotchas: • Requires extra logic

    to handle standalone toolchains • It might soon become obsolete Advanced Topics: Native code
  42. 61.

    How to include the native libraries in the Jar file?

    $ tree . !"" META-INF # $"" MANIFEST.MF !"" com # $"" amazing-library # $"" AmazingLibrary.class $"" lib !"" armeabi # $"" amazing-library.so !"" armeabi-v7a # $"" amazing-library.so $"" x86 $"" amazing-library.so Advanced Topics: Native code
  43. 62.

    How to generate the jar file in Gradle? task  androidJar(type:

     Jar,  dependsOn:  ['assemble'])  {        group  'Build'        description  ‘blah  blah'        from  zipTree('build/intermediates/bundles/release/classes.jar')        from(file('src/main/jniLibs'))  {              into  'lib'        }   }   Advanced Topics: Native code
  44. 63.
  45. 67.

    • Embrace Gradle • Explore Gradle plugins • Automate your

    tests • Bintray is the go-to solution for publishing Takeaways
  46. 68.

    • Embrace Gradle • Explore Gradle plugins • Automate your

    tests • Bintray is the go-to solution for publishing • Writing libraries rocks! Takeaways