Reusable Components

In the world of Java outside of Android, reusable components rule the roost. Whether they are simple JARs, are tied in via inversion-of-control (IoC) containers like Spring, or rely on enterprise service buses like Mule, reusable Java components are a huge portion of the overall Java ecosystem. Even full-fledged applications, like Eclipse or NetBeans, are frequently made up of a number of inter-locking components, many of which are available for others to use in their own applications.

Android, too, supports this sort of reuse. In some cases, it follows standard Java approaches. However, in other cases, unique Android aspects, such as resources, steer developers in different directions for reuse.

This chapter will outline what reuse models are in use today and how you can package your own components for reuse.

Prerequisites

Understanding this chapter requires that you have read the core chapters of this book.

Where Do I Find Them?

Android historically has not had a “go-to” place to find reusable components. The Android Arsenal is probably the largest collection at present. Beyond that, look for recommendations in Stack Overflow answers, blog posts, and the like.

How Are They Packaged?

There are three main ways that reusable code gets packaged on Android: as a traditional Java JAR, as an Android library project, or (technically) as an APK. The last approach is usually used by apps that have user value in their own right, but also expose some sort of integration API for use by other apps, that you can take advantage of.

JARs

Android code that is pure code, without requiring its own resources, can be packaged into a JAR, no differently than can regular Java code outside of Android.

As was covered earlier in the book, to use such a JAR, just drop it into libs/. Its contents will be added to your compile path (so you can reference classes from the library) and its contents will be packaged in your APK (so those references will work at runtime).

Library Projects

Android code that relies upon resources — such as many reusable UI components, such as custom widgets — cannot be packaged as a simple JAR, as there is no way of packaging the Android resources in that JAR. Instead, Google created the Android library project as the “unit of reuse” for such cases.

Android library projects are sometimes published in full source form (usually open source projects), and sometimes are published as AARs in an artifact repository. Eclipse users can readily use the full-source library projects, but have limited ability to use AARs. Android Studio users can use either, and AARs may be as simple as adding a single line to build.gradle.

APKs

Using JARs or library projects fits in the “traditional” model of compile-time reuse. Android’s many IPC mechanisms offer plenty of options for run-time reuse, where your app communicates with another app, having that app do things on your behalf. In this case, the primary unit of reuse is not the JAR, or the library project, but the APK.

For example, the ZXing project publishes the Barcode Scanner app. This app not only allows users to scan barcodes, but allows other apps to scan barcodes, by asking Barcode Scanner to scan the barcodes and return results.

To integrate with such an app, you will need to find the instructions from the app’s developers on how to do that. Sometimes, they will tell you things that you would use directly (e.g., “call startActivityForResult() with an Intent that contains…”). Sometimes, they will distribute a client-side JAR that you can use that wraps up the low-level IPC details into something a bit easier to consume. For example, ZXing distributes an IntentIntegrator.java class file that you can use that not only handles requesting the scans, but also helping the user install Barcode Scanner if it is not already installed.

How Do I Create Them?

To create a reusable component, you start by getting a working code base, one that implements whatever it is that you desire. From there, you need to choose which of those aforementioned distribution patterns you believe is appropriate:

That, in turn, will drive how you take your code and create such a package. The basics of how to do that for the different alternatives is described in the following sections.

JARs

Creating a JAR for a reusable chunk of Android-related code is not significantly different than is creating a JAR for a reusable chunk of “ordinary” Java code.

First, you need a project that represents the “resuable chunk of Android-related code”. An easy way to do this is to just create a standard Android library project, but one where you do not bother creating any resources.

Once the code is ready for distribution, you can create a JAR from the compiled Java classes by your favorite traditional means. The author of this book, for example, adds custom Gradle tasks for this:


// from http://stackoverflow.com/a/19484146/115145

android.libraryVariants.all { variant ->
  def name = variant.buildType.name
  if (name.equals(com.android.builder.core.BuilderConstants.DEBUG)) {
    return; // Skip debug builds.
  }
  def task = project.tasks.create "jar${name.capitalize()}", Jar
  task.dependsOn variant.javaCompile
  task.from variant.javaCompile.destinationDir
  task.archiveName = "cwac-${task.archiveName}"
  task.exclude('com/commonsware/cwac/**/BuildConfig.**')
}

This will create JAR-building Gradle tasks for all non-debug build types, so you get Gradle tasks like jarRelease. It specifically excludes BuildConfig, which the CWAC libraries never use, but otherwise takes all of the library classes and packages them in a JAR, named after the library and version, with a cwac- prefix.

If your reusable code is pure Java, not involving Android at all, you are welcome to create a plain Java project and create your JAR from that. The only major recommendation would be to ensure that you are using some android.jar from the SDK, rather than a JDK rt.jar, to ensure that you are sticking with classes and methods that are in Android’s subset of the Java SE class library.

Standard Library Projects

In many respects, distributing a standard Android library project is even easier: just ZIP it up. Or, if it is in a public source control repository (e.g., GitHub), reusers can obtain it from that repository.

Of course, this will distribute the source code along with the resources and everything else. This is typical for an open source library project.

Android Studio and Gradle users can create AARs from their library projects. The assembleRelease task will create an AAR for the library in build/outputs/aar, named after the library and version (e.g., pager-0.2.3.jar).

Eclipse-Compatible Binary-Only Library Projects

AARs do not ship Java source code, but rather only binaries. However, AARs are not readily consumable from Eclipse.

