Upgrading to Jetpack Compose Alpha 12 causes errors on setContent - android

I upgraded to Jetpack Compose 1.0.0-alpha12 and started to run into issues.
Firstly, the setContent method I was using showed as deprecated.
From the Alpha 12 release notes, I noticed that it said:
ComponentActivity.setContent has moved to androidx.activity.compose.setContent in the androidx.activity:activity-compose module. (Icf416)
So I removed my import androidx.compose.ui.platform.setContent and switched it to import androidx.activity.compose.setContent, which removed the deprecation.
However, I then got an error that says:
w: Flag is not supported by this version of the compiler: -Xallow-jvm-ir-dependencies
w: ATTENTION!
This build uses unsafe internal compiler arguments:
-XXLanguage:+NonParenthesizedAnnotationsOnFunctionalTypes
This mode is not recommended for production use,
as no stability/compatibility guarantees are given on
compiler or generated code. Use it at your own risk!
e: Classes compiled by an unstable version of the Kotlin compiler were found in dependencies.
Remove them from the classpath or use '-Xallow-unstable-dependencies' to suppress errors
e: /[my path]/MainActivity.kt: (39, 9): Class 'androidx.activity.compose.ComponentActivityKt' is
compiled by an unstable version of the Kotlin compiler and cannot be loaded by this compiler
And again, I was able to work around that by changing my build.gradle file to have:
kotlinOptions {
jvmTarget = '1.8'
useIR = true
// I added this line
freeCompilerArgs += "-Xallow-unstable-dependencies"
}
While that let me compile my app, I now get the following exception at runtime:
java.lang.NoSuchMethodError: No static method setContent(
Landroidx/activity/ComponentActivity;Landroidx/compose/runtime/Com
positionContext;Lkotlin/jvm/functions/Function2;)V in class
Landroidx/activity/compose/ComponentActivityKt; or its super classes
(declaration of 'androidx.activity.compose.ComponentActivityKt' appears in [my apk]
How can I fix this and upgrade my app to Jetpack Compose 1.0.0-alpha12?

As per this issue, this issue is related to the new androidx.activity:activity-compose:1.3.0-alpha01 artifact.
From that issue:
Activity 1.3.0-alpha02 has been released and fixes this issue.
Apps using Compose alpha12 and specifically artifacts like androidx.compose.ui:ui-test-junit4:1.0.0-alpha12 that internally use setContent should add the activity-compose:1.3.0-alpha02 dependency to their dependencies block to ensure that the 1.3.0-alpha01 artifact is not used
So to fix your app, you should:
Remove the freeCompilerArgs += "-Xallow-unstable-dependencies" line from the build.gradle file (as it is no longer needed)
Add a specific dependency on Activity Compose 1.3.0-alpha02:
implementation 'androidx.activity:activity-compose:1.3.0-alpha02'
By adding that dependency, any direct usages of setContent as well as internal usages by androidx.compose.ui:ui-tooling:1.0.0-alpha12 or androidx.compose.ui:ui-test-junit4:1.0.0-alpha12 will use the fixed Activity Compose 1.3.0-alpha02 release.

With Activity 1.3.0-alpha02, setContent is working, but got another error.
Execution failed for task ':app:mergeDebugJavaResource'.
> A failure occurred while executing com.android.build.gradle.internal.tasks.MergeJavaResWorkAction
> 2 files found with path 'META-INF/AL2.0' from inputs:
Had to use the workaround to make it built
packagingOptions {
exclude 'META-INF/AL2.0'
exclude 'META-INF/LGPL2.1'
}
And still have the warning
Flag is not supported by this version of the compiler: -Xallow-jvm-ir-dependencies

Related

Jetpack Compose. Preview is not available

There is a project with compose.
There are a 2 modules in the project: core and othergames (core is depends on othergames).
I can successfully see a previews (annotated with #Preview) of compose views in core module. But when I try to see previews in othergames, preview can't be shown with error:
The following classes could not be instantiated:
- androidx.compose.ui.tooling.ComposeViewAdapter (Open Class, Show Exception, Clear Cache)
Tip: Use View.isInEditMode() in your custom views to skip code or show sample data when shown in the IDE. If this is an unexpected error you can also try to build the project, then manually refresh the layout.
There are details:
java.lang.NoSuchFieldError: view_tree_saved_state_registry_owner
at androidx.savedstate.ViewTreeSavedStateRegistryOwner.set(ViewTreeSavedStateRegistryOwner.java:53)
at androidx.compose.ui.tooling.ComposeViewAdapter.init(ComposeViewAdapter.kt:666)
at androidx.compose.ui.tooling.ComposeViewAdapter.<init>(ComposeViewAdapter.kt:217)
at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:490)
at org.jetbrains.android.uipreview.ViewLoader.createNewInstance(ViewLoader.java:373)
at org.jetbrains.android.uipreview.ViewLoader.loadClass(ViewLoader.java:192)
at org.jetbrains.android.uipreview.ViewLoader.loadView(ViewLoader.java:150)
at com.android.tools.idea.rendering.LayoutlibCallbackImpl.loadView(LayoutlibCallbackImpl.java:302)
at android.view.BridgeInflater.loadCustomView(BridgeInflater.java:417)
at android.view.BridgeInflater.loadCustomView(BridgeInflater.java:428)
at android.view.BridgeInflater.createViewFromTag(BridgeInflater.java:332)
at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:965)
at android.view.LayoutInflater.inflate(LayoutInflater.java:663)
at android.view.LayoutInflater.inflate(LayoutInflater.java:505)
at com.android.layoutlib.bridge.impl.RenderSessionImpl.inflate(RenderSessionImpl.java:361)
at com.android.layoutlib.bridge.Bridge.createSession(Bridge.java:436)
at com.android.tools.idea.layoutlib.LayoutLibrary.createSession(LayoutLibrary.java:121)
at com.android.tools.idea.rendering.RenderTask.createRenderSession(RenderTask.java:727)
at com.android.tools.idea.rendering.RenderTask.lambda$inflate$7(RenderTask.java:883)
at com.android.tools.idea.rendering.RenderExecutor$runAsyncActionWithTimeout$2.run(RenderExecutor.kt:187)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
at java.base/java.lang.Thread.run(Thread.java:829)
Both of modules has a equal compose dependencies and settings in build.gradle files:
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = '1.8'
useIR = true
}
buildFeatures {
compose true
}
composeOptions {
kotlinCompilerExtensionVersion '1.2.0-alpha03'
}
And:
dependencies {
...
implementation "androidx.compose.ui:ui:1.2.0-alpha03"
implementation "androidx.compose.ui:ui-tooling:1.2.0-alpha03"
implementation "androidx.compose.ui:ui-tooling-preview:1.2.0-alpha03"
implementation "androidx.compose.foundation:foundation:1.2.0-alpha03"
implementation "androidx.compose.foundation:foundation-layout:1.2.0-alpha03"
implementation "androidx.compose.material:material:1.2.0-alpha03"
implementation "androidx.compose.material:material-icons-core:1.2.0-alpha03"
implementation "androidx.compose.material:material-icons-extended:1.2.0-alpha03"
implementation "androidx.compose.animation:animation:1.2.0-alpha03"
implementation "androidx.compose.animation:animation-core:1.2.0-alpha03"
implementation "androidx.compose.animation:animation-graphics:1.2.0-alpha03"
implementation "androidx.compose.runtime:runtime-livedata:1.2.0-alpha03"
implementation "androidx.compose.compiler:compiler:1.2.0-alpha03"
...
Why I can't see previews in othergames module? How to solve it?
I found a solution to fix it. In module where previews broke I added library which I removed recently:
implementation 'androidx.appcompat:appcompat:1.4.1'
Once I did it, previews appeared again. I not sure this library is real reason, because core module doesn't contains this library, but still show preview.
UPDATE:
Time passed and I ran into this problem again. Now it is not solved by adding the library I mentioned above. I still don't know what to do.
Came across the exact issue earlier. Make sure everything is up to date, this includes:
Android Studio ( Help > Check for updates)
Jetpack Compose (project level build)
Kotlin (project level build)
Other than that, the compose-tooling dependency should have the same version as that of Compose itself.
Here's what solved my issue
#Preview(showSystemUi = true, showBackground = true) // Apparently, adding these two lines seems to do the magic here
#Composable
fun MyComposable(){
...
}
Well, that should be pretty much it.
Have a look at Studio BumbleBee "Render Problem" For Compose Preview
Whenever you see a "try to build the project" error, always check the gradle implementations first.
Then, move on to whether your version numbers are correct.
Alpha versions aren't always the best choices.
So, if you can't find an error in the implementations, roll back any error associated implementation to it's previous stable release.
Then check again.
Also, maybe try and create a new android studio project and check if the core implementations in both the new and your current are similar or, at least look ok for the common ones.
If they look ok, add a comment besides all the implementations that look ok. Then focus on the other implementations.
Now, assuming your error is the same, i.e. a combination of try to build the project and is associated with compose, check all your ui based implementations and, your jetpack compose implementations if you are using those. Hope it helps.

Custom lint checks stopped running for multi-module Android project after upgrading to Android Gradle Plugin 4.2.2

Last year we successfully implemented some custom lint rules for our multi-module Android project by following https://proandroiddev.com/implementing-your-first-android-lint-rule-6e572383b292. At some point the lint rules stopped being applied, which I discovered by chance. By using git bisect on my repository, I was able to determine that the rules stopped being applied in a commit which upgraded the following:
Gradle in gradle-wrapper.properties: distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-all.zip => gradle-6.7.1-all.zip
Android Gradle plugin in our top-level build.gradle: classpath "com.android.tools.build:gradle:4.1.3"' => gradle:4.2.2
Someone asked a similarly worded question 3 years ago but in their case they did not isolate a potential cause as the upgrade of Gradle or Android Gradle plugin.
Update 12/29/2021
I figured out that this has to do with multi-module projects. I compared the call stack that calls my custom lint Detector.GradleScanner and discovered that it changed from Android Gradle Plugin 4.1.3 to 4.2.2:
com.android.tools.build:gradle:4.1.3
at com.locuslabs.lintrules.GradleLibraryNonStableVersionDetector.checkDslPropertyAssignment(GradleLibraryNonStableVersionDetector.kt:22)
...
at com.android.tools.lint.client.api.LintDriver.checkBuildScripts(LintDriver.kt:1203)
at com.android.tools.lint.client.api.LintDriver.runFileDetectors(LintDriver.kt:1151)
at com.android.tools.lint.client.api.LintDriver.checkProject(LintDriver.kt:926)
at com.android.tools.lint.client.api.LintDriver.analyze(LintDriver.kt:446)
at com.android.tools.lint.LintCliClient.run(LintCliClient.kt:256)
at com.android.tools.lint.LintCliClient.run(LintCliClient.kt:237)
at com.android.tools.lint.gradle.LintGradleClient.run(LintGradleClient.kt:255)
at com.android.tools.lint.gradle.LintGradleExecution.runLint(LintGradleExecution.kt:259)
at com.android.tools.lint.gradle.LintGradleExecution.lintAllVariants(LintGradleExecution.kt:318)
at com.android.tools.lint.gradle.LintGradleExecution.analyze(LintGradleExecution.kt:68)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:64)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:564)
at com.android.tools.lint.gradle.api.ReflectiveLintRunner.runLint(ReflectiveLintRunner.kt:38)
at com.android.build.gradle.tasks.LintBaseTask.runLint(LintBaseTask.java:117)
at com.android.build.gradle.tasks.LintGlobalTask.lint(LintGlobalTask.java:51)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:64)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:564)
at org.gradle.internal.reflect.JavaMethod.invoke(JavaMethod.java:104)
...
com.android.tools.build:gradle:4.2.2
at com.locuslabs.lintrules.GradleLibraryNonStableVersionDetector.checkDslPropertyAssignment(GradleLibraryNonStableVersionDetector.kt:22)
...
at com.android.tools.lint.client.api.LintDriver$checkBuildScripts$2.run(LintDriver.kt:1490)
at com.android.tools.lint.client.api.LintClient.runReadAction(LintClient.kt:1780)
at com.android.tools.lint.client.api.LintDriver$LintClientWrapper.runReadAction(LintDriver.kt:2634)
at com.android.tools.lint.client.api.LintDriver.checkBuildScripts(LintDriver.kt:1483)
at com.android.tools.lint.client.api.LintDriver.runFileDetectors(LintDriver.kt:1401)
at com.android.tools.lint.client.api.LintDriver.checkProject(LintDriver.kt:1151)
at com.android.tools.lint.client.api.LintDriver.checkProjectRoot(LintDriver.kt:628)
at com.android.tools.lint.client.api.LintDriver.access$checkProjectRoot(LintDriver.kt:153)
at com.android.tools.lint.client.api.LintDriver$analyzeOnly$1.invoke(LintDriver.kt:442)
at com.android.tools.lint.client.api.LintDriver$analyzeOnly$1.invoke(LintDriver.kt:435)
at com.android.tools.lint.client.api.LintDriver.doAnalyze(LintDriver.kt:502)
at com.android.tools.lint.client.api.LintDriver.analyzeOnly(LintDriver.kt:434)
at com.android.tools.lint.LintCliClient$analyzeOnly$1.invoke(LintCliClient.kt:241)
at com.android.tools.lint.LintCliClient$analyzeOnly$1.invoke(LintCliClient.kt:241)
at com.android.tools.lint.LintCliClient.run(LintCliClient.kt:283)
at com.android.tools.lint.LintCliClient.run$default(LintCliClient.kt:266)
at com.android.tools.lint.LintCliClient.analyzeOnly(LintCliClient.kt:241)
at com.android.tools.lint.Main.run(Main.java:1536)
at com.android.tools.lint.Main.run(Main.java:269)
...
So the analyze() function was changed to start calling a new function checkProjectRoot(). I investigated when the function checkProjectRoot() was introduced by going though the Android Gradle Plugin source code. The command git log -S checkProjectRoot indicates the following commit introduced checkProjectRoot() which implies that multi-module analysis changed:
base[mirror-goog-studio-main]10:06:10 git log -S checkProjectRoot
commit 1d01e75bf984568ecdf198cd35bfe05c8b0cce9f
Author: Tor Norbye <tnorbye#google.com>
Date: Tue Jan 19 16:18:19 2021 -0800
178514993: Support module-independent analysis in Lint
This CL adds support into lint for "provisional reporting"; this is a
big architectural change which is key to significantly speeding up
the performance (and incrementality) of lint in Gradle.
The key idea is that, for lint embedding clients which support it such
as Gradle, modules are analyzed one at a time, independently (and
possibly in parallel), without access to sources from any upstream
dependencies. In some cases that means they can't conclusively report
issues (for example, if they depend on the consuming module's
minSdkVersion), but the detectors record enough state such that in a
merging phase (reporting), they can look at their previously computed
results and map it into definite warnings.
This requires many detectors to be updated to explicitly handle this new
mode. There are a handful of typical scenarios where a detector needs to
be updated: accessing the minSdkVersion of the consuming module, or
depending on the type of the consuming mode (e.g. is it also a library?
or an Android module?).
To simplify this, most lint checks can simply pass in one of a number of
built-in constraints, e.g.
context.report(incident, minSdkAtLeast(minSdk))
There are several mechanisms included to help catch detectors that need
to be updated. First, various lint APIs are not valid to be called when
in analysis rather than reporting mode, and if a detector calls them,
lint will emit a warning message.
Private.java: Error: The lint detector
com.android.tools.lint.checks.PrivateResourceDetector
called context.getMainProject() during module analysis.
This does not work correctly when running in Lint Unit Tests.
In particular, there may be false positives or false negatives
[...]
Second, there's a new TestMode for lint's unit tests which causes all
unit tests to be analyzed both with and without module-independent
analysis. To catch common problems, in addition to running the
infrastructure with module-independent analysis enabled and in separate
and analysis phases, it also varies the minSdkVersion between the two
phases to ensure that the lint checks aren't just basing their analysis
on the module's minSdkVersion.
NOTE: This CL only adds support for module-independent analysis in lint
itself, and the detectors, and the unit testing infrastructure. It does
not hook this up to for example AGP, which will be done separately.
Test: Existing
Bug: 178514993
Change-Id: Iffa25707792e416eab3ce446c1f8d9d8cc830295
Does anyone know what changes are needed to make custom lint rules apply to all modules of a project, not just the top-level? Currently, I've implemented my rule as follows:
internal const val PRIORITY = 10
#Suppress("UnstableApiUsage")
class GradleLibraryNonStableVersionDetector : Detector(), Detector.GradleScanner {
override fun checkDslPropertyAssignment(
context: GradleContext,
property: String,
value: String,
parent: String,
parentParent: String?,
propertyCookie: Any,
valueCookie: Any,
statementCookie: Any
) {
super.checkDslPropertyAssignment(context, property, value, parent, parentParent, propertyCookie, valueCookie, statementCookie)
if (property == "implementation"
&& (value.contains("-alpha")
|| value.contains("-beta")
|| value.contains("-rc"))) {
context.report(ISSUE,
statementCookie, context.getLocation(statementCookie),
"Use only stable versions of the library")
}
}
companion object {
#JvmField
val ISSUE: Issue = Issue.create("NonStableLibraryVersion",
"Marks usage of unstable version of dependency library.",
"It's not recommended to use alpha, beta or release candidate library versions in production",
CORRECTNESS, PRIORITY, Severity.ERROR,
Implementation(GradleLibraryNonStableVersionDetector::class.java,
Scope.GRADLE_SCOPE))
}
}
And I expect when I call the lint tool as follows, it should apply to all build.gradle files across all modules:
./gradlew -Pci --console=plain :sdk:lint -PbuildDir=lint
Update 1/7/2022
I reported a similar issue on the Google Sample project for lint rules.

