Android-runtime: Annotations for android

Created on 3 Aug 2015  路  7Comments  路  Source: NativeScript/android-runtime

_From @Alphapage on July 9, 2015 20:7_

Hello,

I use a webview and I want to show a toast between two html pages to inform the user about an action.
With java, you need to add @javascriptInterface annotation to enable the function.

How can I do with Nativescript for android ?

Thanks in advance for your help.

_Copied from original issue: NativeScript/NativeScript#414_

low feature

All 7 comments

You should use the WebView events loadStartedEvent, loadFinishedEvent (http://docs.nativescript.org/ApiReference/ui/web-view/WebView.html)

and then use the Toast class of Android framework to show the message
https://developer.android.com/guide/topics/ui/notifiers/toasts.html

@enchev @Alphapage

_Feedback needed_

I did a working prototype that allows you to specify Java annotations from JavaScript. Let's see the concrete scenario. We want to call NativeScript from a WebView control using addJavascriptInterface method. To accomplish this we need three things

  1. Create a new class :white_check_mark:
  2. Provide a public method :x:
  3. Decorate the method with the proper annotations :x:

NativeScript runtime can already create new types via extend function. That's we can subclass a Java class in JavaScript. For example

var MyObject = java.lang.Object.extend({
   hashCode: function() {
      return 123;
   },
   sayHello: function() {
      return "Hello!";
   }
});

Basically, this will create a Java proxy class similar the to following one:

public class MyObject extends java.lang.Object {
   public int hashCode() {
      return (int)com.tns.Platform.callJSMethod(this, "hashCode", null);
   }
}

However, the generated Java proxy will declare only the methods what are overwritten in JavaScript (so it can pass the control flow). Thus the generated Java proxy will not expose sayHello method.

I added one more parameter to the current extend syntax in the following way.

var MyObject = java.lang.Object.extend("MyObject", {
   hashCode: function() {
      return 123;
   },
   sayHello: function() {
      return "Hello!";
   }
}, {
      annotations: [ /* list of annotations that will be applied on MyObject class */ ],
      exposedMethods: [ /* list of JavaScript methods that will be exposed in Java proxy class */ ]
});

In order to define a Java method all we need is it's signature. For the purpose of this prototype I use the standard JNI notation which is well known among the Java developers and widely used by Java tools. In our case we can encode sayHello methods as

var exposedMethod = { "signature": "sayHello()Ljava/lang/String;" }

In order to apply the corresponding Java annotations we can add annotations property as follows

var exposedMethod = { 
   "signature": "sayHello()Ljava/lang/String;" },
   "annotations": [ /* list of annotations applied on sayHello method */ ]
};

We can use a single annotation format for both class and method annotation scenarios. Basically, to describe an annotation we need its name and its parameters if any. I selected the following annotation format

var annotation = {
   "className": <JNI string for the annotation class>
   "props": [ /* array or key/values */]
};

In our case, we can full describe sayHello method as follows

var jsiAnnotation = { "className":"Landroid/webkit/JavascriptInterface;", "props":[] };
var MyObject = java.lang.Object.extend("WebViewInterOp", {
      sayHello: function() {
         return "Hello NativeScript (extended in JavaScript)!";
      }
   }, {
      "annotations": [ /* list class annotations */ ],
      "exposedMethods": [ { "signature": "sayHello()Ljava/lang/String;", "annotations": [ jsiAnnotation ] } ]
   });

In TypeScript, we can use decorators in order to make the syntax more succinct

class MyObject extends java.lang.Object {
   constructor() {
      super();
      return __native(this);
   }
   hashCode() {
      return 123;
   }
   @ExposeWithSignature("sayHello()Ljava/lang/String;", [ { "className": "Landroid/webkit/JavascriptInterface;", "props": [] }])
   sayHello(): string {
      return "Hello NativeScript (extended in TypeScript)!"
   }
}

Here we use a single ExposeWithSignature decorator that follows the same pattern

@ExposeWithSignature("sayHello()Ljava/lang/String;", [ { "className": "Landroid/webkit/JavascriptInterface;", "props": [] }])

The transpiled code will be the same as in the JavaScript case.

The current prototype does not implement setting annotation properties though the infrastructure is already in place. Also, at the moment all annotations are treated as visible to the Java runtime though this also can be configuration option.

This is the first iteration for the feature and the suggested syntax is not set in stone so please feel free to comment and propose other options.

we're closing this because of the lack in interest, but don't hesitate to drop us a line and we'll open the issue, if it's still relevant.

Can we open this issue, looks I saw good prototype that can work, if it is not that hard to add, it will be great addition, as main compelling reason to use Nativescript over others others, is that it is the least one requiring playing with native platform eclipse or xcode so if it is possible now that we got version 5.0 it will be nice addition

@AhmedAzzabi what is your scenario?

In case your scenario is WebView/NativeScript integration, I would suggest to avoid it and think about other options if possible. While such integration is possible, it comes with a cumbersome memory model and you have to think about the life of the involved JS objects. As you can see for the last 3 years there were no requests for this functionality and it makes sense to focus on other tasks. In case your scenario is critical, I would suggest to use com.tns.Platform.callJSMethod(..) and write the Java proxies yourself even though it is not an elegant solution.

P.S. I am no longer with Telerik and NativeScript team so take my comment as a personal opinion.

I agree looks an edge case, I'm interested what other alternatives you would suggest for webview/nativescript, here is my scenario: my app get some data from websites but these websites use javascript so content can't be obtained by using http.getString, I need to emulate browser, for now I'm using plugin webview interface but just wondering if there are alternatives

Hello guys,
How can I use Android Annotations from NativeScript? like this: http://greenrobot.org/files/eventbus/javadoc/3.0/ (Annotation Type Subscribe)
For example, within an extended class of java.lang.Object

Any help is really appreciated!

Was this page helpful?
0 / 5 - 0 ratings

Related issues

Plamen5kov picture Plamen5kov  路  4Comments

Natalia-Hristova picture Natalia-Hristova  路  3Comments

x4080 picture x4080  路  5Comments

m-abs picture m-abs  路  3Comments

NathanaelA picture NathanaelA  路  3Comments