Kotlin REPL with Android Classes unStub!ed - android

I like the Kotlin REPL in Idea / Android-Studio - but as an Android Developer I often run into Stub! problems here. When writing unit-tests I am using unmock to work around this problem. Is there a way to use the same method used there for the Kotlin REPL plugin?
[

All android (and java.lang.*) classes are placeholders in an Android project. This is because android does not use standard java class files to store the compiled code and there is no way to directly run this code on a computer.
You simply can't use the REPL with android classes, they will only exist on an actual device or emulator.
If you do not care about correctness, then you can use Robolectric's implementation of Android by adding it as a dependency to the project.
To make sure it does not collide with the actual implementation you should probably do this with a separate module dedicated to the REPL.
Robolectic's dependency used by unmock is: org.robolectric:android-all:7.1.0_r7-robolectric-0

The problem is that the Kotlin REPL in IDEA is provided by the Kotlin IDEA plugin, which has no notion of Android per se, but only looks at what's in the classpath, which in this case is the android.jar containing the stubs that throw the exception you mentioned.
Using unmock or even the integrated Android support for removing exceptions from the stubs in tests (see here at the end of "Mock Android dependencies") won't work as that only affects your Gradle build.
The only solution I can think of is to either open an issue on the Kotlin tracker or dig through the source code of the REPL function in the Kotlin plugin and send a Pull Request.

Related

What is the correct way of developing an Android platform application using Android Studio (or other IDE)

I am currently working on an Android AOSP project for which I am developing a java module which will be a part of the core services (such as the Phone app, for example).
There are some frameworks I use which are not exposed by default to "regular" apps (which lay in the private framework.jar).
For example: There are places I directly use android.app.IActivityManager's Binder API.
I do own the platform keys, but I not prefer compiling the whole AOSP framework each time I want to make a change.
I also prefer working with Android Studio, but will compromise on compiling the application through the terminal, if not possible.
What is the correct way of working on a project of this kind?
How do AOSP's developers develop their code without re-compiling the whole framework each time?
Update:
The best way I've found so far is to simply create an android studio project, get the framework.jar from the device (adb pull /system/framework/framework.jar) or from the AOSP source code, and add it as a compileOnly or runtimeOnly dependency in the gradle.build file of your app.
dependencies {
compileOnly files('libs/framework.jar')
implementation 'com.android.support:recyclerview-v7:28.0.0'
}
Then just add android:sharedUserId="android.uid.system" to the Android Manifest and compile it using the platform keys.
It should be installable as is.
This post seems to sum it up pretty good:
https://kwagjj.wordpress.com/2017/10/27/building-custom-android-sdk-from-aosp-and-adding-it-to-android-studio/comment-page-1/
Is there any other way?
You can wrap those API callings to a new manager and service. For example, you have a manager called CustomManager, and it will call IActivityManager or other private/hidden API directly. And then you can create a module for you CustomManager, and build jar/aar for it. After every changing, you can copy that generated jar/aar file to you AndroidStudio project. You can use it as a normal library. Actually, there are some examples in AOSP source code, such as SystemUISharedLib, wrapper of SystemUI internal API, used by Launcher3.

Is there a way to disable usage of specific packages?

I'm on a team with multiple developers. We're using JUnit5 via android-junit5 and tests written using the #Test annotation from the org.junit package as opposed to the org.junit.jupiter.api package are excluded from gradle's test reporting. I'd like to, if possible, outright prevent developers from using org.junit. Is there a way to do this using gradle? I'd like to achieve this particular solution and not a workaround as there are other instances that we'd like to prevent users from using a given package (java.time.* in Java 8 vs ThreeTenABP)
Thank you
One way of approaching the problem could be to create a Jar that contains only the allowed APIs. You could then upload that jar to an repository and ask developers to use it as a testCompileOnly dependency while keeping the original jar as a testRuntimeOnly dependency.
This will guarantee that test code cannot access the forbidden classes/packages since it will not see them during compilation.

Kotlin bytecode in Android Apps

I'm a kotlin and Java developer, and recently I started analyzing the bytecode generated by kotlin. And I found out a lot of wrapper code and other stuff that the compiler generates in order to translate what I have coded in Kotlin to Java.
So, my question is:
Imagine that I have an app that its code is 100% written in kotlin. Dependencies and the main app. All Kotlin.
Does this mean that a different compiler will be used in order to avoid Java compatible bytecode?
Or is there any optimization done by the compiler in this kind of scenarios?
Many Thanks.
I know about Kotlin Native but I think it will only be applied to Android in the future.
The only way you're going to avoid Java bytecode with Kotlin is to use Kotlin Native, and you won't be able to use the Android SDK in that case.
Kotlin JVM, as the name implies, compiles to JVM bytecode; it's one of the main draws of using it. If it compiled to something different, it would be Kotlin Native.
To answer your bullets:
No, the same compiler is used whether or not you have Java source files.
Probably not. Kotlin JVM is made to be almost completely interoperable with Java, and that's the same whether or not your project includes Java code.
Think about if you were creating an Android library in Kotlin. Would you really want it to automatically compile to something other than Java bytecode in that case? It wouldn't be able to be used in Java projects, defeating one of the main reasons Kotlin is so good as a Java alternative.
Also remember, you're using the Android SDK. Even if you have no dependencies in your build.gradle, you still reference the core SDK itself, which is Java. The SDK isn't included in your APK, but it's still used during compilation.
If you want something that avoids Java bytecode, use something like Flutter. It has its own SDK, and can bridge back to Java components. Of course, you can't completely avoid the JVM, because you still need some way for Android to install and open the app.

Running multi platform Kotlin test in IntelliJ produces No JDK specified error

I have several tests in common module for multi platform Kotlin project. When I execute those tests using gradle, e.g. ./gradlew :android:test, they all go through and the tests run.
I have now encountered a more complicated problem where I would like to debug an actual test in IntelliJ. Unfortunately, upon selecting the debug option in IntelliJ, I get an No JDK specified error.
I am using the following dependencies for testing:
testImplementation "org.jetbrains.kotlin:kotlin-test-annotations-common:$kotlin_version"
testImplementation "org.jetbrains.kotlin:kotlin-test-common:$kotlin_version"
with $kotlin_version being 1.2.41.
The common module settings looks like this:
SDKs section also correctly recognises JDKs:
I have tried changing the Module SDK from Kotlin SDK to java, however IntelliJ then wants me to require jUnit for test execution, which I would prefer not to, if possible.
Is there a way how to make the debugger run in IntelliJ for the Kotlin code?
Found the solution.
Just like it does not make sense to execute tests using Gradle in the common module alone, e.g. ./gradlew :common:test and the tests need to be executed for a specific platform ./gradlew :android:test, because the common module might contain expected declarations which are supposed to be implemented per platform using the actual keyword, it also does not make sense to debug in the common module directly.
Instead, for such purposes, the test to be debugged must be placed in a specific platform module, for my purpose I have chosen the Android module, and then it can be executed and debugged.
As I have mentioned, this approach is necessary because in the Android module the expected structures are actually replaced by the actual implementations.

Can I use Android data-binding with Maven?

There's a beta release of a data-binding library by Google. According to the docs
To use data binding, Android Plugin for Gradle 1.3.0-beta1 or higher is required.
In my project I need to use Maven instead. I'm trying to set up a minimal initial project. The problem is that the new data-binding library somehow mangles processing of the XML layout file that generates the R class and probably requires a gradle plugin: android/databinding/tool/DataBinderPlugin
There is no information on how to handle this without Gradle. Does anyone know what needs to be done to make this run with Maven as well?
There hasn't been a lot of effort put into this since most developers use gradle. That said, I did a quick bit of development to try to enable make builds that you could try out. There is a class android.databinding.tool.MakeCopy that you can try to run. It is a command line interface that copies resources from one or more directories to a target directory, modifies the layout files, and generates some artifacts that are required by the annotation processor (xml files, source files).
It should be included in the library with the annotation processor. You'll have to work out the full class path requirements to get it to work. As I said, I didn't spend a lot of time getting it going because we didn't have any clients for it.

Categories

Resources