Slide 1

Slide 1 text

Writing Android Libraries Emanuele Zattin March 23, 2015 Bay Area Android Developer Group

Slide 2

Slide 2 text

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

Slide 3

Slide 3 text

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

Slide 4

Slide 4 text

Why would you want to write a library?

Slide 5

Slide 5 text

Modularity Why would you want to write a library?

Slide 6

Slide 6 text

Modularity Reusability Why would you want to write a library?

Slide 7

Slide 7 text

Modularity Reusability Vanity Why would you want to write a library?

Slide 8

Slide 8 text

Your code depends on Android idioms: • UI • Looper/Handler • Sensors • Native code • Many more! Why writing an Android library?

Slide 9

Slide 9 text

How hard can it be right? Just fire Android Studio up and start a new project! Step one: Getting started!

Slide 10

Slide 10 text

Android Studio supports the creation of: Step one: Getting started! Application Library New project ✓ ✗ New module ✓ ✓

Slide 11

Slide 11 text

Option 1: Android Studio 1. Create a new application project 2. Add a library module 3. Remove the application module Step one: Getting started!

Slide 12

Slide 12 text

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!

Slide 13

Slide 13 text

Step one: Getting started!

Slide 14

Slide 14 text

Step two: Code, code, code!

Slide 15

Slide 15 text

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!

Slide 16

Slide 16 text

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!

Slide 17

Slide 17 text

Testing is universally important but even more so for libraries Step three: Test

Slide 18

Slide 18 text

Testing is universally important but even more so for libraries Testing an Android library is just like testing an Android application Step three: Test

Slide 19

Slide 19 text

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

Slide 20

Slide 20 text

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

Slide 21

Slide 21 text

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

Slide 22

Slide 22 text

Some must-have Jenkins plugins include: Step three: Test

Slide 23

Slide 23 text

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

Slide 24

Slide 24 text

Some must-have Jenkins plugins include: • Job Config History plugin • Git plugin Step three: Test

Slide 25

Slide 25 text

Some must-have Jenkins plugins include: • Job Config History plugin • Git plugin • Gradle plugin Step three: Test

Slide 26

Slide 26 text

Some must-have Jenkins plugins include: • Job Config History plugin • Git plugin • Gradle plugin • Android Emulator plugin Step three: Test

Slide 27

Slide 27 text

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

Slide 28

Slide 28 text

Another useful way to test your library (and showcase it) is to write one or more example apps. Step three: Test

Slide 29

Slide 29 text

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

Slide 30

Slide 30 text

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

Slide 31

Slide 31 text

Aar vs Jar Step four: Publish

Slide 32

Slide 32 text

Aar vs Jar • Aar is supported by Gradle and Android Studio Step four: Publish

Slide 33

Slide 33 text

Aar vs Jar • Aar is supported by Gradle and Android Studio • Aar is not supported by Ant and Eclipse Step four: Publish

Slide 34

Slide 34 text

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

Slide 35

Slide 35 text

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

Slide 36

Slide 36 text

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

Slide 37

Slide 37 text

Where to publish? Step four: Publish

Slide 38

Slide 38 text

Bintray requires a source Jar task androidSourcesJar(type: Jar) { from android.sourceSets.main.java.srcDirs } Step four: Publish

Slide 39

Slide 39 text

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

Slide 40

Slide 40 text

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

Slide 41

Slide 41 text

Annotation processing is a functionality of javac used for scanning and processing annotations at compile time Advanced Topics: Annotation Processor

Slide 42

Slide 42 text

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

Slide 43

Slide 43 text

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

Slide 44

Slide 44 text

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

Slide 45

Slide 45 text

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

Slide 46

Slide 46 text

Popular Android libraries using annotation processing: Advanced Topics: Annotation Processor

Slide 47

Slide 47 text

Popular Android libraries using annotation processing: • Dagger Advanced Topics: Annotation Processor

Slide 48

Slide 48 text

Popular Android libraries using annotation processing: • Dagger • Butter Knife Advanced Topics: Annotation Processor

Slide 49

Slide 49 text

Popular Android libraries using annotation processing: • Dagger • Butter Knife • Autovalue/Autoparcel Advanced Topics: Annotation Processor

Slide 50

Slide 50 text

Popular Android libraries using annotation processing: • Dagger • Butter Knife • Autovalue/Autoparcel • Realm Advanced Topics: Annotation Processor

Slide 51

Slide 51 text

Bad news! The Android API does not support the 
 javax.annotation.processing package Advanced Topics: Annotation Processor

Slide 52

Slide 52 text

Create two new java sub-projects: • annotations (used both by the library and the processor) • annotations processor Advanced Topics: Annotation Processor

Slide 53

Slide 53 text

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

Slide 54

Slide 54 text

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

Slide 55

Slide 55 text

NDK Advanced Topics: Native code

Slide 56

Slide 56 text

NDK Advanced Topics: Native code

Slide 57

Slide 57 text

WARNING  [Project:  :lib]   Current  NDK  support  is  deprecated.   Alternative  will  be  provided  in  the  future. Advanced Topics: Native code

Slide 58

Slide 58 text

Advanced Topics: Native code

Slide 59

Slide 59 text

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

Slide 60

Slide 60 text

Solution 2 Gradle native plugin Gotchas: • Requires extra logic to handle standalone toolchains • It might soon become obsolete Advanced Topics: Native code

Slide 61

Slide 61 text

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

Slide 62

Slide 62 text

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

Slide 63

Slide 63 text

Takeaways

Slide 64

Slide 64 text

• Embrace Gradle Takeaways

Slide 65

Slide 65 text

• Embrace Gradle • Explore Gradle plugins Takeaways

Slide 66

Slide 66 text

• Embrace Gradle • Explore Gradle plugins • Automate your tests Takeaways

Slide 67

Slide 67 text

• Embrace Gradle • Explore Gradle plugins • Automate your tests • Bintray is the go-to solution for publishing Takeaways

Slide 68

Slide 68 text

• Embrace Gradle • Explore Gradle plugins • Automate your tests • Bintray is the go-to solution for publishing • Writing libraries rocks! Takeaways

Slide 69

Slide 69 text

Questions?