Bug 1291372 - Produce Maven repository with GeckoView Javadoc and Sources JARs. r=snorp
We use a Maven repository and the (misleadingly named!) uploadArchives
task because this is the best way to make Android Studio download and
recognize the Javadoc and sources. With this, it's automatic; with a
single AAR file, it's a nightmare of point-and-click configuration.
This patch does a bunch of Gradle hacking to make -javadoc and
-sources JARs; there's nothing special or particularly likely to break
here.
This patch also adds Proguard declarations to the :geckoview library
project. That involves moving a good part of the Proguard
configuration into mobile/android/geckoview. (I also expand upon the
existing configuration.) This should be only a re-arrangement, and
the resulting file is included in the original, so nothing should be
changed.
MozReview-Commit-ID: BGNW1v92J0k
--- a/mobile/android/config/proguard/proguard.cfg
+++ b/mobile/android/config/proguard/proguard.cfg
@@ -128,43 +128,16 @@
# This optimisation causes corrupt bytecode if we run more than two passes.
# Testing shows that running the extra passes of everything else saves us
# more than this optimisation does, so bye bye!
-optimizations !code/allocation/variable
# Keep miscellaneous targets.
-# Keep the annotation.
--keep @interface org.mozilla.gecko.annotation.JNITarget
-
-# Keep classes tagged with the annotation.
--keep @org.mozilla.gecko.annotation.JNITarget class *
-
-# Keep all members of an annotated class.
--keepclassmembers @org.mozilla.gecko.annotation.JNITarget class * {
- *;
-}
-
-# Keep annotated members of any class.
--keepclassmembers class * {
- @org.mozilla.gecko.annotation.JNITarget *;
-}
-
-# Keep classes which contain at least one annotated element. Split over two directives
-# because, according to the developer of ProGuard, "the option -keepclasseswithmembers
-# doesn't combine well with the '*' wildcard" (And, indeed, using it causes things to
-# be deleted that we want to keep.)
--keepclasseswithmembers class * {
- @org.mozilla.gecko.annotation.JNITarget <methods>;
-}
--keepclasseswithmembers class * {
- @org.mozilla.gecko.annotation.JNITarget <fields>;
-}
-
# Keep Robocop targets. TODO: Can omit these from release builds. Also, Bug 916507.
# Same formula as above...
-keep @interface org.mozilla.gecko.annotation.RobocopTarget
-keep @org.mozilla.gecko.annotation.RobocopTarget class *
-keepclassmembers class * {
@org.mozilla.gecko.annotation.RobocopTarget *;
}
@@ -173,79 +146,18 @@
}
-keepclasseswithmembers class * {
@org.mozilla.gecko.annotation.RobocopTarget <methods>;
}
-keepclasseswithmembers class * {
@org.mozilla.gecko.annotation.RobocopTarget <fields>;
}
-# keep Reflection targets
--keep @interface org.mozilla.gecko.annotation.ReflectionTarget
--keep @org.mozilla.gecko.annotation.ReflectionTarget class *
--keepclassmembers class * {
- @org.mozilla.gecko.annotation.ReflectionTarget *;
-}
--keepclassmembers @org.mozilla.gecko.annotation.ReflectionTarget class * {
- *;
-}
--keepclasseswithmembers class * {
- @org.mozilla.gecko.annotation.ReflectionTarget <methods>;
-}
--keepclasseswithmembers class * {
- @org.mozilla.gecko.annotation.ReflectionTarget <fields>;
-}
-
-# Keep WebRTC targets.
--keep @interface org.mozilla.gecko.annotation.WebRTCJNITarget
--keep @org.mozilla.gecko.annotation.WebRTCJNITarget class *
--keepclassmembers class * {
- @org.mozilla.gecko.annotation.WebRTCJNITarget *;
-}
--keepclassmembers @org.mozilla.gecko.annotation.WebRTCJNITarget class * {
- *;
-}
--keepclasseswithmembers class * {
- @org.mozilla.gecko.annotation.WebRTCJNITarget <methods>;
-}
--keepclasseswithmembers class * {
- @org.mozilla.gecko.annotation.WebRTCJNITarget <fields>;
-}
-
-# Keep generator-targeted entry points.
--keep @interface org.mozilla.gecko.annotation.WrapForJNI
--keep @org.mozilla.gecko.annotation.WrapForJNI class *
--keepclassmembers class * {
- @org.mozilla.gecko.annotation.WrapForJNI *;
-}
--keepclasseswithmembers class * {
- @org.mozilla.gecko.annotation.WrapForJNI <methods>;
-}
--keepclasseswithmembers class * {
- @org.mozilla.gecko.annotation.WrapForJNI <fields>;
-}
-
-# Keep all members of an annotated class.
--keepclassmembers @org.mozilla.gecko.annotation.WrapForJNI class * {
- *;
-}
-
-keep class **.R$*
-# Keep classes, and all their contents, compiled before annotation.RobocopTarget.
--keep class org.mozilla.gecko.AppConstants {
- *;
-}
--keep class org.mozilla.gecko.AppConstants$Versions {
- *;
-}
--keep class org.mozilla.gecko.SysInfo {
- *;
-}
-
# Keep all interfaces that might be dynamically required by Java Addons.
-keep class org.mozilla.javaaddons.* {
*;
}
-keep class org.mozilla.javaaddons.*$* {
*;
}
@@ -264,8 +176,10 @@
-include "adjust-keeps.cfg"
-include "leakcanary-keeps.cfg"
-include "appcompat-v7-keeps.cfg"
-include "proguard-android.cfg"
+
+-include "../../geckoview/proguard-rules.txt"
--- a/mobile/android/geckoview/build.gradle
+++ b/mobile/android/geckoview/build.gradle
@@ -1,20 +1,28 @@
buildDir "${topobjdir}/gradle/build/mobile/android/geckoview"
apply plugin: 'android-sdk-manager' // Must come before 'com.android.*'.
apply plugin: 'com.android.library'
+def VERSION_NAME = '0.0.1'
+
android {
compileSdkVersion 23
buildToolsVersion mozconfig.substs.ANDROID_BUILD_TOOLS_VERSION
defaultConfig {
+ // TODO: version GeckoView explicitly. We'd like to avoid
+ // mozconfig.substs.ANDROID_VERSION_CODE, which won't be intuitive to
+ // consumer (and advances very quickly on pre-release channels).
+ versionCode 1
+ versionName VERSION_NAME
targetSdkVersion 23
minSdkVersion 15
+ consumerProguardFiles 'proguard-rules.txt'
}
buildTypes {
withGeckoBinaries {
initWith release
}
withoutGeckoBinaries { // For clarity and consistency throughout the tree.
initWith release
@@ -78,9 +86,91 @@ android.libraryVariants.all { variant ->
// It would be most natural for :geckoview to always include the Gecko
// binaries, but that's difficult; see the notes in
// mobile/android/gradle/with_gecko_binaries.gradle. Instead :app uses
// :geckoview:release and handles it's own Gecko binary inclusion.
if (buildType.equals('withGeckoBinaries')) {
configureVariantWithGeckoBinaries(variant)
}
+
+ // Javadoc and Sources JAR configuration cribbed from
+ // https://github.com/mapbox/mapbox-gl-native/blob/d169ea55c1cfa85cd8bf19f94c5f023569f71810/platform/android/MapboxGLAndroidSDK/build.gradle#L85
+ // informed by
+ // https://code.tutsplus.com/tutorials/creating-and-publishing-an-android-library--cms-24582,
+ // and amended from numerous Stackoverflow posts.
+ def name = variant.name
+ def javadoc = task "javadoc${name.capitalize()}"(type: Javadoc) {
+ description = "Generate Javadoc for build variant $name"
+ failOnError = false
+ destinationDir = new File(destinationDir, variant.baseName)
+ source = files(variant.javaCompile.source)
+ classpath = files(variant.javaCompile.classpath.files) + files(android.bootClasspath)
+ options.windowTitle("Mozilla GeckoView Android API $VERSION_NAME Reference")
+ options.docTitle("Mozilla GeckoView Android API $VERSION_NAME")
+ options.header("Mozilla GeckoView Android API $VERSION_NAME Reference")
+ options.bottom("© 2016 Mozilla. All rights reserved.")
+ options.links("http://docs.oracle.com/javase/7/docs/api/")
+ options.linksOffline("http://d.android.com/reference/", "$System.env.ANDROID_HOME/docs/reference")
+ // TODO: options.overview("src/main/java/overview.html")
+ options.group("Mozilla GeckoView", "org.mozilla.gecko*") // TODO: narrow this down.
+ exclude '**/R.java', '**/BuildConfig.java', 'com/googlecode/**'
+ }
+
+ task "javadocJar${name.capitalize()}"(type: Jar, dependsOn: javadoc) {
+ classifier = 'javadoc'
+ from javadoc.destinationDir
+ }
+
+ task "sourcesJar${name.capitalize()}"(type: Jar) {
+ classifier 'sources'
+ description = "Generate Javadoc for build variant $name"
+ destinationDir = new File(destinationDir, variant.baseName)
+ from files(variant.javaCompile.source)
+ }
}
+
+apply plugin: 'maven'
+
+uploadArchives {
+ repositories.mavenDeployer {
+ pom.groupId = 'org.mozilla'
+ pom.artifactId = 'geckoview'
+ pom.version = VERSION_NAME
+ pom.project {
+ licenses {
+ license {
+ name 'The Mozilla Public License, v. 2.0'
+ url 'http://mozilla.org/MPL/2.0/'
+ distribution 'repo'
+ }
+ }
+ }
+ repository(url: "file://${project.buildDir}/maven")
+ }
+}
+
+// This is all related to the withGeckoBinaries approach; see
+// mobile/android/gradle/with_gecko_binaries.gradle.
+afterEvaluate {
+ // The bundle tasks are only present when the particular configuration is
+ // being built, so this task might not exist. (This is due to the way the
+ // Android Gradle plugin defines things during configuration.)
+ def bundleWithGeckoBinaries = tasks.findByName('bundleWithGeckoBinaries')
+ if (!bundleWithGeckoBinaries) {
+ return
+ }
+
+ // Remove default configuration, which is the release configuration, when
+ // we're actually building withGeckoBinaries. This makes `gradle install`
+ // install the withGeckoBinaries artifacts, not the release artifacts (which
+ // are withoutGeckoBinaries and not suitable for distribution.)
+ def Configuration archivesConfig = project.getConfigurations().getByName('archives')
+ archivesConfig.artifacts.removeAll { it.extension.equals('aar') }
+
+ artifacts {
+ // Instead of default (release) configuration, publish one with Gecko binaries.
+ archives bundleWithGeckoBinaries
+ // Javadoc and sources for developer ergononomics.
+ archives javadocJarWithGeckoBinaries
+ archives sourcesJarWithGeckoBinaries
+ }
+}
new file mode 100644
--- /dev/null
+++ b/mobile/android/geckoview/proguard-rules.txt
@@ -0,0 +1,175 @@
+# Modified from https://robotsandpencils.com/blog/use-proguard-android-library/.
+
+# Preserve all annotations.
+
+-keepattributes *Annotation*
+
+# Preserve all public classes, and their public and protected fields and
+# methods.
+
+-keep public class * {
+ public protected *;
+}
+
+# Preserve all .class method names.
+
+-keepclassmembernames class * {
+ java.lang.Class class$(java.lang.String);
+ java.lang.Class class$(java.lang.String, boolean);
+}
+
+# Preserve all native method names and the names of their classes.
+
+-keepclasseswithmembernames class * {
+ native <methods>;
+}
+
+# Preserve the special static methods that are required in all enumeration
+# classes.
+
+-keepclassmembers class * extends java.lang.Enum {
+ public static **[] values();
+ public static ** valueOf(java.lang.String);
+}
+
+# Explicitly preserve all serialization members. The Serializable interface
+# is only a marker interface, so it wouldn't save them.
+# You can comment this out if your library doesn't use serialization.
+# If your code contains serializable classes that have to be backward
+# compatible, please refer to the manual.
+
+-keepclassmembers class * implements java.io.Serializable {
+ static final long serialVersionUID;
+ static final java.io.ObjectStreamField[] serialPersistentFields;
+ private void writeObject(java.io.ObjectOutputStream);
+ private void readObject(java.io.ObjectInputStream);
+ java.lang.Object writeReplace();
+ java.lang.Object readResolve();
+}
+
+# Preserve all View implementations and their special context constructors.
+
+-keep public class * extends android.view.View {
+ public <init>(android.content.Context);
+ public <init>(android.content.Context, android.util.AttributeSet);
+ public <init>(android.content.Context, android.util.AttributeSet, int);
+ public void set*(...);
+}
+
+# Keep setters in Views so that animations can still work.
+# See http://proguard.sourceforge.net/manual/examples.html#beans
+# From tools/proguard/proguard-android.txt.
+-keepclassmembers public class * extends android.view.View {
+ void set*(***);
+ *** get*();
+}
+
+# Preserve all classes that have special context constructors, and the
+# constructors themselves.
+
+-keepclasseswithmembers class * {
+ public <init>(android.content.Context, android.util.AttributeSet);
+}
+
+# Preserve the special fields of all Parcelable implementations.
+
+-keepclassmembers class * implements android.os.Parcelable {
+ static android.os.Parcelable$Creator CREATOR;
+}
+
+# Preserve static fields of inner classes of R classes that might be accessed
+# through introspection.
+
+-keepclassmembers class **.R$* {
+ public static <fields>;
+}
+
+# GeckoView specific rules.
+
+# Keep classes, and all their contents, compiled before annotation.*.
+-keep class org.mozilla.gecko.AppConstants {
+ *;
+}
+-keep class org.mozilla.gecko.AppConstants$Versions {
+ *;
+}
+-keep class org.mozilla.gecko.SysInfo {
+ *;
+}
+
+# Keep the annotation.
+-keep @interface org.mozilla.gecko.annotation.JNITarget
+
+# Keep classes tagged with the annotation.
+-keep @org.mozilla.gecko.annotation.JNITarget class *
+
+# Keep all members of an annotated class.
+-keepclassmembers @org.mozilla.gecko.annotation.JNITarget class * {
+ *;
+}
+
+# Keep annotated members of any class.
+-keepclassmembers class * {
+ @org.mozilla.gecko.annotation.JNITarget *;
+}
+
+# Keep classes which contain at least one annotated element. Split over two directives
+# because, according to the developer of ProGuard, "the option -keepclasseswithmembers
+# doesn't combine well with the '*' wildcard" (And, indeed, using it causes things to
+# be deleted that we want to keep.)
+-keepclasseswithmembers class * {
+ @org.mozilla.gecko.annotation.JNITarget <methods>;
+}
+-keepclasseswithmembers class * {
+ @org.mozilla.gecko.annotation.JNITarget <fields>;
+}
+
+# Keep WebRTC targets.
+-keep @interface org.mozilla.gecko.annotation.WebRTCJNITarget
+-keep @org.mozilla.gecko.annotation.WebRTCJNITarget class *
+-keepclassmembers class * {
+ @org.mozilla.gecko.annotation.WebRTCJNITarget *;
+}
+-keepclassmembers @org.mozilla.gecko.annotation.WebRTCJNITarget class * {
+ *;
+}
+-keepclasseswithmembers class * {
+ @org.mozilla.gecko.annotation.WebRTCJNITarget <methods>;
+}
+-keepclasseswithmembers class * {
+ @org.mozilla.gecko.annotation.WebRTCJNITarget <fields>;
+}
+
+# Keep generator-targeted entry points.
+-keep @interface org.mozilla.gecko.annotation.WrapForJNI
+-keep @org.mozilla.gecko.annotation.WrapForJNI class *
+-keepclassmembers class * {
+ @org.mozilla.gecko.annotation.WrapForJNI *;
+}
+-keepclasseswithmembers class * {
+ @org.mozilla.gecko.annotation.WrapForJNI <methods>;
+}
+-keepclasseswithmembers class * {
+ @org.mozilla.gecko.annotation.WrapForJNI <fields>;
+}
+
+# Keep all members of an annotated class.
+-keepclassmembers @org.mozilla.gecko.annotation.WrapForJNI class * {
+ *;
+}
+
+# Keep Reflection targets.
+-keep @interface org.mozilla.gecko.annotation.ReflectionTarget
+-keep @org.mozilla.gecko.annotation.ReflectionTarget class *
+-keepclassmembers class * {
+ @org.mozilla.gecko.annotation.ReflectionTarget *;
+}
+-keepclassmembers @org.mozilla.gecko.annotation.ReflectionTarget class * {
+ *;
+}
+-keepclasseswithmembers class * {
+ @org.mozilla.gecko.annotation.ReflectionTarget <methods>;
+}
+-keepclasseswithmembers class * {
+ @org.mozilla.gecko.annotation.ReflectionTarget <fields>;
+}
--- a/mobile/android/geckoview_example/src/main/java/org/mozilla/geckoview_example/GeckoViewActivity.java
+++ b/mobile/android/geckoview_example/src/main/java/org/mozilla/geckoview_example/GeckoViewActivity.java
@@ -7,29 +7,35 @@ package org.mozilla.geckoview_example;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.os.Bundle;
import android.util.Log;
import android.widget.Toast;
+import org.mozilla.gecko.BaseGeckoInterface;
import org.mozilla.gecko.GeckoProfile;
import org.mozilla.gecko.GeckoThread;
import org.mozilla.gecko.GeckoView;
import org.mozilla.gecko.PrefsHelper;
+import static org.mozilla.gecko.GeckoView.setGeckoInterface;
+
public class GeckoViewActivity extends Activity {
private static final String LOGTAG = "GeckoViewActivity";
GeckoView mGeckoView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+
+ setGeckoInterface(new BaseGeckoInterface(getApplicationContext()));
+
setContentView(R.layout.geckoview_activity);
mGeckoView = (GeckoView) findViewById(R.id.gecko_view);
mGeckoView.setChromeDelegate(new MyGeckoViewChrome());
mGeckoView.setContentDelegate(new MyGeckoViewContent());
}
@Override
--- a/taskcluster/ci/build/android.yml
+++ b/taskcluster/ci/build/android.yml
@@ -111,19 +111,19 @@ android-api-15-gradle/opt:
worker-type: aws-provisioner-v1/gecko-{level}-b-android
worker:
implementation: docker-worker
max-run-time: 7200
env:
# Bug 1292762 - Set GRADLE_USER_HOME to avoid sdk-manager-plugin intermittent
GRADLE_USER_HOME: /home/worker/workspace/build/src/dotgradle
artifacts:
- - name: public/android/geckoview.aar
- path: /home/worker/workspace/build/src/obj-firefox/gradle/build/mobile/android/geckoview/outputs/aar/geckoview-withGeckoBinaries.aar
- type: file
+ - name: public/android/maven
+ path: /home/worker/workspace/build/src/obj-firefox/gradle/build/mobile/android/geckoview/maven/
+ type: directory
- name: public/android/geckoview_example.apk
path: /home/worker/workspace/build/src/obj-firefox/gradle/build/mobile/android/geckoview_example/outputs/apk/geckoview_example-withGeckoBinaries.apk
type: file
- name: public/build
path: /home/worker/artifacts/
type: directory
run:
using: mozharness
--- a/testing/mozharness/configs/builds/releng_sub_android_configs/64_api_15_gradle.py
+++ b/testing/mozharness/configs/builds/releng_sub_android_configs/64_api_15_gradle.py
@@ -7,11 +7,12 @@ config = {
'multi_locale_config_platform': 'android',
# It's not obvious, but postflight_build is after packaging, so the Gecko
# binaries are in the object directory, ready to be packaged into the
# GeckoView AAR.
'postflight_build_mach_commands': [
['gradle',
'geckoview:assembleWithGeckoBinaries',
'geckoview_example:assembleWithGeckoBinaries',
+ 'uploadArchives',
],
],
}