It is possible to create an Eclipse-Compatible binary-only library project, one where your source code is replaced by a JAR. This can be useful for proprietary library projects, for example. However, there is one noteworthy limitation with today’s tools: the library project cannot itself depend upon a JAR or another library project.

For simpler library projects, the recipe is straightforward, given an already-existing Android library project:

  1. Compile the Java source (e.g., via Ant) and turn it into a JAR file.
  2. Create a copy of your original Android library project to serve as a distribution Android library project.
  3. Place the compiled JAR from step #1 and put it in libs/ of the distribution library project from step #2.
  4. Delete everything in src/ of the distribution library project (but leave the now-empty src/ directory there).
  5. Distribute the distribution library project (e.g., ZIP it up)

For example, an Ant target to create a distribution ZIP might be:


<target name="jar" depends="release">
    <delete file="bin/WhateverYouWantToCallYourLibrary.jar" />
    <jar destfile="bin/WhateverYouWantToCallYourLibrary.jar">
      <fileset dir="bin/classes">
        <exclude name="**/BuildConfig.class" />
        <exclude name="**/R.class" />
        <exclude name="**/R$*.class" />
      </fileset>
    </jar>
</target>
<target name="dist" depends="jar">
  <copy todir="/tmp/WhateverYouWantToCallYourLibrary/libs">
    <fileset dir="libs/" />
  </copy>
  <copy todir="/tmp/WhateverYouWantToCallYourLibrary/res">
    <fileset dir="res/" />
  </copy>
  <copy
    file="bin/WhateverYouWantToCallYourLibrary.jar"
    todir="/tmp/WhateverYouWantToCallYourLibrary/libs" />
  <copy
    file="AndroidManifest.xml"
    todir="/tmp/WhateverYouWantToCallYourLibrary" />
  <copy file="build.xml" todir="/tmp/WhateverYouWantToCallYourLibrary" />
  <copy
    file="project.properties"
    todir="/tmp/WhateverYouWantToCallYourLibrary" />
  <copy file="LICENSE" todir="/tmp/WhateverYouWantToCallYourLibrary" />
  <mkdir dir="/tmp/WhateverYouWantToCallYourLibrary/src" />
  <zip
    destfile="/tmp/WhateverYouWantToCallYourLibrary.zip"
    basedir="/tmp/"
    includes="WhateverYouWantToCallYourLibrary/**"
    whenempty="create" />
  <delete dir="/tmp/WhateverYouWantToCallYourLibrary" />
</target>

Assuming the existence of a /tmp/ directory (e.g., OS X or Linux), this will result in a WhateverYouWantToCallYourLibrary.zip file in /tmp/. Along the way, we:

APK

Most of your work for this distribution model is in writing and distributing the app to your end users, through the Play Store or your other chosen distribution channels.

In addition to that, you need to either document to reusers what sorts of IPC your app supports, or create a JAR or library project that reusers can use to perform that sort of integration. In the latter case, you would have a separate project representing that JAR or library project that you would distribute using any of the aforementioned approaches.

Other Considerations for Publishing Reusable Code

Of course, there is more to publishing a resuable component than code and perhaps Android resources. The following sections outline some other things to consider as you contemplate offering some code base up for reuse by third parties.

Licensing

Your reusable code should be accompanied by adequate licensing information.

Your License

The first license you should worry about is your own. Is your component open source? If so, you will want to ship a license file containing those terms. If your component is not open source, make sure there is a license agreement shipped with the component that lets the reuser know the terms of use.

Bear in mind that not all of your code necessarily has to have the same license. For example, you might have a proprietary license for the component itself, but have sample code be licensed under Apache License 2.0 for easy copy-and-paste.

Third-Party License Impacts

You may need to include licenses for third party libraries that you have to ship along with your own JAR. Obviously, those licenses would need to give you redistribution rights — otherwise, you cannot ship those libraries in the first place.

Sometimes, the third party licenses will impact your project more directly, such as:

  1. Incorporating a GPL library may require your project to be licensed under the same license
  2. Adding support for Facebook data may require you to limit your API or require reusers to supply API access keys, since you probably do not have rights to redistribute Facebook data

Documenting the Usage

If you are expecting people to reuse your code, you are going to have to tell them how to do that. Usually, these sorts of packages ship documentation with them, sometimes a clone of what is available online. That way, developers can choose the local or hosted edition of the documentation as they wish.

Note that generated documentation (e.g., Javadocs) may still need to be shipped or otherwise supplied to reusers, if you are not providing the source code in the package. Without the source code, reusers cannot regenerate the Javadocs.

Many open source projects eschew formal documentation in favor of simple JavaDocs, plus “documentation in the form of a test suite” or “documentation in the form of sample apps”. While test suites and sample apps are useful supplements, they are not always an effective replacement for written documentation. And, while JavaDocs are useful for reference material, they are often difficult to comprehend for those trying to get started with the code and not knowing where to begin.

Naming Conventions

Make sure that your Java code is in a package that is likely to be distinct from any others that reusers might already have. Typically, this means that the package name is based on a domain name that you control, much like the package name for Android apps themselves. Whatever you do, please do not publish your own code as android.*, unless you are contributing this code to the Android open source project, as android.* is reserved for use by Android itself.

(The author of this book would also appreciate it if you would not use com.commonsware.*)

Also, be careful about the names of your resources. While your Java code resides in its own namespace, your resources are pooled with all other resources in use by the app. As a result, if you decide to reference R.layout.main thinking that it will be your main.xml layout resource, it might actually be replaced by a main.xml resource written by the app developer. You may wish to use some sort of a prefix convention on your resource names to reduce the odds of accidental collision: