I build an Android Library (using Kotlin) and I have a class containing some constants.
class LibraryClass {
companion object {
#JVMStatic
val MY_CONSTANT = "value"
}
}
I generate an .aar file using the assembleRelease Gradle task, then I import the .aar file into another app.
The other app also uses kotlin, when I reference the constant inside the companion object, It can't find it.
if(myVariable == LibraryClass.MY_CONSTANT) {
foo()
}
The IDE itself can't find it, it just says:
Unresolved reference: MY_CONSTANT
And when I use the IntelliJ decompiler, the constant is not there, not even using LibraryClass.Companion, it can't even find the reference to the Companion object.
How can I fix this?
Related
In my android project, I have a kotlin object AssetValidator which does some validation over the asset files.
object AssetValidator {
fun validate(assetsDir: File) {
...
}
...
}
Until now, I was calling this function at the startup of my application. But now, I am thinking of calling it from build script instead. But, I am unable to import this package into my gradle file. Android studio is showing Unresolved reference in the import statement. Someone please tell me how to do this.
I have an .aar third party library that I want to use in Xamarin Android. So I created a new Android Bindings Library, added the aar-library and changed the Build action of the aar file to LibraryProjectZip like described here: https://learn.microsoft.com/en-us/xamarin/android/platform/binding-java-library/binding-an-aar
Nothing else was changed and I would expect the project to compile and generate a dll file.
Instead I get a lot of errors saying Error CS0542 'xy': member names cannot be the same as their enclosing type.
When I jump to the origin of the error, I find the errors in generated code by Visual Studio with the classes looking something like:
public abstract class Albumin : Java.Lang.Object {
internal Albumin ()
{
}
// (removed for readability)
[Register ("ALBUMIN")]
public const string Albumin = (string) "albumin";
I cannot modify the source code of the library.
What can I do in order to build the Binding Library successfully?
Thank you very much #Leo Zhu for the answer in the comments:
The solution is Renaming Members.
So in my case the Metadata.xml in die Binings Library would look like the following:
<attr path="/api/package[#name='com.company.android.sdk.dataclass']/interface[#name='DataClass.Albumin']/field[#name='ALBUMIN']" name="name">ALBUMIN_Binding</attr>
I implemented Jacoco in my Android project using the following tutorial https://proandroiddev.com/unified-code-coverage-for-android-revisited-44789c9b722f to cater for test coverage in the kotlin classes.
For some unknown reason, it's not reporting coverage for static methods declared under the Companion block.
class Meh {
companion object {
fun test () {
// logic to test
}
}
However if I convert the class to an instance rather than a singleton that I am able to see the coverage completely fine.
Has anyone came across this problem ? and what did you do ?
following tutorial https://proandroiddev.com/unified-code-coverage-for-android-revisited-44789c9b722f
after cloning of example from the same tutorial in its state as of today (HEAD commit)
git clone https://github.com/rafaeltoledo/unified-code-coverage-android.git
cd unified-code-coverage-android
git checkout kotlin-coverage
addition of companion object into MainActivity
class MainActivity : AppCompatActivity() {
+ companion object {
+ fun executed() {
+ }
+
+ fun notExecuted() {
+ }
+ }
+
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
+ executed()
start of virtual device Pixel XL with API 28 and target Android 9.0 (Google APIs) in freshly downloaded Android Studio 3.2.1
and execution of
./gradlew jacocoTestReport
following report is produced in directory app/build/reports/jacoco/jacocoTestReport/html/ as expected
Given the amount of factors that influence result (such as versions of all involved components - Android SDK, Device, Kotlin compiler, Gradle, JaCoCo, etc, etc), attempts to guess what is different in your case are IMO counterproductive, and so that the best advice - is to perform very careful comparison of differences between your setup and above example.
Update
As was figured out during comparison by #HeWhoProtects , problem was in
exclusion of **/*$*
that refers to exclusion of class files from analysis. Single source file can compile into multiple class files, e.g. in case of nested classes in Java and exactly in case of companion in Kotlin and in both cases name of class and class file will contain $.
I found the the cause of the problem but not sure why it caused it yet, my excludes rules includes more rules than the one in the tutorial above, in different jacoco tutorial for ignoring autogenerated files, it was suggested to include '**/*$*' as rule, as soon as I removed it, it showed coverage for static methods in kotlin.
My understanding of Jacoco that these rules ignore files and will not show it in the report, and before I made the change, it was showing that this class is covered in the test coverage.... is it weird or am I missing a fundamental thing about how kotlin generates methods or how jacoco excludes rules work ?
Anyway I hope this helps..
The app defines constants in a Kotlin singleton object:
#file:JvmName("APIConstants")
package com.myapp.api
object APIConstants {
const val HTTP_RESPONSE_CODE_NOT_AUTHORIZED = 401
etc....
}
They are then used in another class:
import com.myapp.api.APIConstants.HTTP_RESPONSE_CODE_NOT_AUTHORIZED
etc ...
class API {
private fun returnBadResponse(response: Response<*>, callback: ApiAuthListener<*>) {
if (response.code() == HTTP_RESPONSE_CODE_NOT_AUTHORIZED) {
callback.onBadAuthToken()
} else {
callback.onFailure(response.message(), getServerError(response))
}
}
In this class Android Studio (3.0 beta) provided a hint to add the import for the constant, and it does not give any indication of a problem (no red underlines etc, and the constant reference in the method is shown in purple italic text indicating it has been resolved) but when I build the project I get this:
Error: Unresolved reference: HTTP_RESPONSE_CODE_NOT_AUTHORIZED
I've tried clearing the IDE cache and restarting it, and doing a clean build, which make no difference. I've tried removing the #JvmName annotation and even placing the const values in the root of the file with no containing object but neither allows a build.
Why is the class failing to reference the constant, especially when the IDE strongly suggests it can resolve it?
And the solution is.... to make very sure all Kotlin source files have a .kt file extension! In this case the APIConstants file was called "APIConstants" and not "APIConstants.kt" which appears to mean the IDE was able to resolve references based on the content of the file, but the build tools could not. Confusingly Android Studio showed a Kotlin K icon on the filename despite the lack of a .kt extension.
I am attempting to create an Android application using Scala 2.9.2. So far, I have got everything to compile.
However, I am running into problems when I perform the following in my activity:
override def onCreateDialog(id: Int) {
The compiler complains of an incompatible type as Activity.onCreateDialog() takes a primitive int yet I am passing a scala.Int.
The folowing is the compilation error:
error: overriding method onCreateDialog in class Activity of type (x$1: Int)android.app.Dialog;
[INFO] method onCreateDialog has incompatible type
[INFO] override def onCreateDialog(id: Int) {
[INFO] ^
[ERROR] one error found
I thought these would be compatible.
Can anyone advise how to get around this problem?
The following is for Scala 2.10, but I think that the cause of the error is exactly the same for Scala 2.9.x.
By the way, the onCreateDialog(int) method from the type Activity is deprecated, but it's beside the point.
Now, I'm not a Scala expert by any means, but from what I have noticed, functions that do not return anything tend do look like def fun(arg) {}, and ones that do: def fun(arg) = {}. Notice the =. You can also spell out the return type if you want.
So I tried to override the method you mention, and here's the (trivial) implementation:
override def onCreateDialog(id : Int) = {
super.onCreateDialog(id)
}
And it compiles and runs just fine. When you remove the =, you'll get the error you have right now:
overriding method onCreateDialog in class Activity of type (x$1: Int)android.app.Dialog; method onCreateDialog has
incompatible type
The whole MainActivity:
class MainActivity extends Activity {
override def onCreate(savedInstanceState : Bundle) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main_activity)
}
override def onCreateDialog(id : Int) = {
super.onCreateDialog(id)
}
}
Notes: I'm using ADT with bundled Eclipse (Juno), created a default Android project, including Scala-IDE (Scala nature) and AndroidProguardScala (AndroidProguardScala nature)