How to refer aosp hidden methods in core android app using gradle build system. I am referring framework and other jars from out folder but unable to access hidden API. Is there any way to access hidden methods.
There are a couple ways.
Android Hidden API
As long as you're fine targeting API 27 (there's no API 28 release as of writing this) this way works great. You can directly call the hidden methods with proper code completion and everything.
Note: As of writing this, you'll need to set your Gradle classpath to 3.1.4. 3.2.0 adds some sort of integrity check that breaks builds when using a modified framework JAR.
Use reflection
It's not ideal, but it'll work if you want to target API 28, or you want to use Gradle 3.2.0.
Example (Kotlin):
val IWindowManager = Class.forName("android.view.IWindowManager")
val IWindowManagerStub = Class.forName("android.view.IWindowManager\$Stub")
val ServiceManager = Class.forName("android.os.ServiceManager")
val binder = ServiceManager.getMethod("checkService", String::class.java).invoke(null, Context.WINDOW_SERVICE)
val iWindowManagerInstance = IWindowManagerStub.getMethod("asInterface", Binder::class.java).invoke(null, binder)
val hasNavBar = IWindowManager.getMethod("hasNavigationBar").invoke(iWindowManagerInstance) as Boolean
Related
I'm new with Android Studio and Kotlin and I have some trouble with Kotlin Duration. When I try to do following in my code:
val test: Duration = Duration.parse(value = timeClose)
I get this error message:
This declaration needs opt-in. Its usage must be marked with '#kotlin.time.ExperimentalTime' or '#OptIn(kotlin.time.ExperimentalTime::class)'
I use Android Studio Chipmunk 2021.2.1 Patch 1 with Kotlin 212-1.7.10
How can I solve my problem?
Do what the error is telling you to do: mark it with one of the suggestions.
#kotlin.time.ExperimentalTime
val test: Duration = Duration.parse(value = timeClose)
or
#OptIn(kotlin.time.ExperimentalTime::class)
val test: Duration = Duration.parse(value = timeClose)
The reason you have to do this is that the Duration class is in the ExperimentalTime package, which means that this is an experimental preview, as the documentation states:
Note that this API is in a preview state and has a very high chance of being changed in the future. Do not use it if you develop a library since your library will become binary incompatible with the future versions of the standard library.
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?
I wanted to create sbt cross platforms (Hello world app ) including JVM , Scala Native , Android and scalajs , I have succeed in compiling all of them except the android and this is my build.sbt:
name := "Cross-Platforms-ScalaNative-JVM"
import sbtcrossproject.CrossPlugin.autoImport.{crossProject, CrossType}
val sharedSettings = Seq(scalaVersion := "2.11.12")
lazy val bar =
// select supported platforms
crossProject(JSPlatform, JVMPlatform, NativePlatform)
.crossType(CrossType.Full)
.settings(sharedSettings)
.jsSettings(
libraryDependencies += "org.querki" %%% "jquery-facade" % "1.2")
.jvmSettings(/* ... */)
.nativeSettings(/* ... */)
lazy val barJS = bar.js
lazy val barJVM = bar.jvm
lazy val barNative = bar.native
My question how I can create an android platform in this project; what changes should be to my SBT?
Android build is basically an JVM build with an extra steps - taking JVM bytecode, optionally running proguard to minimize code and compiling it into Android format.
Here you have a lot of information about how to setup normal android build in sbt: https://scala-android.org/quickstart/.
The difference would be by applying androidBuild (and all Android-related settings) only to JVM projects:
val myProjectJVM = myProject.jvm
.settings(androidBuild: _*)
However, considering that Android build and normal Scala build will look differently (as normal JVM application has architecturally little to do with Android apps - e.g. Main.main(Array[String]) vs Android fragments and services) it would be a better idea to have a module for some shared JVM code and a dedicated projects for the platform-specific parts:
val commonJVM = myProject.jvm
val myProjectJVM = project.in(file("java-specific"))
.dependsOn(commonJVM)
val myProjectAndroid = project.in(file("android-specific"))
.settings(androidBuild)
.dependsOn(commonJVM)
That architectural difference is most likely a reason why nobody even considers making Android a fourth option in a cross project - you have a different runtime dependencies, a different way to start the application, so you would have more parts of the code that differ than in common. Submodules with code dedicated to platform depending on common dependency (even cross-compiled one) is a better idea.
I want to integrate h3 java binding library to my android app and I'm getting following exception:
java.lang.UnsatisfiedLinkError: No native resource found at /android-armv7l/libh3-java.so
at com.uber.h3core.H3CoreLoader.copyResource(H3CoreLoader.java:67)
Does anyone used this library before for Android OS?
Thank you.
Initially, following the intended usage as seen in their README should make it work. If it doesn't, see below.
Known Issue: Android, can't use library
UnsatisfiedLinkError: This can be encountered when the corresponding native library is not copied/detected in the project. Following NickRadu's workaround should make it work.
Below is a step-by-step guide.
Add a JNI folder in your project app folder and rename it jniLibs (app/src/main/jniLibs) (for some reason, having it named jni only doesn't work for me).
Get the H3 JAR (make sure you use the same version) and extract the JAR contents.
Copy the folders prefixed with android- and insert them in the jniLibs folder (from step 1).
Rename the copied folders, remove the android- prefix.
Add splits { abi { enable false } } to your app's build.gradle file (within android).
Done. In general, the library should now work as expected.
If during the app installation you encounter:
INSTALL_FAILED_NO_MATCHING_ABIS,
then depending on your test device, create a copy of the folder (along with its contents) and rename it as needed.
For example, a device running on arm64-v8a, I just made a copy of the arm64 folder and renamed it to arm64-v8a. Or if you're using an emulator, make sure that you're not using one with an x86 CPU.
D8 errors: Invoke-customs are only supported starting with Android O (--min-api 26), add these compile options in your app's build.gradle (within android -- note that it may change depending on your system's Java version)
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
Note: It is best to test the app on multiple CPU architecture types first to see it's behavior.
To quickly see the CPU Architecture of the device, you could install Droid Hardware Info, or run a quick test code yourself.
Here's a test block I used and its corresponding result logs:
private fun testH3() {
val h3 = H3Core.newSystemInstance()
val lat = 37.775938728915946
val lng = -122.41795063018799
val resolution = 8
val hexAddr = h3.geoToH3Address(lat, lng, resolution)
val hex = h3.stringToH3(hexAddr)
val kRingsResult = h3.kRings(hexAddr, 1)
Log.d("H3Test", "geoToH3Address: $hexAddr")
Log.d("H3Test", "stringToH3: $hex")
Log.d("H3Test", "kRings: $kRingsResult")
}
Result:
D/H3Test: geoToH3Address: 8828308281fffff
D/H3Test: stringToH3: 613196570331971583
D/H3Test: kRings: [[8828308281fffff], [8828308281fffff, 882830828dfffff, 8828308285fffff, 8828308287fffff, 8828308283fffff, 882830828bfffff, 8828308289fffff]]
I made a sample project where the library works as expected. See android-uber-h3-sample.
Also be advised that the library will not work on Android api < 26 without some modifications to the code. The function that H3Core relies on to parse the hex long to hex string Long.parseUnsignedInt was not added to Android Java until api 26.
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.