Why an unresolved reference on attempting to access constant values? - android

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.

Related

How to call a kotlin function from gradle in android project?

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.

Android Xamarin AAR Binding enclosing type

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>

How to resolve "Obsolete custom lint check" for my custom IssueRegistry written in Kotlin and make it work (Android)

I am trying to implement custom lint checks (using Kotlin). I have set up a module for my custom checks and added classes to test my first lew lint check, mostly following these two tutorials here and here.
So I now have a module, I have a custom IssueRegistry, I've created an issue and a Detector class for it. So far it seems complete. I've added a test to check if my lint check works and it looks alright.
I have added my module to the project by referencing it in settings.gradle like this: include ':app', ':somemodule', ':mylintmodule'
Now if I run the linter using ./gradlew lint I get a lint result file telling me this:
Lint found an issue registry (com.myproject.mylintmodule) which requires a newer API level. That means that the custom lint checks are intended for a newer lint version; please upgrade
Lint can be extended with "custom checks": additional checks implemented by developers and libraries to for example enforce specific API usages required by a library or a company coding style guideline.
The Lint APIs are not yet stable, so these checks may either cause a performance degradation, or stop working, or provide wrong results.
This warning flags custom lint checks that are found to be using obsolete APIs and will need to be updated to run in the current lint environment.
It may also flag issues found to be using a newer version of the API, meaning that you need to use a newer version of lint (or Android Studio or Gradle plugin etc) to work with these checks.
To suppress this error, use the issue id "ObsoleteLintCustomCheck" as explained in the Suppressing Warnings and Errors section.
So it tells me that I am using a newer API verion in my custom lint check, right? This is my custom IssueRegistry (minus some parts not relevant for this problem):
class MyCustomIssueRegistry : IssueRegistry() {
override val issues: List<Issue>
get() = listOf(ISSUE_NAMING_PATTERN)
override val api: Int = com.android.tools.lint.detector.api.CURRENT_API
override val minApi: Int = 1
}
From googling this problem and finding this issue I figured I have to override and set the right API version (and maybe the min API?) by overriding these properties like I did above (this version is my last attempt, directly taken from that issue).
So this property can be set to values between -1 and 5, meaning this (taken right out of the lint.detector.api class):
/** Describes the given API level */
fun describeApi(api: Int): String {
return when (api) {
5 -> "3.5+" // 3.5.0-alpha07
4 -> "3.4" // 3.4.0-alpha03
3 -> "3.3" // 3.3.0-alpha12
2 -> "3.2" // 3.2.0-alpha07
1 -> "3.1" // Initial; 3.1.0-alpha4
0 -> "3.0 and older"
-1 -> "Not specified"
else -> "Future: $api"
}
I have tried all of them, plus the one above adding a minApi override too, and I keep getting the exact same result for each of them.
Also I am unable to locate what other API version this is compared with. Is there a place where this is set for the regular linter in an Android project?
It's also unclear to me what I have to do to make sure my changes got applied - is it enough to change some code, then run lint, or do I have to compile the project first, or build & clean?
Following the tutorials, I added my custom lint check by adding this to the app's build.gradle: lintChecks project(":mylintmodule")
Is that even right? The API issue on my registry class shows up no matter if my lint check is referenced (and hopefully used) like that or not. I have also tried the other method described in the first tutorial, adding this task to the linter module build.gradle:
defaultTasks 'assemble'
task copyLintJar(type: Copy) {
description = 'Copies the lint jar file into the {user.home}/.android/lint folder.'
from('build/libs/')
into(System.getProperty("user.home") + '/.android/lint')
include("*.jar")
}
// Runs the copyLintJar task after build has completed.
build.finalizedBy(copyLintJar)
But since I can't figure out how to see if my custom checks are actually run, I don't know if that works as intended either.
So how do I get this warning resolved (since I interpret the text as "As long as the versions don't match I will not try to run your lint check"), and how can I make sure my lint check is actually run by the linter?

Lobok #AllArgsConstructor throw exception when app start on Android 4.2

I have model
#Data
#AllArgsConstructor
#NoArgsConstructor
public class ProductsRequest {
private String initiatorType;
private String categoryCode;
I have lombok config:
lombok.anyConstructor.suppressConstructorProperties = true
lombok.addGeneratedAnnotation = false
On android with API 27(Android 7 on real device) all work fine. On android 17(Android 4.2 on emulator) In this line I get error:
return restApiFactory.getProductService().getProducts(productsRequest);
error:
Caused by: java.lang.ClassNotFoundException: Didn't find class "java.beans.ConstructorProperties" on path: /data/app/my-1.apk
If I change
#AllArgsConstructor
#NoArgsConstructor
to standart constructors - all work fine
Because I never experienced such issue with ctor-s I encourage you to describe your problem in more detail. I assume the code you manually wrote somehow differs from the code lombok generated. Might be the visibility of methods or some special annotation added.
Using delombok feature (https://projectlombok.org/features/delombok) you will expand the annotations to real code. Than you can diff your manually written code and lombok generated code. So you can explore if #java.beans.ConstructorProperties added or not above the code lombok generated. (Delombok using Gradle)
Note: Actually you will have 3 ctor: #AllArgsConstructor, #NoArgsConstructor and #RequiredArgsConstructor is implicitly covered in #Data.
Based on your lombok.config file, ctor-s should not have an annotation. Could it be that some of your flavors are missing the lombok.config on class path?

Runtime error using Xamarin Android with F# and ReactiveUI

I have created a Xamarin Android project that is using F# and ReactiveUI.
When loading my Dashboard, I encounter a runtime exception (of type MissingMethodException) on the inherit line of this code snippet:
type DashboardViewModel(?host: IScreen) =
inherit ReactiveViewModel()
let host = LocateIfNone host
member __.Title with get() = "Dashboard"
interface IRoutableViewModel with
member __.HostScreen = host
member __.UrlPathSegment = "Dashboard"
The error message reads
Method 'Microsoft.FSharp.Quotations.FSharpExpr.Deserialize40' not found.
The ReactiveViewModel type is a thin wrapper around ReactiveObject:
type ReactiveViewModel() as this =
inherit ReactiveObject()
let mutable message = noMessage
let uiContext = SynchronizationContext.Current
member __.SyncContext with get() = uiContext
member this.Message
with get() = message
and set(value) =
this.RaiseAndSetIfChanged(&message, value, "Message") |> ignore
if message <> noMessage then this.RaiseAndSetIfChanged(&message, noMessage, "Message") |> ignore
member val MessageSent =
this.WhenAnyValue(toLinq <# fun vm -> vm.Message #>).ObserveOn(RxApp.MainThreadScheduler).Where(fun m -> m <> noMessage) with get
The project is open source: at the moment, it contains very little content. It can be found at https://github.com/SpiegelSoft/Astrid.
I have submitted a bug on the Xamarin bug tracker: https://bugzilla.xamarin.com/show_bug.cgi?id=51000
Are there any known fixes I can implement myself, so that I can close the bug of my own accord?
UPDATE 1
I've been investigating this issue this weekend.
The FSharp.Core version that is loaded is stuck on the obsolete version 2.3.98.1. This corresponds to the FSharp.Core.dll file in
C:\Program Files (x86)\Reference
Assemblies\Microsoft\Framework\MonoAndroid\v1.0
I have tried to remove this version and load the NuGet package FSharp.Core; however, when I build the Android project, the path always reverts to the obsolete file in the Reference Assemblies path.
Is there a way to override this behaviour?
UPDATE 2
Replacing the FSharp.Core.dll file in the Reference Assemblies path fixes the issue, but this is a very unsatisfactory sticking plaster, which I can't ask my users to apply. Ideally, I would like to find a way to prevent the .Droid project from loading FSharp.Core from the GAC rather than the NuGet package.
I just ran into a very similar issue the other day. My android app had a reference to a Profile7 F# PCL library, which made use of List.unfold, which I believe was introduced in F# 4. When I used the library in my app, I saw a MissingMethodException similar to what you are seeing. The version of FSharp.Core that Xamarin references by default when creating a new Android app didn't have this newer method. I got around it by editing the .fsproj file for the app to remove the original reference to FSharp.Core, and replaced it with a reference to the newer version ( I copy/pasted the tag from the PCL .fsproj file). It looks something like this:
<Reference Include="FSharp.Core">
<Name>FSharp.Core</Name>
<Private>True</Private>
<AssemblyName>FSharp.Core.dll</AssemblyName>
<HintPath>$(MSBuildExtensionsPath32)\..\Reference Assemblies\Microsoft\FSharp\.NETCore\$(TargetFSharpCoreVersion)\FSharp.Core.dll</HintPath>
</Reference>
I was suprised to find that this seems to have fixed the problem for me. I'm not sure if I'll run into other issues down the line, but it may be worth trying this if you havent already.
UPDATE If this doesn't work immediately, follow the sequence of steps in Rob Lyndon's answer.
It appears that this has been fixed by the GitHub commit
https://github.com/xamarin/xamarin-android/commit/df41af046000556ed82f638e8041b7f718966a92
which removes FSharp.Core from the list of framework assemblies, and allows the project to be built without the NuGet FSharp.Core assembly being replaced.
Until this fix is released into the SDK, there is a workaround. The answer submitted by user3850711 works, but you need to apply the changes in a specific sequence, because otherwise the reference will be overwritten during the build.
Delete the existing reference to FSharp.Core.
Install or reinstall the FSharp.Core NuGet package.
Unload the project and add <HintPath>packages\FSharp.Core.4.0.0.1\lib\portable-net45+monoandroid10+monotouch10+xamarinios10\FSharp.Core.dll</HintPath> to the FSharp.Core project reference.

Categories

Resources