ClassNotFoundException when using Jetpack Compose inside a library - gradle

I am working on a Photo Editor library as a playground project to learn Jetpack Compose.
The library exposes an Activity that the client should launch and the editor library should do its magic. This is why I'm expecting the library to be used by apps that does not yet use Compose.
Having said all of the above, when I include my library AAR to a sample app, I'm getting a lot of class not found exceptions.
Caused by: java.lang.ClassNotFoundException: Didn't find class "androidx.compose.material.ColorsKt"
Caused by: java.lang.ClassNotFoundException: Didn't find class "androidx.compose.runtime.internal.ComposableLambdaKt"
Important to mention that the library is not minified (no obfuscation)
Here is the list of dependencies I'm using in the library:
ext {
compose_version = '1.1.1'
kotlin_version = '1.6.10'
ktx_version = '2.4.1'
}
dependencies {
// general dependencies
implementation 'androidx.core:core-ktx:1.8.0'
implementation "androidx.lifecycle:lifecycle-runtime-ktx:$ktx_version"
implementation "androidx.lifecycle:lifecycle-livedata-ktx:$ktx_version"
implementation 'com.github.bumptech.glide:glide:4.13.0'
// kotlin dependencies
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.1'
// compose dependencies
implementation 'androidx.activity:activity-compose:1.4.0'
implementation "androidx.compose.ui:ui:$compose_version"
implementation "androidx.compose.material:material:$compose_version"
implementation "androidx.compose.ui:ui-tooling-preview:$compose_version"
implementation "androidx.compose.runtime:runtime-livedata:$compose_version"
implementation "androidx.compose.ui:ui-tooling-preview:$compose_version"
// navigation
implementation 'androidx.navigation:navigation-compose:2.4.2'
// gpu image
implementation 'jp.co.cyberagent.android:gpuimage:2.1.0'
// test dependencies
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
debugImplementation "androidx.compose.ui:ui-tooling:$compose_version"
}
Any thoughts?

I had similar issue. I added compose dependencies that were used by library to the host application as well. E.g. implementation 'androidx.compose.ui:ui-tooling:1.1.1', implementation 'androidx.lifecycle:lifecycle-viewmodel-compose:2.4.1'
To be clean I added dependencies to .pom shipped with AAR so library user does not need to worry about adding those manually.
As an added bonus I also tried to start my library compose UI in Java host application and it works. Great for flexibility.
Hope this helps you

Related

How can I access the dependencies of an application from within the build file of a dependency embedded in the application?

I have a Gradle-based library that is imported as a dependency into consuming applications. In other words, an application that consumes my library will have a build.gradle file with a list of dependencies that includes both my library as well as any other dependencies they wish to import.
From within my library's build.gradle file, I need to write a Gradle task that can access the full set of dependencies declared by the consuming application. In theory, this should be pretty straightforward, but hours of searching has not yielded a working solution yet.
The closest I've come is to follow this example and define an additional task in the library's build.gradle file that runs after the library is built:
build {
doLast {
project.getConfigurations().getByName('runtime')
.resolvedConfiguration
.firstLevelModuleDependencies
.each { println(it.name) }
}
}
I keep getting an error message that the 'runtime' configuration (passed into getByName and referenced in the Gradle forum post I linked) cannot be found. I have tried other common Gradle configurations that I can think of, but I never get any dependencies back from this code.
So: what is the best way to access the full set of dependencies declared by a consuming application from within the build file of one of those dependencies?
Okay, I mostly figured it out. The code snippet is essentially correct, but the configuration I should have been accessing was 'compileClasspath' or 'runtimeClasspath', not 'runtime'. This page helped me understand the configuration I was looking for.
The final build task in the library looks roughly like this:
build {
doLast {
// ...
def deps = project.getConfigurations().getByName('compileClasspath')
.resolvedConfiguration
.firstLevelModuleDependencies
.each {
// it.name will give you the dependency in the standard Gradle format (e.g."org.springframework.boot:spring-boot:1.5.22.RELEASE")
}
}
}

Adding gradle dependencies

