Status Update
Comments
xa...@android.com <xa...@android.com> #2
ko...@gmail.com <ko...@gmail.com> #3
yb...@google.com <yb...@google.com> #4
xa...@google.com <xa...@google.com>
ja...@gmail.com <ja...@gmail.com> #5
MacOs Sierra 10.12.6
Android Studio 2.3.3
java version "1.8.0_51"
Java(TM) SE Runtime Environment (build 1.8.0_51-b16)
Java HotSpot(TM) 64-Bit Server VM (build 25.51-b03, mixed mode)
ja...@gmail.com <ja...@gmail.com> #6
pa...@gmail.com <pa...@gmail.com> #7
re #5: for adding the findViewById cast it's not worth to check any condition, the Java compiler generates that for you anyway, even on 26, so there's no win to omit it
re #6: similarly if you just add if (app.package.BuildConfig.DEBUG) around the debug code, javac may eliminate the dead code. If DEBUG is declared as static final boolean, javac can prove the if will never execute.
even if javac wouldn't do these, any good-standing citizen of Android runs a ProGuard on their app in release mode... which definitely clears these up ;)
ja...@gmail.com <ja...@gmail.com> #8
Your assumption that the code generation changes between debug to release mode can always be encapsulated behind a conditional are incorrect. The nature of generated code often precludes operating with a runtime library which means that debug support permeates a lot of the generated API. Duplicating the entire codepaths that the debug information propagates through needlessly clutters the processor with duplicate generation logic, clutters the generated code end users see, and puts a reliance on a tool that can't always determine unused codepaths let alone if it's even used. The conditional should be hoisted into the processor. This allows simplified generation logic, the minimal source for the end user to understand, and works regardless of post-processing tool usage.
Neither of your suggestions adequately solve either problem in a way I would be comfortable shipping to my users.
yb...@google.com <yb...@google.com> #9
is...@google.com <is...@google.com>
ja...@gmail.com <ja...@gmail.com> #10
yb...@google.com <yb...@google.com> #11
Of course it is a bit cheating because gradle plugin already adds androidx.databinding or android.databinding so we know what to check (and if both available, we crash as it should never happen).
Something from the support-annotation would cover most the cases as well but of course, a proper argument would be better.
hu...@google.com <hu...@google.com> #12
Problem #1 - Javac issues a warning for unused options
> Task :app:compileDebugJavaWithJavac
> warning: The following options were not recognized by any processor: '[applicationId, minSdkVersion, ...]'
There is currently no way to disable this specific warning (
Problem #2 - JavaCompile/Kapt task could be incorrectly out-of-date if options are unused
If unused options are changed, the JavaCompile/Kapt task will not be UP-TO-DATE, even though it shouldn’t be as the options are not used.
To address this, I'm proposing the following:
- Annotation processors declare what options they need in a META-INF file (e.g., META-INF/services/javax.annotation.processing.Processor.SupportedOptions). This contains the same information as javax.annotation.processing.AbstractProcessor#getSupportedOptions. However, it is required because the Android Gradle plugin won’t be able to make a call to AbstractProcessor#getSupportedOptions().
- The Android Gradle plugin then reads these META-INF files and passes only the options that will be used by the annotation processors.
I'll take this issue for now, but can't really promise a timeline at this point.
ja...@gmail.com <ja...@gmail.com> #13
Would setting system properties on the javac JVM (whether local or forked) be an option here?
hu...@google.com <hu...@google.com> #14
As you may be well aware, Gradle tasks need to have well-defined inputs and outputs for the build to work correctly and optimally. While passing info through side channels using a global state sounds tempting, I'm afraid that it will open doors for build flakiness and irreproducibility, with hard-to-debug errors.
ja...@gmail.com <ja...@gmail.com> #15
How about publishing a library which exposes something like
package com.android.tools.build.info;
interface AndroidBuildInfo {
static Optional<AndroidBuildInfo> get() {
Throwable failure;
try {
return Optional.of(
Class.forName("com.android.tools.build.info.AndroidBuildInfoImpl")
.getConstructor()
.newInstance());
} catch (NoClassDefFoundError ignored) {
return Optional.empty();
} catch (InvocationTargetException e) {
failure = e.getCause();
} catch (ReflectiveOperationException e) {
failure = e;
}
if (failure instanceof Error) throw (Error) failure;
if (failure instanceof RuntimeException) throw (RuntimeException) failure;
throw new RuntimeException(failure);
}
int minSdk()
String compileSdk();
boolean debuggable();
String applicationId();
// etc..
}
and then having AGP spin a classfile for AndroidBuildInfoImpl
which implements AndroidBuildInfo
and put that on the processor path. Then any processor wanting info could depend on this client library to optionally access build info.
Users of other build systems could then spin the classfile themselves to provide such info.
hu...@google.com <hu...@google.com> #16
That's still using side channels, it addresses problem #1 but not #2 in
ja...@gmail.com <ja...@gmail.com> #17
Ah, do you mean because while the generated class would be on the processor path and part of the inputs, the actual values are not exposed for Gradle to see and so any changes would not invalidate the task? I suppose a workaround for that would to be to have the values also declared as properties on the task, but that's definitely error-prone since you could forget to keep them in sync.
hu...@google.com <hu...@google.com> #18
Yes, we need to ensure anything that's passed to annotation processors is registered as an input to Gradle. On the other hand, if all of the properties are registered as inputs but some of them are unused, it could trigger unnecessary task execution (problem #2).
hu...@google.com <hu...@google.com> #19
(We'll revisit this issue in a future release, so decreasing priority to P2.)
Description
By convention, all configuration options will be prefixed with "android." to scope them in the options map.
The following list is my suggestions for what should be included:
- applicationId
- minSdkVersion
- targetSdkVersion
With the applicationId, references to `BuildConfig` can be generated to point at any of its properties (version name, code, flavor name, etc.). The minimum and target SDK versions are essential for allowing processors to change their generated code based on the supported APIs of the project in which they are being run. For example, a project with a minimum above 21 would use the Theme-overloads of Resource methods, or a target of 23 or newer would generate code that used the new permissions APIs.
[1]: