Intellisense not working in Kotlin Multiplatform Library - android

I have a kotlin multiplatofrm library that is included into an Android and iOS app.
In my android project include it as a composite build (MyLib). But Intellisense is not working at all for all code from in MyLib, though the whole thing compiles fine. I am using Android Studio. What could be wrong and how can I debug it?
rootProject.name='xxx'
includeBuild 'MyLib'
include ':common'
include ':app'
MyLib's build.gradle.kts looks as follows:
plugins {
kotlin("multiplatform") version "1.5.31"
kotlin("native.cocoapods") version "1.5.31"
}
repositories {
mavenCentral()
maven { setUrl("https://dl.bintray.com/kotlin/kotlinx.html/") }
}
group = "com.xxx.MyLib"
// CocoaPods requires the podspec to have a version.
version = "1.0"
kotlin {
ios()
jvm {
compilations.all {
kotlinOptions.jvmTarget = "1.8"
}
testRuns["test"].executionTask.configure {
useJUnit()
}
}
cocoapods {
ios.deploymentTarget = "11.4"
frameworkName = "MyLib"
summary = "xxx"
homepage = "xxx"
podfile = project.file("../../iOS-App/Podfile")
}
sourceSets {
commonMain {
dependencies {
implementation("org.jetbrains.kotlin:kotlin-stdlib:1.5.31")
implementation("com.badoo.reaktive:reaktive:1.2.0")
implementation("com.badoo.reaktive:reaktive-annotations:1.2.0")
implementation("org.jetbrains.kotlinx:kotlinx-datetime:0.3.1")
implementation("com.russhwolf:multiplatform-settings-no-arg:0.8.1")
implementation("net.swiftzer.semver:semver:1.1.1")
}
}
}
}
tasks.withType<GenerateModuleMetadata> {
enabled = true
}

I think this is likely related to https://youtrack.jetbrains.com/issue/KTIJ-18903

I had the same issue and it drove me crazy. How can one write code nowadays without Intellisense (answer: you can't).
I tried a ton of things (all the usual and unusual stuff you do when Android Studio / IntelliJ act up). Ultimately I upgraded to Kotlin 1.6.0-RC2 (from 1.5.31) -> https://github.com/JetBrains/kotlin/releases/tag/v1.6.0-RC2.
Part of that is upgrading the Kotlin Plugin:
Another part is the Kotlin Gradle Plugin dependency:
org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.0-RC2
And last but not least I had to downgrade the corouting dependency (from 1.5.2):
org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.0-RC
After that everything was back to normal.

Related

Upgrading compose/gradle

I copied project from GitHub and I want to modify it.
But I can't add LazyHorizontalGrid so I guess I need to update Jetpack Compose version or Gradle right?
What is proper way of doing that because if I do it with Project Structure as IDE suggest app crashes and I can't even build project.
I googled error and then next one and then next one and so on. But I think that it shouldn't be so hard to just update project.
LazyHorizontalGrid was added with 1.2.0 of the Compose Foundation dependency.
To update just change your build.gradle files.
In the root build.gradle file:
buildscript {
ext {
compose_version = '1.2.1'
}
//..
dependencies {
//...
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.7.10"
}
}
In your app/build.gradle:
android {
compileSdk 33
//...
composeOptions {
kotlinCompilerExtensionVersion 1.3.1
}
}
dependencies {
implementation "androidx.compose.foundation:foundation:$compose_version"
//...all the other compose dependencies
}
Check also the compatibility map for Compose Compiler Version/Kotlin Version.

How to update latest gradle version of kotlin library

I created a library in multiplatform in latest intellij. My intellj added the outdated gradle version
settings.gradle.kts
pluginManagement {
repositories {
google()
gradlePluginPortal()
mavenCentral()
}
resolutionStrategy {
eachPlugin {
if (requested.id.namespace == "com.android") {
useModule("com.android.tools.build:gradle:4.1.2"). // How to update to latest version and what is the use of 4.1.2?
}
}
}
}
rootProject.name = "xyz"
I commented above in my code. Can someone guide how can I update my gradle version to latest and what is the use of 4.1.2 that piece of code?
I tried to remove 4.1.2 below piece of code then I am getting issue
resolutionStrategy {
eachPlugin {
if (requested.id.namespace == "com.android") {
useModule("com.android.tools.build:gradle:4.1.2")
}
}
}
Error
Build file '/Users/vmodi/IdeaProjects/abc/build.gradle.kts' line: 1
Plugin [id: 'com.android.application'] was not found in any of the following sources:
gradle-wrapper.properties
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
build.gradle.kts
plugins {
kotlin("multiplatform") version "1.6.21"
id("com.android.application")
}
group = "com.abc"
version = "0.0.1"
repositories {
google()
mavenCentral()
}
kotlin {
android()
iosX64()
iosArm64()
iosSimulatorArm64()
sourceSets {
val ktorVersion = "2.0.0"
val commonMain by getting {
dependencies {
implementation("io.ktor:ktor-client-core:$ktorVersion")
implementation("io.ktor:ktor-client-logging:$ktorVersion")
implementation("io.ktor:ktor-client-content-negotiation:$ktorVersion")
implementation("io.ktor:ktor-serialization-kotlinx-json:$ktorVersion")
implementation("io.ktor:ktor-client-auth:$ktorVersion")
implementation("org.jetbrains.kotlinx:kotlinx-serialization-core:1.3.2")
implementation("io.insert-koin:koin-core:3.2.0-beta-1")
}
}
val androidMain by getting {
dependencies {
implementation("io.ktor:ktor-client-okhttp:$ktorVersion")
implementation("io.ktor:ktor-client-logging-jvm:$ktorVersion")
}
val iosX64Main by getting
val iosArm64Main by getting
val iosSimulatorArm64Main by getting
val iosMain by creating {
dependsOn(commonMain)
iosX64Main.dependsOn(this)
iosArm64Main.dependsOn(this)
iosSimulatorArm64Main.dependsOn(this)
dependencies {
implementation("io.ktor:ktor-client-darwin:$ktorVersion")
}
}
}
}
}
android {
compileSdk = 21
sourceSets["main"].manifest.srcFile("src/androidMain/AndroidManifest.xml")
defaultConfig {
applicationId = "com.abc.kotlinmultiplatform"
minSdk = 21
targetSdk = 31
}
#Suppress("UnstableApiUsage")
compileOptions {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
}
IntelliJ version
IntelliJ IDEA 2022.1.1 (Ultimate Edition)
Build #IU-221.5591.52, built on May 10, 2022
Licensed to Vivek Modi
For educational use only.
Runtime version: 11.0.14.1+1-b2043.45 x86_64
VM: OpenJDK 64-Bit Server VM by JetBrains s.r.o.
macOS 11.6.5
GC: G1 Young Generation, G1 Old Generation
Memory: 2048M
Cores: 16
Non-Bundled Plugins:
com.intellij.nativeDebug (221.5591.54)
org.jetbrains.kotlin-js-inspection-pack-plugin (0.0.9)
Kotlin: 221-1.6.21-release-337-IJ5591.52
After #PylypDukhov suggestion, trying to update gradle 7.0.4 I am getting this weird error
error
Failed to query the value of property 'namespace'.
Package Name not found in /Users/vmodi/IdeaProjects/abc/src/androidMain/AndroidManifest.xml, and namespace not specified. Please specify a namespace for the generated R and BuildConfig classes via android.namespace in the module's build.gradle file like so:
android {
namespace 'com.example.namespace'
}
settings.gradle.kts
pluginManagement {
repositories {
google()
gradlePluginPortal()
mavenCentral()
}
resolutionStrategy {
eachPlugin {
if (requested.id.namespace == "com.android") {
useModule("com.android.tools.build:gradle:7.0.4")
}
}
}
}
rootProject.name = "LetsGetCheckedKotlinMultiplatform"
Added androidMain
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest package="com.abc"/>
4.1.2 is android gradle plugin version, it's not related to gradle version.
Android gradle plugin is shipped with Android Studio, if you wanna use latest version mentioned by #Egor, you have to use Android Studio.
IntelliJ IDEA supports them with a delay - the last supported version at the moment is 7.0.4, which works fine to me, the only problem you might have with it is the lack of support for the 32 target version of Android - but it's not required to upload the app and will work fine on 32 devices, also you can build release version in AS with newest plugin, and develop in IDEA, as to me it seems more performant in KMM projects.
4.1.2 is the version number. To find out what the latest version is, visit Google's Maven Repository. At the time of writing, the latest stable version is 7.2.0, so simply replace "4.1.2" with "7.2.0" and rebuild the project.

Local library module dependency kotlin multiplatform

Can I include local library module on the android sourceset in kotlin multiplatform?
If so, how do we do that?
I have tried adding
api(project(":local-library-one"))
api(project(":local-library-two"))
in android source-set of build.gradle.kts file.
It fails.
You have to make your "local-library" multiplatform too. It can be only targeted to android, so you don't need to modify anything but build.gradle file, something like this:
plugins {
kotlin("multiplatform")
id("com.android.library")
}
android {
// your setup
}
kotlin {
android()
sourceSets {
val androidMain by getting {
dependencies {
// your deps
}
}
}
}

How do you add gRPC to Android Studio with Kotlin?

Task
I need to connect an Android client with a python server using gRPC. Making the server and generating the protos was easy in Python, but the lack of tutorials and confusing documentation for the Kt client makes it appear overwhelmingly complicated.
Background
Until now I've made some simple Android apps using Kotlin, I got used to adding dependencies to either the module or app level build.gradle.
What have I tried?
My first thought was to go to the official documentation as I did with Python.
I found the guide from there pretty confusing (I felt like there's something missing from that article), so I went to see the full examples from their GitHub. I also cloned the repo and compiled the protos with the gradlew installDist command. Then the things got awfully complicated:
When you create an Android Studio project, you get a bunch of gradle things(module and app level build.gradle's, gradlew and gradlew.bat, settings, etc)
After you clone the repo, you get another bunch of gradle things inside the grpc-kotlin folder.
You also get build.gradle.kts which seem to be the same build logic/package manager helper files, but with other dependencies and with the Kotlin Script syntax.
This is when I went off to YouTube in order to search for a simple implementation and found out that there's only a handful of videos on the gRPC with Kotlin subject, and most of those are presentation videos about the features of gRPC in Kotlin when using Coroutines.
What I have until now
I migrated all my build.gradle's to .kts ones.
This is how my module-level build.gradle.kts looks like:
buildscript {
val kotlin_version = "1.5.10"
repositories {
google()
mavenCentral()
}
dependencies {
classpath("com.android.tools.build:gradle:4.2.1")
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:${kotlin_version}")
classpath("org.jetbrains.kotlin:kotlin-android-extensions:${kotlin_version}")
classpath("com.google.gms:google-services:4.3.8")
classpath ("com.google.protobuf:protobuf-gradle-plugin:0.8.14")
}
}
allprojects {
repositories {
google()
mavenCentral()
}
}
tasks.register("clean",Delete::class){
delete(rootProject.buildDir)
}
This is how my app level build.gradle.kts looks like:
import com.google.protobuf.gradle.generateProtoTasks
import com.google.protobuf.gradle.id
import com.google.protobuf.gradle.plugins
import com.google.protobuf.gradle.protobuf
import com.google.protobuf.gradle.protoc
plugins {
id("com.android.application")
id("com.google.protobuf")
kotlin("android")
}
android {
compileSdkVersion(30)
buildToolsVersion = "30.0.3"
defaultConfig {
applicationId = "com.example.myapplication"
minSdkVersion(26)
targetSdkVersion(30)
versionCode = 1
versionName = "1.0"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
getByName("release") {
isMinifyEnabled = false
proguardFiles(getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro")
}
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = "1.8"
}
buildFeatures {
viewBinding = true
}
}
protobuf {
protoc { artifact = "com.google.protobuf:protoc:3.12.0" }
plugins {
id("grpc") {
artifact = "io.grpc:protoc-gen-grpc-java:1.35.0"
}
}
generateProtoTasks {
all().forEach { task ->
task.plugins.create("java") {
option("lite")
}
task.plugins {
id("grpc") {
this.option("lite")
}
}
}
}
}
dependencies {
val kotlin_version = "1.5.10"
implementation("org.jetbrains.kotlin:kotlin-stdlib:${kotlin_version}")
implementation("androidx.core:core-ktx:1.5.0")
implementation("androidx.appcompat:appcompat:1.3.0")
implementation("com.google.android.material:material:1.3.0")
implementation("androidx.constraintlayout:constraintlayout:2.0.4")
testImplementation("junit:junit:4.13.2")
androidTestImplementation("androidx.test.ext:junit:1.1.2")
androidTestImplementation("androidx.test.espresso:espresso-core:3.3.0")
// GRPC Deps
implementation("io.grpc:grpc-okhttp:1.37.0")
implementation("io.grpc:grpc-protobuf-lite:1.37.0")
implementation("io.grpc:grpc-stub:1.36.0")
implementation("org.apache.tomcat:annotations-api:6.0.53")
}
I could generate the protos but something was off about them.
Problem
When implementing the request functions, respectively a bi-directional stream, I found out that all my rpc functions asked for an extra StreamObserver parameter(which was absent in all of the tutorials I've found on the internet). At a closer look I observed that all the generated files were in java and on the official docs, the generated files are both POJOs and Kotlin.
This is how my generated Stub class looks like:
public static final class ChatServiceStub extends io.grpc.stub.AbstractAsyncStub<ChatServiceStub> {
private ChatServiceStub(
io.grpc.Channel channel, io.grpc.CallOptions callOptions) {
super(channel, callOptions);
}
#java.lang.Override
protected ChatServiceStub build(
io.grpc.Channel channel, io.grpc.CallOptions callOptions) {
return new ChatServiceStub(channel, callOptions);
}
/**
* <pre>
* This bi-directional stream makes it possible to send and receive Notes between 2 persons
* </pre>
*/
public void chatStream(grpc.Chat.Empty request,
io.grpc.stub.StreamObserver<grpc.Chat.Note> responseObserver) {
io.grpc.stub.ClientCalls.asyncServerStreamingCall(
getChannel().newCall(getChatStreamMethod(), getCallOptions()), request, responseObserver);
}
/**
*/
public void sendNote(grpc.Chat.Note request,
io.grpc.stub.StreamObserver<grpc.Chat.Empty> responseObserver) {
io.grpc.stub.ClientCalls.asyncUnaryCall(
getChannel().newCall(getSendNoteMethod(), getCallOptions()), request, responseObserver);
}
}
I do not know how to replicate a gradle script for my project, I found no one on the internet explaining how are all those build.gradle's linked together(I figured out that module level build.gradle's are describing how the module they're in is supposed to build and app level build.gradle's are idem but for the entire app). Most of the articles I found are the same as the official docs.
What I want
I just want a simple-simple project or a step by step tutorial, without "clone this and run a command in the terminal, it just works".
I do not blame the devs or whoever wrote the official docs, I actually bet I'm the stupid one here, but I struggle to understand these concepts and I would be grateful if someone can explain to me what I did wrong or where to learn.
Also, sorry for the long question, I tried to expose my POV the best I could, this is my second question since I started learning programming and I'm sorry if the problem and my goals aren't clear enough, I'll edit anything if it's needed.
I do not have a step-by-step process I can share and do not want to trivialize an excellently asked question. However, I wanted to respond that in researching a similar problem, I found that Square has a library that seems to be more Kotlin friendly:
https://square.github.io/wire/#wire-kotlin
I created the simplest project I could. The minimal configuration of Android project can be found in this commit.
Start a new project from Basic activity template in Android Studio and then:
Modify app/build.gradle
Add Gradle plugin, so it can generate all stubs in the build step:
plugins { // this section should be already at the top of the file
// ...
id 'com.google.protobuf' version "0.9.1" // "0.9.2 causes compilation errors!"
}
WARNING: At the time of writing, the latest version of
protobuf gradle plugin is 0.9.2. Using this version causes
build errors I wasn't able to deal with using information I found
on the Internet.
Add project dependencies. Lack of one can cause usually
non-understandable error messages.
dependencies { // this section should be already in the file
// ...
implementation 'io.grpc:grpc-stub:1.52.1'
implementation 'io.grpc:grpc-protobuf:1.52.1'
implementation 'io.grpc:grpc-okhttp:1.52.1'
implementation 'io.grpc:protoc-gen-grpc-kotlin:1.3.0'
implementation 'io.grpc:grpc-kotlin-stub:1.3.0'
implementation 'com.google.protobuf:protobuf-kotlin:3.21.12'
}
Add protobuf section - the one that is responsible for generating protobuf data classes and gRPC client stubs:
protobuf { // this section needs to be added
protoc {
artifact = "com.google.protobuf:protoc:3.21.12"
}
plugins {
grpc {
artifact = "io.grpc:protoc-gen-grpc-java:1.52.1"
}
grpckt {
// I don't really know what ":jdk8#jar" does...
artifact = "io.grpc:protoc-gen-grpc-kotlin:1.3.0:jdk8#jar"
// ...but it doesn't work without it.
}
}
generateProtoTasks {
all().forEach {
it.plugins {
grpc {}
grpckt {}
}
it.builtins {
kotlin {}
java {}
}
}
}
}
4*. I placed my proto file in app/src/main/proto directory. In case you store your protos in some other directory you can configure it by following instructions from protobuf-gradle-plugin repo readme.
Update AndroidManifest.xml
You also need to add proper permission to app/src/main/AndroidManifest.xml:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.INTERNET" />
<!-- ... -->
</manifest>
Use gRPC client
class FirstFragment : Fragment() {
// ...
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val port = 50051
val channel = ManagedChannelBuilder.forAddress("192.168.0.13", port).usePlaintext().build()
val stub = PingPongGrpcKt.PingPongCoroutineStub(channel)
binding.buttonFirst.setOnClickListener {
runBlocking {
val request = Pingpong.PingPongMsg.newBuilder().setPayload("World").build()
val response = stub.ping(request)
Log.i("result", response.toString())
}
}
}
// ...
}

Android Gradle: Custom Plugin with id 'XXXX' not found - Kotlin DSL

I'm trying to develop a gradle plugin to use it for generating some objects and methods for our api using some scheme.
I have followed some tutorials but they all seem not to work, atleast for me.
Some of these tutorials were:
https://musings.animus.design/kotlin-poet-building-a-gradle-plugin/
https://medium.com/#magicbluepenguin/how-to-create-your-first-custom-gradle-plugin-efc1333d4419
I have not used the buildSrc module because I'm already using it for Kotlin DSL, so I decided to create a new module and create my plugin there.
My plugin's module build.gradle.kts looks like this:
plugins {
id("java-gradle-plugin")
id("kotlin")
}
java {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
buildscript {
repositories {
google()
jcenter()
}
dependencies {
classpath(config.ClassPaths.androidBuildTools)
classpath(config.ClassPaths.kotlinGradlePlugin)
}
}
repositories {
google()
jcenter()
}
dependencies {
implementation(config.ClassPaths.androidBuildTools)
implementation(config.ClassPaths.kotlinGradlePlugin)
}
gradlePlugin {
plugins {
create("Generator") {
id = "Generator"
implementationClass = "Generator"
}
}
}
My projects settings.gradle.kts looks like this:
include(":SampleProject", ":scheme-generator")
And in my application module's build.gradle.kts I'm applying this plugin like this:
apply(plugin = "Generator")
The build script stops here with an error: plugin 'Generator' not found
My Generator class looks like this:
class Generator : Plugin<Project> {
override fun apply(target: Project) {
target.android().variants().all { variant ->
// Make a task for each combination of build type and product flavor
val myTask = "myFirstTask${variant.name.capitalize()}"
// Register a simple task as a lambda. We can later move this to its own
// class to make our code cleaner and also add some niceties.
target.tasks.create(myTask){task ->
// Group all our plugin's tasks together
task.group = "MyPluginTasks"
task.doLast {
File("${target.projectDir.path}/myFirstGeneratedFile.txt").apply {
writeText("Hello Gradle!\nPrinted at: ${SimpleDateFormat("HH:mm:ss", Locale.getDefault()).format(Date())}")
}
}
}
}
}
}
The android and variants methods are declared in a utils file, they look like this:
object GeneratorUtils {
fun Project.android(): BaseExtension {
val android = project.extensions.findByType(BaseExtension::class.java)
if (android != null) {
return android
} else {
throw GradleException("Project $name is not an Android project")
}
}
fun BaseExtension.variants(): DomainObjectSet<out BaseVariant> {
return when (this) {
is AppExtension -> {
applicationVariants
}
is LibraryExtension -> {
libraryVariants
}
else -> throw GradleException("Unsupported BaseExtension type!")
}
}
}
I have tried many things, but I seem not to get this right.
EDIT:
Using the buildSrc module for my plugin works totally fine, the plugin is applied and the gradle tasks are visible. However, buildSrc is reserved for other purposes, and we would like our plugin to be in a separate module, so we will be able to use it in other projects.
EDIT 13/04/2021
I have managed to see the tasks that are added by my plugin in my app tasks list by including this module as a composite build.
My settings.gradle now looks like this:
pluginManagement {
includeBuild("generator")
}
include(":SampleProject")
build.gradle of my plugin looks like this:
apply plugin: 'java-gradle-plugin' // Allows us to create and configure custom plugins
apply plugin: 'kotlin' //Needed as we'll write our plugin in Kotlin
buildscript {
ext {
kotlin_version = '1.4.31'
gradle_version = '4.1.2'
}
repositories {
google()
jcenter()
}
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath "com.android.tools.build:gradle:$gradle_version"
}
}
repositories {
google()
jcenter()
}
dependencies {
// Android gradle plugin will allow us to access Android specific features
}
gradlePlugin {
plugins {
create("Generator") {
id = "Generator"
implementationClass = "com.example.Generator"
}
}
}
And my generator class now looks like this:
class Generator : Plugin<Project> {
override fun apply(project: Project) {
project.tasks.register("generationTask") { task ->
task.apply {
group = "generation"
actions.add(Action {
print("Hello from generation task!")
})
}
}
}
}
I can see generationTask in my tasks list and I can execute it normally. It prints the text without any problems.
The problem now is to include com.android.tools.build:gradle:4.1.2 in my dependecies to use it to access build types and flavors and their paths to save my generated code there. When I add it to my dependencies block, gradle fails with this error: Could not find com.android.tools.build:gradle:4.1.2.
How can I solve this problem?
Gradle build goes through specific set of phases, and the Configuration phase comes before the Execution phase. So you cannot use a plugin, which is built in the same build process, because by the time gradle tries to use it on Configuration phase, the plugin has not been built yet.
buildSrc directory is a special one, it's built not as part of the same build process, but in a separate build, before the main build process starts. This feature is called included or composite build. buildSrc is just a pre-defined way to set up a composite build and you can define your own included builds. So to make your plugin visible to the main build, you need to put it into a separate build and include this build into a composite build as described in the doc above. Here is an article describing how to transform a plugin defined in buildSrc into a composite build.

Categories

Resources