I have a simple gradle 7.2 project, with a simple kotlin file, running java 11, on ubuntu 20.04 in vs code
For my project, I need to add some simple dependencies to java.security such that I'll be able to encrypt and hash some things.
So I need to add it as a dependency.
The project is created by running gradle init and picking all the default options.
I then want to be able to do an import like: import java.security.MessageDigest and use the java.security package.
I guess I'll have to add the dependency in the build file, which currently looks like this:
plugins {
// Apply the org.jetbrains.kotlin.jvm Plugin to add support for Kotlin.
id("org.jetbrains.kotlin.jvm") version "1.5.0"
// Apply the application plugin to add support for building a CLI application in Java.
application
}
repositories {
// Use Maven Central for resolving dependencies.
mavenCentral()
}
dependencies {
// Align versions of all Kotlin components
implementation(platform("org.jetbrains.kotlin:kotlin-bom"))
// Use the Kotlin JDK 8 standard library.
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
// This dependency is used by the application.
implementation("com.google.guava:guava:30.1.1-jre")
// Use the Kotlin test library.
testImplementation("org.jetbrains.kotlin:kotlin-test")
// Use the Kotlin JUnit integration.
testImplementation("org.jetbrains.kotlin:kotlin-test-junit")
}
application {
// Define the main class for the application.
mainClass.set("com.what.isthis.AppKt")
}
I now search google high and low for how a reference to the java.security package can be added in gradle, but find absolutely nothing anywhere.
Following a guide like this it looks like I could just add a in this manner:
implementation 'org.springframework.boot:spring-boot-starter-validation:2.4.0'
If what I wanted was a reference to this validation library. But I can never get to test it, because I can't find any info on how I would target java.security anywhere.
Looking at the docsI tried to just grab the names I could find here, but this did not compile:
implementation 'java.security Package'
So yes, how do I get thjis dependency. And in general how do find the names that I need for getting dependencies in general?
java.security package is part of the Java language itself as you can see from the documentation, for this reason you don't need to include it explicitly it should already be available to you.
Please make sure you have proper Java SDK set up in IDE. Try to configure different distribution/type than you use currently.
Even if you have logic in Kotlin class it should properly resolve an import and compile.
import java.security.MessageDigest
fun main() {
val test = MessageDigest.getInstance("SHA-256")
println("Test Succeeded")
}
You're not finding examples of declaring java.security packages in Gradle because you don't need to declare them; they're included in the JDK so you can import them natively in any class without declaring them in gradle. Try creating this class in any given package within your project and running it. It should succeed.
import java.security.MessageDigest;
public class Test {
public static void main(String[] args) throws Exception {
MessageDigest test = MessageDigest.getInstance("SHA-256");
System.out.println("Test Succeeded");
}
}

update gradle from 4.4 to 5.4 make joda-time dependancy issue