What is `encode()` function detected in JaCoCo coverage report (for Kolin)?

Recently I upgrade my gradle from 6.5.1 to 7.0 i.e.
distributionUrl=https\://services.gradle.org/distributions/gradle-7.0-all.zip
After the upgrade, I notice my test coverage dropped.
After investigation, I found out that in Gradle 6.5.1, my JaCoCo test coverage report shows some of my class has an encode() function, but it no longer exists in Gradle 7.0.
I dig out the simplest example below. The code is as below
In Gradle 6.5, my JaCoCo report is as below (notice there's an additional encode() function.
However, in Gradle 7.0, my JaCoCo report is as below
Because of this missing covered function, hence my coverage dropped. Nonetheless, it looks like in Gradle 7.0, that is more correct, as my real code doesn't have encode().
I'm just trying to understand where encode() function is there in the first place, and why it is no longer in Gradle 7.0? And is it correct that my assumption that Gradle 7.0 result is correct?
Different versions of Gradle come with different values of jacoco.toolVersion which you also can change in your build.gradle, and which controls version of JaCoCo to use.
Gradle 6.5 by default uses JaCoCo 0.8.5, and starting from Gradle 6.7 default is 0.8.6.
And here is a list of changes in JaCoCo version 0.8.6 - https://www.jacoco.org/jacoco/trunk/doc/changes.html
Most likely your interface ContextData contains method encode with default implementation.
JVM supports default methods in interfaces starting from version 8, however Kotlin supports compilation into bytecode of version 6. To do so Kotlin compiler does a trick for such methods - it generates method in classes implementing this interface that merely delegates execution to default implementation:
for the following Example.kt
interface ContextData {
fun encode() = { /* something */ }
}
data class SearchRefinementModalOpenData(
val userAction: String?
) : ContextData
execution of
kotlin-compiler-1.4.32/bin/kotlinc Example.kt
javap -v -p SearchRefinementModalOpenData.class
shows following bytecode
public final class SearchRefinementModalOpenData implements ContextData
{
public kotlin.jvm.functions.Function0<kotlin.Unit> encode();
descriptor: ()Lkotlin/jvm/functions/Function0;
flags: (0x0001) ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: invokestatic #29 // Method ContextData$DefaultImpls.encode:(LContextData;)Lkotlin/jvm/functions/Function0;
4: areturn
JaCoCo starting from version 0.8.6 filters out such methods since they are compiler artifacts and not presented in original source code.
It looks like you are using kotlinx.Serialization.
That generates a few encodeToString and similar functions for your objects. I guess Gradle 7 now ignores those?

How to exclude explicitApi warnings for test classes in Kotlin?

I have Android library module with enabled explicitApi kotlin feature in gradle
android {
kotlinOptions {
freeCompilerArgs += '-Xexplicit-api=warning'
}
}
Everything is fine, but the problem is that warnings are also reported for test classes in packages src/test and src/androidTest.
How to exclude test classes from explicit-api control?
Thanks
As far as I know, you can't! I was thinking of opening a bug report just this week but never got to it. In the meantime, I suggest you add something like this to your build script, which will at least fix it for the Kotlin compiler (but you'll still see the IDE warnings):
tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile) {
if (!it.name.contains("Test")) {
kotlinOptions.freeCompilerArgs += "-Xexplicit-api=strict"
}
}
If you're using Gradle Kotlin DSL:
tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile> {
if ("UnitTest" !in name) {
kotlinOptions.freeCompilerArgs += "-Xexplicit-api=strict"
}
}
And don't set the compiler argument in android.kotlinOptions, only in that block, so that it is applied only to the non-test source sets.
EDIT: I just checked and the warnings bug was fixed in IntelliJ, so it should be fixed in Android Studio in a few months to a year.

Kotlin Opt-in: Flag is not supported by this version of the compiler

I followed the Kotlin documentation here and here to opt into kotlin.ExperimentalUnsignedTypes for the whole module. My module build.gradle looks like this now:
android {
...
kotlinOptions {
jvmTarget = "1.8"
freeCompilerArgs += "-Xopt-in=kotlin.ExperimentalUnsignedTypes"
}
Lint is still complaining about ExperimentalUnsignedTypes and when compiling I get this warning:
> Task :myModule:compileDebugKotlin
w: Flag is not supported by this version of the compiler: -Xopt-in=kotlin.ExperimentalUnsignedTypes
My kotlin version is: 1.3.61
As mentioned in the docs here
#RequireOptIn and #OptIn annotations were introduced in 1.3.70 to replace previously used #Experimental and #UseExperimental; at the same time, -Xopt-in compiler option replaced -Xuse-experimental.
#OptIn(...::class) and use of -Xopt-in=... were introduced in Kotlin 1.3.70, but the old and gold -Xuse-experimental is still available in future versions (tested in Kotlin 1.4-M1).

Categories

Resources