I would like to use the Scala (2.11) reflection package's runtime mirror in a Scala application compiled for android which is being build using Scala on android.
I was able to fiddle with ProGuard options in order to make it include the required Scala classes. However when I try to get a mirror instance:
universe.runtimeMirror(this.getClass.getClassLoader)
(Indeed it fails during the lazy computation of universe)
The application crashes in run time:
java.lang.NoClassDefFoundError: Failed resolution of: Ljava/rmi/Remote;
at scala.reflect.internal.Definitions$DefinitionsClass.RemoteInterfaceClass$lzycompute(Definitions.scala:370)
at scala.reflect.internal.Definitions$DefinitionsClass.RemoteInterfaceClass(D efinitions.scala:370)
at scala.reflect.runtime.JavaUniverseForce$class.force(JavaUniverseForce.scal a:255)
at scala.reflect.runtime.JavaUniverse.force(JavaUniverse.scala:16)
at scala.reflect.runtime.JavaUniverse.init(JavaUniverse.scala:147)
at scala.reflect.runtime.JavaUniverse.<init>(JavaUniverse.scala:78)
at scala.reflect.runtime.package$.universe$lzycompute(package.scala:17)
at scala.reflect.runtime.package$.universe(package.scala:17)
This crash is for me as expected as it isn't:
It is expected as java.rmi is not part of the Android API and I should expect any code trying to load its classes to crash.
It is unexpected as I didn't know that Scala's reflect package used java.rmi
I have traced the code to were rmi is required, that is to JavaUniverse (a trait mixed in JavaUniverse class) force method:
...
definitions.RemoteInterfaceClass
...
Which leads to DefinitionsClass:
lazy val RemoteInterfaceClass = requiredClass[java.rmi.Remote]
Am I wrong to think that this is a no-go for Scala reflection in Android?
If I am, what could be a workaround to this problem?
To summarize your solution and a related solution, it is sufficient to add two files, and modify build.sbt to include:
dexAdditionalParams in Android += "--core-library"
Add java/rmi/Remote.java to your project with the content:
package java.rmi;
public interface Remote {}
Add java/rmi/RemoteException.java to your project with the content:
package java.rmi;
public interface RemoteException {}
Related
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>
So I have an Android library project, SimpleWidget. I publish it to jcenter.
I can make a new project and add implementation 'my.project:simplewidget:1.2.3' and everything works as expected, I can use SimpleWidget instances and their public APIs.
Now I make another Android library project, ComplexWidget. ComplexWidget is a subclass of SimpleWidget. I add implementation 'my.project:simplewidget:1.2.3' to the build.gradle and everything resolves, and in fact I can even get away without lint yelling for something super basic like ComplexWidget complexWidget = new ComplexWidget().
However, the project will not compile. Any ComplexWidget method that has a return or parameter type of SimpleWidget (e.g., many of the inherited methods, or an interface that accepts SimpleWidget arguments, or a Factory that returns SimpleWidget instances) will not compile and Android Studio complains that "Cannot access my.project.SimpleWidget".
Not sure if I should even mention it for fear of muddying the waters, but if I command click SimpleWidget in, for example, public class ComplexWidget extends SimpleWidget, I get a warning at the top of the file that "Library source does not match the byetcode for the class SimpleWidget".
Any ideas?
TYIA
use api 'my.project:SimpleWidget:1.2.3' instead
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 am receiving an exception at runtime as follows.
"No realmobject. Has linker stripped them...."
My solution includes a PCL, Android and IOS project with Visual studio Mac and the realm package 1.6.0 installed in each project. I've also checked that Fodyweaver.xml includes the correct reference and all packages have th same version.
When I have the PCL included in the same folder as the solution (i.e like the default multiplatform solution with PCL) everything works ok.
However I moved the PCL project which includes all the realm logic to a separate folder so I can use it across multiple solutions. My solution now includes the PCL from this external folder and the iOS and Android project also reference the realm packages. the app compiles fine but when I run the application it now receives this exception on the first call to use realm.getinstance.
If Input the PCL project back into the same folder as the main solution as originally created it works fine.
can anyone advise a fix for this ?
I've solved the issue now. Firstly I had applied the solution from #sushhangover, but it didn't work straight off.
After some investigation I discovered the compiler was not weaving the classes and realm objects into the library at all.
I simply loaded the library independently of my main solution, removed and reloaded realm packages and Fody, cleaned it all, rebuild All. and then I could see the fodyweaver working properly. I then added the reference back into my main solution and it all works .
This is the same issue I have when placing my RealmObject models into a separate library (PCL or NetStd) as I use a Viper architecture and I share the same model across multiple solutions.
When Realms.Realm.GetInstance(....) is called the Realm initialization assumes the RealmObjects will be in the same assembly or that the assembly containing is already loaded, but they are not in this case. You can tell this is the case as a compiler warning is issued in the assembly build (via the Fody processing) that is calling GetInstance but that does not have any RealmObjects in it:
Warning: Fody/RealmWeaver: Default schema appears to be empty. This is not an error if you don't have any RealmObject inheritors declared. Otherwise it may be a bug with the weaver. (GeneticCancerSelectors)
So I add a static class to my Realm model library:
public static class RealmModel
{
public static Realms.Realm GetInstance() => GetInstance("");
public static Realms.Realm GetInstance(string databasePath) => GetInstance(new RealmConfiguration(databasePath));
public static Realms.Realm GetInstance(RealmConfigurationBase config = null) => Realms.Realm.GetInstance(config);
public static Task<Realms.Realm> GetInstanceAsync(RealmConfigurationBase config) => Realms.Realm.GetInstanceAsync(config);
}
Now when you need to get a Realm instance, do not call:
Realms.Realm.GetInstance()
But call the one in your Model assembly:
RealmModel.GetInstance()
Thanks to Chris Baxter.
That's my situation.
[WPF Application, Fody 3.0.3, Realm 3.4.0]
Exception: No RealmObjects. Has linker stripped them?
...This is my First Time using Realm, and It's really bad feeling...
A [Brand New] Blank WPF Project
Nuget => Realm
Required FodyWeavers.xml file Created in Solution Folder, because Nuget can't
do this for you now.
(Somehow I Update Then Downgrade a latest version of Fody, after
recongized that Realm don't support Any Fody which version newer
than 3.X)
Awful Exception Occurs, ooooops!
(hours work with System
Auth, SpecialFolder, etc... Until I Discovered Chris Baxter's
answer)
Xml file content:
<?xml version="1.0" encoding="utf-8" ?>
<Weavers>
<RealmWeaver/>
</Weavers>
How to Solve the Problem:
Just Clean And ReBuild Solution, Problem Solved.
In the project I'm working we've recently added some level of security, now i don't want to have to rewrite the entire nework logic if it can be done much more easily with AOP.
So, I'm trying to intercept the "onRequestSuccess" method of the requestListeners that are used throughout the application.
For this I have made a simple aspect:
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
#Aspect
public class NetworkResponseAspect {
#Around("execution(public void *.onRequestSuccess(..))")
public void intercept(ProceedingJoinPoint joinPoint){
System.out.println("call intercepted " + joinPoint);
try {
joinPoint.proceed();
} catch (Throwable e) {
System.out.println("wut");
}
}
}
I've added the aspectj weaver dependency: compile 'org.aspectj:aspectjweaver:1.8.6'
And it seems to work, at least the annotations are recognized by android studio.
I've placed a breakpoint on the "joinpoint.proceed()" call and started the application in debug mode.
But when I log in (an action that triggers one such listener) nothing happens. Am I missing something?
In Maven you would use AspectJ Maven Plugin (current version is 1.7), in Gradle something similar. This is what you need for compilation if you want to use CTW (compile-time weaving). Those plugins should already contain a dependency on aspectjtools.jar which contains the AspectJ compiler and other stuff. If you use CTW, you need aspectjrt.jar (AspectJ runtime) as a default-scoped (compile) or dependency because it is needed during runtime as well.
If you want to use load-time weaving (LTW), though, you need aspectjweaver.jar on your JVM command line via -javaagent:... because the weaving agent needs to hook into class-loading before your first application class is loaded. P.S.: The weaving agent also contains the AspectJ runtime classes, so you do not need an additional dependency on the runtime in this case.