HI I've migrated a project to gradle version 5.4 from 4.4. Since then gradlew build returns error as below.
....ConvTable.java:6: error: package org.joda.time does not exist
import org.joda.time.DateTime;
...ConvetService.java:5: error: package org.joda.time does not exist
import org.joda.time.DateTime;
...ConvetService.java:34: error: cannot find symbol
ConvTableP getLastCononTableDate(String fromCurrency, String toCurrency, DateTime dateTimeZone) throws IOException;
symbol: class DateTime
location: interface ConvetService
Note: Some input files use or override a deprecated API.
Note: Recompile with -Xlint:deprecation for details
* What went wrong:
Execution failed for task ':cur-api:compileJava'
gradle file looks like below. and its a sub project of bigger one
apply plugin: "j-library"
apply plugin: "m-publish"
group = "com.t.cur"
sourceCompatibility = JavaVersion.VERSION_1_7
targetCompatibility = JavaVersion.VERSION_1_7
publishing { publications { mavenJava(MavenPublication) { } }
repositories {
maven { url "${mv_repo_url}" } }
}
dependencies {
implementation "com.t.com:x-core:1.0.0"
implementation "commons-lang:commons-lang:2.6"
}
My guess is that as part of the upgrade, you changed compile configurations with implementation. One of the differences with the new configuration is that the dependencies will not be exposed to consuming projects as part of the compilation classpath. The idea is that the dependencies you put into implementation are implementation specific and should not "leak" onto the consuming projects. This speeds up the build when using incremental compilation as dependent classes are only recompiled if the public API changes but not the internal implementation. There is also a case to be made for providing looser coupling between projects, though this is a bit more subjective. The implementation dependencies will still be part of, and resolved, in the runtimeClasspath configuration though.
So (assuming this is the underlying issue of cause), the dependency x-core used to provide Joda as a transitive dependency for compilation. But this is no longer the case.
There are two ways to fix it. If you use Joda as part of the public API of x-core, you need to declare it using the api configuration instead of implementation (and use the java-library plugin if you don't already). This will make Joda part of the compilation classpath of dependent projects.
On the other hand, if this sub-project just happens to use Joda as well, but in a completely unrelated way to x-core, you should declare it as dependency here as well (either as implementation or api using the same rules as before).

Adding a `.klib` library to kotlin multiplatform

I'm wondering how I'd be able to import my cinterop-ted library to gradle build of the kotlin multiplatform build.
I've already created the library.def file and filled it, I also generated the library.klib and the folder that goes with it.
I just don't understand how to import it into gradle.
I've looked all over internet and I found a reference to Konan and I'm wondering if that's something I have to use, or if that's something being used for something similar to 'cinterop'.
I've looked over the following links, and I haven't found anything remotely connected to the .klib import part of my question.
Link #1 (kotlinlang.org)
Link #2 (github.com)
Link #3 (plugins.gradle.org)
In general, you'll want to use the multiplatform plugin. If you're building a klib separately, you're creating some extra steps (probably). In Link #2 it says that platform plugin is deprecated. Konan is the name of the native platform/compiler. There was a separate plugin for that last year, but you definitely don't want to be using that.
I just created an example but it's not public yet, so this is the best one I have off hand:
https://github.com/JetBrains/kotlin-native/blob/3329f74c27b683574ac181bc40e3836ceccce6c1/samples/tensorflow/build.gradle.kts#L12
I'm working on a Firestore library. The native and interop config live in the multiplatform config.
kotlin {
android {
publishAllLibraryVariants()
}
// iosArm64()
iosX64("ios"){
compilations["main"].cinterops {
firebasecore {
packageName 'cocoapods.FirebaseCore'
defFile = file("$projectDir/src/iosMain/c_interop/FirebaseCore.def")
includeDirs ("$projectDir/../iosApp/Pods/FirebaseCore/Firebase/Core/Public")
compilerOpts ("-F$projectDir/src/iosMain/c_interop/modules/FirebaseCore-${versions.firebaseCoreIos}")
}
firestore {
packageName 'cocoapods.FirebaseFirestore'
defFile = file("$projectDir/src/iosMain/c_interop/FirebaseFirestore.def")
includeDirs ("$projectDir/../iosApp/Pods/FirebaseFirestore/Firestore/Source/Public", "$projectDir/../iosApp/Pods/FirebaseCore/Firebase/Core/Public")
compilerOpts ("-F$projectDir/src/iosMain/c_interop/modules/FirebaseFirestore-${versions.firebaseFirestoreIos}")
}
}
}
}
The cinterops sets up where the def files are and params. I then publish that whole thing as a multiplatform library. The actual native artifact is a klib ultimately, but it's all managed with gradle and dependency metadata.

Use Gradle's DependencySet in depencencies block or other way to use multiple modules from one group

Gradle has an interface called DependencySet that Spring's dependency-management-plugin can use in a dependencies block in a dependencyManagement block like below. (Code from here for reference.)
dependencyManagement {
dependencies {
dependencySet(group:'org.slf4j', version: '1.7.7') {
entry 'slf4j-api'
entry 'slf4j-simple'
}
}
}
This is a very pretty to group dependencies that are in the same group. The more dependencies in the group the prettier it gets. Projects tend to have a lot of dependencies from the same group, especially if you are using Spring. Is there any way to use a similar notation in the "real" dependencies block?
I am afraid there isn't a way how to use dependencySet outside of the dependencyManagement section added by the Spring dependency-management-plugin plugin.
You can take a look at the following classes to see how the dependencies are being read from the script:
DefaultProject - method dependencies()
DefaultDependencyHandler
The interface for dependencySet is used differently in Gradle. For example it is returned when you want to know all dependencies from a configuration.

Resources