@ncalexander

Build your own browser: A Maven repository for GeckoView

Thu 10 July 2014 / tagged: android, build system, fennec, geckoview, maven, gradle

GeckoView is a project that lets you embed the Gecko rendering engine into your Android App. Slowly but surely, we’ve making this process easier. It’s now really easy to include GeckoView in your Gradle-based application, thanks to a new Maven repository hosting Nightly GeckoView builds.

GeckoView is a long-time Fennec (Firefox for Android) side-project: you can see the the GeckoView project page and the first GeckoView blog post. The first sample code, the original geckobrowser is still working too, but in the year since the initial development, progress has been slow.

I think part of the reason that progress has been slow is that it’s quite difficult to embed GeckoView into an App — at least, it’s quite tricky if you use it how it’s packaged on Mozilla’s build infrastructure [1]. Now, there’s an easier way that takes advantage of Gradle’s excellent support for Maven repositories.

A Maven repository for GeckoView

A Jenkins job, running on ci.mozilla.org, builds a new AAR (Android ARchive) library file [2]. The new job runs every night at 5AM Pacific; Nightly builds are usually kicked off between 2 and 3AM Pacific, so the artifacts should usually be fresh.

The AAR files produced are versioned appropriately [3] and then published in the Maven repository hosted at https://ci.mozilla.org/job/mozilla-central-geckoview/mozilla-central_Maven_Repository The AAR artifacts are pushed with groupId=org.mozilla.geckoview and artifactId=library; to refer to the latest AAR in Gradle, use:

repositories {
    maven {
        url 'https://ci.mozilla.org/job/mozilla-central-geckoview/mozilla-central_Maven_Repository'
    }
}

dependencies {
    compile 'com.android.support:support-v4:19.+'
    compile 'org.mozilla.geckoview:library:+'
}

That’s it; that’s all you need to build against GeckoView [4] [5]. For a worked example, keep reading.

Example: an updated geckobrowser

You can follow along with the repository at https://github.com/ncalexan/geckobrowser-gradle.

As of Android 19, the android create project tool can create Gradle projects, so let’s use it:

~/Mozilla/geckobrowser-gradle $ android create project \
  -a MainActivity -k org.mozilla.geckobrowser -t android-19 -g -p . -v 0.12
Error: Project folder '.' is not empty. Please consider using 'android update' instead.
Created directory /Users/nalexander/Mozilla/geckobrowser-gradle/src/main/java
Created directory /Users/nalexander/Mozilla/geckobrowser-gradle/src/main/java/org/mozilla/geckobrowser
Added file ./src/main/java/org/mozilla/geckobrowser/MainActivity.java
Created directory /Users/nalexander/Mozilla/geckobrowser-gradle/src/instrumentTest/java
Created directory /Users/nalexander/Mozilla/geckobrowser-gradle/src/instrumentTest/java/org/mozilla/geckobrowser
Added file ./src/instrumentTest/java/org/mozilla/geckobrowser/MainActivityTest.java
Created directory /Users/nalexander/Mozilla/geckobrowser-gradle/src/main/res
Created directory /Users/nalexander/Mozilla/geckobrowser-gradle/src/main/res/values
Added file ./src/main/res/values/strings.xml
Created directory /Users/nalexander/Mozilla/geckobrowser-gradle/src/main/res/layout
Added file ./src/main/res/layout/main.xml
Created directory /Users/nalexander/Mozilla/geckobrowser-gradle/src/main/res/drawable-xhdpi
Created directory /Users/nalexander/Mozilla/geckobrowser-gradle/src/main/res/drawable-hdpi
Created directory /Users/nalexander/Mozilla/geckobrowser-gradle/src/main/res/drawable-mdpi
Created directory /Users/nalexander/Mozilla/geckobrowser-gradle/src/main/res/drawable-ldpi
Added file ./src/main/AndroidManifest.xml
Added file ./build.gradle
Created directory /Users/nalexander/Mozilla/geckobrowser-gradle/gradle/wrapper

My new project is in directory geckobrowser-gradle and the original is in directory geckobrowser. Copy the Android resources (res/ directory) verbatim, and take MainActivity.java from the original geckobrowser; it will need some light editing:

~/Mozilla/geckobrowser-gradle $ rm -rf src/main/res && cp -R ../geckobrowser/res src/main
~/Mozilla/geckobrowser-gradle $ cp ../geckobrowser/src/com/starkravingfinkle/geckobrowser/MainActivity.java \
  src/main/java/org/mozilla/geckobrowser/MainActivity.java

We’re almost there; we just need to rename the package. Update the Java package in MainActivity.java like so:

--- a/src/main/java/org/mozilla/geckobrowser/MainActivity.java
+++ b/src/main/java/org/mozilla/geckobrowser/MainActivity.java
@@ -1,4 +1,4 @@
-package com.starkravingfinkle.geckobrowser;
+package org.mozilla.geckobrowser;

 import org.mozilla.gecko.GeckoView;
 import org.mozilla.gecko.GeckoView.Browser;

After building and pushing to device using ./gradlew build installDebug, I took the following screen capture:

Conclusion

That’s a browser — minimal but functional — built around GeckoView! And it uses "Android standard" packaging techniques: no fussing with manually managed ZIP files. I’ve worked on improving packaging Fennec and GeckoView so that things like this were at least feasible, and now that I’ve done it, I’d like to congratulate the Android Tools team for steadily improving the Android packaging story. It’s still not perfect [6], but it handles most functional requirements and is a huge improvement over the frustrating limitations of earlier iterations.

Finally, a plea: GeckoView needs consumers to drive its development. The Fennec team tries to move the project forward when possible, but without guiding lights and community involvement (other than Fennec itself, and the Fennec team), making GeckoView more functional always plays a poor second fiddle to making Fennec more awesome than it already is. But we need to bring the Open Web to more places than those where Fennec can take it, and for that, we need GeckoView, and your help.

Notes

[1]Every mozilla-central Nightly build includes GeckoView, in the form of two zip files. The first, geckoview_library.zip, contains compiled code (Java JARs) and Android resources that need to be included in the embedding App. The second, geckoview_assets.zip, contains specially compressed native code libraries (.so files) that need to be copied into the embedding App’s assets/ directory. Who likes manual dependency management? Not me!
[2]It’s not well-documented, but an assets/ directory packaged into an AAR will be merged with the embedding application’s assets, and we take advantage of this fact.
[3]The Maven version is the Gecko build id of the corresponding Nightly build; for example, 20140710071924 is a version from today.
[4]Technically, the incantation org.mozilla.geckoview:library:+ means to find the latest version of the library artifact (in this case, the appropriate AAR) in the group org.mozilla.geckoview. That’s living on the bleeding edge, to be sure. I think the current Jenkins job saves each Nightly it produces, but I’m not certain, and in any case, each AAR is roughly 35Mb, so I’m going to have start culling pretty much immediately. I’m not sure what the right way to host such a large Maven repository is, so the version scheme is likely to change in the (near) future. If you depend on a specific version, download and install it into your local Maven repository manually.
[5]I did witness a transient error downloading from the Maven repository, perhaps during the first download. The content length was mis-reported and the AAR file was valid but contained redundant data. Let me know if you see this; I have only witnessed it the one time.
[6]For example there is only patchy Gradle plugin documentation, and with the shift to Gradle, there is little support for library dependency management at the aapt level. This matters for Fennec, since we don’t use Gradle, but would like to participate in the AAR ecosystem.
Nick Alexander

About Nick Alexander

Mathematician. Mozillian. Runner. Master of Disguise.