Nashorn binding issue - javascript

I have a java class like below
public class StaticBean {
public static String returnString(int num){
String json = "[{\"name\" : \"John Doe\", \"age\" : 30}]";
return json;
}
}
In the below test, i have two engine instances.
Upon execution, i see that it is not possible to copy the bindings instance onto another and use it for execution in the same engine or different engine. Even if i do copy, the results doesn't match with the ones i get if i use the same engine/binding.
#Test
public void testParsingStringObjects() {
Bindings b = engine.createBindings();
b.put("ndb", getBindingObject(StaticBean.class, engine));
engine.setBindings(b, ScriptContext.ENGINE_SCOPE);
String source = "print('Definition in engine instance 1');"
+ "var SysU = {};\n"
+ "SysU.returnObject = function returnObjectJS(){\n"
+ "var string = ndb.returnString(1);\n"
+ "return JSON.parse(string);\n" + "}\n"
+ "SysU.returnString = function returnStringJS(){\n"
+ "var string = ndb.returnString(1);\n"
+ "print('String returned by the java function SysU.returnString() '+string);\n"
+ "return string;\n" + "};\n"
+ "print('====================Using the same engine instance for execution====================');\n"
+ "(function (){" + "var json = {};\n"
+ "print(\"String Returned in Caller SysU.returnString(): \"+SysU.returnString());\n"
+ "print(\"Object Returned in Caller SysU.returnObject(): \"+SysU.returnObject());\n"
+ "print(\"**Stringified Object Returned in Caller JSON.stringify(SysU.returnObject()): \"+JSON.stringify(SysU.returnObject()));\n"
+ "print('Adding the object in another ( json.ext = SysU.returnObject();) ...');\n"
+ "json.ext = SysU.returnObject();\n"
+ "print(\"Added JSON object which is stringified to display JSON.stringify(json): \"+JSON.stringify(json));\n" + "})();";
try {
engine.eval(source);
Bindings oldEngineBindings = engine.getBindings(ScriptContext.ENGINE_SCOPE);
Bindings localBindings = engine2.getBindings(ScriptContext.ENGINE_SCOPE);
Bindings newBindings = engine.createBindings();
oldEngineBindings.put("fileName","oldEngine");
localBindings.put("fileName","localEngine");
newBindings.putAll(oldEngineBindings);
newBindings.putAll(localBindings);
oldEngineBindings.putAll(localBindings);
ScriptContext ctxt = new SimpleScriptContext();
ctxt.setBindings(oldEngineBindings, ScriptContext.ENGINE_SCOPE);
engine.setContext(ctxt);
engine.eval(""
+ "print('====================Using the same engine with original binding ====================');\n"
+ "(function (){" + "var json = {};\n"
+ "print(\"String Returned in Caller SysU.returnString(): \"+SysU.returnString());\n"
+ "print(\"Object Returned in Caller SysU.returnObject(): \"+SysU.returnObject());\n"
+ "print(\"**Stringified Object Returned in Caller JSON.stringify(SysU.returnObject()): \"+JSON.stringify(SysU.returnObject()));\n"
+ "print('Adding the object in another ( json.ext = SysU.returnObject();) ...');\n"
+ "json.ext = SysU.returnObject();\n"
+ "print(\"Added JSON object which is stringified to display JSON.stringify(json): \"+JSON.stringify(json));\n" + "})();");
ctxt.setBindings(newBindings, ScriptContext.ENGINE_SCOPE);
engine.setContext(ctxt);
engine.eval(""
+ "print('====================Using the same engine with copied new binding ====================');\n"
+ "(function (){" + "var json = {};\n"
+ "print(\"String Returned in Caller SysU.returnString(): \"+SysU.returnString());\n"
+ "print(\"Object Returned in Caller SysU.returnObject(): \"+SysU.returnObject());\n"
+ "print(\"**Stringified Object Returned in Caller JSON.stringify(SysU.returnObject()): \"+JSON.stringify(SysU.returnObject()));\n"
+ "print('Adding the object in another ( json.ext = SysU.returnObject();) ...');\n"
+ "json.ext = SysU.returnObject();\n"
+ "print(\"Added JSON object which is stringified to display JSON.stringify(json): \"+JSON.stringify(json));\n" + "})();",newBindings);
ctxt.setBindings(oldEngineBindings, ScriptContext.ENGINE_SCOPE);
engine2.setContext(ctxt);
engine2.eval(""
+ "print('====================Using a different engine instance with original binding ====================');\n"
+ "(function (){" + "var json = {};\n"
+ "print(\"String Returned in Caller SysU.returnString(): \"+SysU.returnString());\n"
+ "print(\"Object Returned in Caller SysU.returnObject(): \"+SysU.returnObject());\n"
+ "print(\"**Stringified Object Returned in Caller JSON.stringify(SysU.returnObject()): \"+JSON.stringify(SysU.returnObject()));\n"
+ "print('Adding the object in another ( json.ext = SysU.returnObject();) ...');\n"
+ "json.ext = SysU.returnObject();\n"
+ "print(\"Added JSON object which is stringified to display JSON.stringify(json): \"+JSON.stringify(json));\n" + "})();");
} catch (ScriptException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Is this an accepted behavior? or a bug?. I should be able to copy the binding and use them in a different scope in the same engine or different engine instance and yield the same results.
I am testing on Java8u101
Results when you run the test. ReturnObject() function seems to fail when the bindings or the engine instance change.
Definition in engine instance 1
====================Using the same engine instance for execution====================
String returned by the java function SysU.returnString() [{"name" : "John Doe", "age" : 30}]
String Returned in Caller SysU.returnString(): [{"name" : "John Doe", "age" : 30}]
Object Returned in Caller SysU.returnObject(): [object Object]
**Stringified Object Returned in Caller JSON.stringify(SysU.returnObject()): [{"name":"John Doe","age":30}]
Adding the object in another ( json.ext = SysU.returnObject();) ...
Added JSON object which is stringified to display JSON.stringify(json): {"ext":[{"name":"John Doe","age":30}]}
====================Using the same engine with original binding ====================
String returned by the java function SysU.returnString() [{"name" : "John Doe", "age" : 30}]
String Returned in Caller SysU.returnString(): [{"name" : "John Doe", "age" : 30}]
Object Returned in Caller SysU.returnObject(): [object Object]
**Stringified Object Returned in Caller JSON.stringify(SysU.returnObject()): [{"name":"John Doe","age":30}]
Adding the object in another ( json.ext = SysU.returnObject();) ...
Added JSON object which is stringified to display JSON.stringify(json): {"ext":[{"name":"John Doe","age":30}]}
====================Using the same engine with copied new binding ====================
String returned by the java function SysU.returnString() [{"name" : "John Doe", "age" : 30}]
String Returned in Caller SysU.returnString(): [{"name" : "John Doe", "age" : 30}]
Object Returned in Caller SysU.returnObject(): [object Object]
**Stringified Object Returned in Caller JSON.stringify(SysU.returnObject()): undefined
Adding the object in another ( json.ext = SysU.returnObject();) ...
Added JSON object which is stringified to display JSON.stringify(json): {}
====================Using a different engine instance with original binding ====================
String returned by the java function SysU.returnString() [{"name" : "John Doe", "age" : 30}]
String Returned in Caller SysU.returnString(): [{"name" : "John Doe", "age" : 30}]
Object Returned in Caller SysU.returnObject(): [object Object]
**Stringified Object Returned in Caller JSON.stringify(SysU.returnObject()): undefined
Adding the object in another ( json.ext = SysU.returnObject();) ...
Added JSON object which is stringified to display JSON.stringify(json): {}
EDIT :-
Found this thread https://bugs.openjdk.java.net/browse/JDK-8067642 . This mentions something about foreign objects being instances of ScriptObjectMirror . I used the typeof operator to display the type of object returned in the cases that failed and succeeded and both times they were ScriptObjectMirror but the stringify works as expected if i use the original bindings object in the context.
EDIT 2:-
Added a very simple test to demonstrate the above. Kinda like a TLDR for the above :) . Executing the below demonstrates that putAll() on a bindings object does not work as we expect it to.
#Test
public void testParsingObjects() throws ScriptException {
String source = "var Func = {};\n"
+ "Func.getJavaScriptObject = function(){"
+ "var jsString = '{\"foo\":\"bar\"}';\n"
+ "return JSON.parse(jsString);"
+ "};";
String executor = "(function(){ "
+ "var obj = Func.getJavaScriptObject();"
+ "print(JSON.stringify(obj));"
+ " })();";
System.out.println("Executing source...");
engine.eval(source);
System.out.println("\nUsing the same binding instance and engine\n");
engine.eval(executor);
Bindings originalBinding = engine.getBindings(ScriptContext.ENGINE_SCOPE);
Bindings copiedBinding = engine.createBindings();
copiedBinding.putAll(originalBinding);
System.out.println("\nUsing the copied binding instance and engine\n");
engine.eval(executor,copiedBinding);
}
Result of execution.
Executing source...
Using the same binding instance and engine
{"foo":"bar"}
Using the copied binding instance and engine
undefined

Here is the code I am using the share compiled JavaScript code between ScriptContext instances used by different threads. The main benefit here is only compiling the code once, although I also benefit from not needing to stream the code from the REST API multiple times. I did not include the REST part for brevity.
import javax.script.CompiledScript;
import javax.script.ScriptContext;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import javax.script.SimpleScriptContext;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.ExecutionException;
import java.util.ArrayList;
import java.util.List;
public class ContextDemo {
static CompiledScript codeLib;
static ScriptEngine engine;
static ScriptContext context;
static List <Future<String>> taskResults;
static ExecutorService executor;
static List <Callable<String>> tasks = new ArrayList<Callable<String>> ();
public static void main(String[] args) {
try {
// Initialize workers and execute
run(4);
} catch(InterruptedException | ExecutionException | ScriptException e) {
System.out.println(e.getMessage());
}
}
static void run(int workers) throws InterruptedException, ExecutionException, ScriptException {
// Initialize engine and initial context
engine = new ScriptEngineManager().getEngineByName("nashorn");
context = new SimpleScriptContext();
engine.setContext(context);
// Compile a JavaScript object with a function
codeLib = ((javax.script.Compilable)engine).compile("var lib = { func1: function(n, s) { return 'thread number ' + n + ': ' + s; } };");
// Create executor with specified number of workers
executor = Executors.newFixedThreadPool((int)workers);
for (int i = 0; i < workers; i++) {
tasks.add(workerLambda(i));
}
// Invoke worker pool
taskResults = executor.invokeAll(tasks);
// Iterate futures list and report results
for (int i = 0; i < workers; i++) {
Future < String > f = taskResults.get(i);
if (f.isDone()) {
System.out.println(f.get());
} else {
System.out.println("Thread " + i + " not done");
}
}
// Shutdown the executor
executor.shutdown();
}
static Callable <String> workerLambda(int n) {
int workerNum = n;
// Thread-specific script context initialization
SimpleScriptContext threadContext = new SimpleScriptContext();
threadContext.setBindings(engine.createBindings(), ScriptContext.ENGINE_SCOPE);
try {
// Inject compiled code library into thread-specific ScriptContext
codeLib.eval(threadContext);
} catch (ScriptException e1) {
System.out.println(e1.getMessage());
}
// Return the lambda
return () -> {
// Call the injected object method and return the result
return (String)engine.eval("lib.func1(" + workerNum + ", 'Hello!');", threadContext);
};
}
}
This outputs:
thread number 0: Hello!
thread number 1: Hello!
thread number 2: Hello!
thread number 3: Hello!

I wish I could provide a working solution to this, but I am suspecting it may be a Nashorn bug. As evidence, I submit this link to an old JDK bug:
https://bugs.openjdk.java.net/browse/JDK-8023363
Test.java (below) is provided in the link as evidence that both issues (lack of key presence in Map and inability to execute function after .putAll() into new Bindings) are "Not an Issue". Except that I tested the same code and got different results:
The original Bindings only seems to contain the key "nashorn.global", even after the eval
Attempts to execute "func(x)" using the new Bindings (after putAll()) throws a Reference error
Test.java follows:
import javax.script.*;
import java.util.Map;
public class Test {
public static void main(String[] args) throws Exception {
ScriptEngineManager m = new ScriptEngineManager();
ScriptEngine scriptEngine = m.getEngineByName("nashorn");
Bindings engineBindings = scriptEngine.getBindings(ScriptContext.ENGINE_SCOPE);
scriptEngine.eval("function func(x) { print('I am func ' + x); }");
// print stuff exposed in engineBindings
for (Map.Entry<?,?> entry : engineBindings.entrySet()) {
System.out.println(entry.getKey());
System.out.println(entry.getValue());
}
Bindings localBindings = scriptEngine.createBindings();
// copy all exposed from other bindings
localBindings.putAll(engineBindings);
// put additional variable
localBindings.put("event", new Object());
scriptEngine.setBindings(localBindings, ScriptContext.ENGINE_SCOPE);
scriptEngine.eval("func(event)");
}
}

Related

Passing Javascript object throught JavascriptInterface to Android application [duplicate]

Is it possible to pass a JavaScript object from JavaScript to Java using addJavascriptInterface()? Something along these lines:
var javaScriptObject = {"field1":"string1", "field2":"string2"};
JavaScriptInterface.passObject(javaScriptObject);
How would such a call be captured on the Java side? I have no problem setting up the interface to send a string, but when I send an object, I receive null on the Java end.
AFAIK, addJavascriptInterface() only works with primitive types and Strings, and so you cannot pass arbitrary Javascript objects.
This is how I am doing...
In Android...
#JavascriptInterface
public void getJSONTData(String jsonData) {
try {
JSONObject data = new JSONObject(jsonData); //Convert from string to object, can also use JSONArray
} catch (Exception ex) {}
}
In JavaScript...
var obj = { Name : 'Tejasvi', Age: 100};
var str = JSON.stringify(obj);
Android.getJSONTData(str);
As of now, I could not find any other proper way to pass the native JavaScript object directly to JavascriptInterface.
Calling Android.getJSONTData({ Name : 'Tejasvi', Age: 100}) results in null (if parameter type is Object) or undefined (if parameter type is defined as String) in getJSONTData.
I found a solution, using JSON. My Java method returns a JSONArray, on my javascript code I receive this and convert to a javascript vector using JSON.parse(). See the example:
Java:
public class JavaScriptInterface {
Context mContext;
private static int ind=-1;
private static int [] val = { 25, 25, 50, 30, 40, 30, 30, 5, 9 };
public JavaScriptInterface(Context c) {
mContext = c;
}
#JavascriptInterface
public JSONArray getChartData() {
String texto = " [ {name: 'valor1', 2007: "+val[(++ind)%9]+"}, "+
" {name: 'valor2', 2007: "+val[(++ind)%9]+"}, "+
" {name: 'valor3', 2007: "+val[(++ind)%9]+"} ]";
JSONArray jsonar=null;
try {
jsonar = new JSONArray(texto);
} catch (JSONException e) {
e.printStackTrace();
}
return jsonar;
}
}
Now the javascript code:
window.generateData = function() {
/*var data = [ {name: 'valor1', 2007: 50},
{name: 'valor2', 2007: 20},
{name: 'valor3', 2007: 30} ]; */
var data = JSON.parse( Android.getChartData() );
return data;
};
The commented code above show how it was when static, and now the data came from the Java code.
It was testes on Android 2.1 and 3.2.
I can run this feature
In Javascript :
var data = {
'username' : $('#username').val().trim(),
'password' : $('#password').val().trim(),
'dns' : $('#dns').val().trim()
}
var str = JSON.stringify(data);
Native.getLoginService(str);
In Android :
#JavascriptInterface
public void getLoginService(String jsonData){
try{
JSONObject data = new JSONObject(jsonData);
String username = data.getString("username");
String password = data.getString("password");
String dns = data.getString("dns");
Log.i("TAG",username + " - " + password + " - " + dns);
}catch (Exception ex){
Log.i("TAG","error : " + ex);
}
}
Good luck with...
I think you can also pass JSONObject and JSONArray. So not only primitive types, but also primitive types stored in a javascript array [0,1,2] or dictionary {one:1, two:2}.
I have NOT verified this in code, just read the docs. Might be using it soon.
You can't pass JSONObject or JSONArray, but you can send strings with that form and parse them to those types.
Your option is to expose the method using strings and then you can use the JSONObject or JSONArray to parse the string and use it accordingly.
Here is what I did.
#JavascriptInterface
public void passJSON(String array, String jsonObj) throws JSONException
{
JSONArray myArray = new JSONArray(array);
JSONObject myObj = new JSONObject(jsonObj);
...
}
where array is '["string1","string2"]' and jsonObj is '{attr:1, attr2:"myName"}'

Pass 2 arguments in Handler javascript function in codebehind

I am trying to pass 2 parameters in Handler call in codebehind but I can't get it to work. Here is my code:
X.Msg.Confirm("Confirm", "The field has " + dependency.Count() + " dependent fields. Are you sure you want to proceed? (The dependent fields will be deleted also)", new MessageBoxButtonsConfig
{
Yes = new MessageBoxButtonConfig
{
Handler = "App.direct.UC.DoYesDeleteDepField('" + fieldname + "," + dependency + "')", //ERROR LINE
Text = "Yes"
},
No = new MessageBoxButtonConfig
{
Handler = "",
Text = "No"
}
}).Show();
Error:
System.ArgumentException: DirectMethod: 'DoYesDeleteDepField', The parameter 'dep' is undefined at Ext.Net.DirectMethod.Invoke(Object target, HttpContext context, ParameterCollection args) at Ext.Net.DirectMethod.Invoke(Object target, ParameterCollection args) at Ext.Net.ResourceManager.RaisePostBackEvent(String eventArgument)
[DirectMethod]
public void DoYesDeleteDepField<T>(string fieldname, List<MyDependenciesClass> dep)
{....
You are passing:
App.direct.UC.DoYesDeleteDepField('fieldname,dependency')
the way you written it.
To pass this:
App.direct.UC.DoYesDeleteDepField('fieldname', 'dependency')
you should draw the line like this:
"App.direct.UC.DoYesDeleteDepField('" + fieldname + "', '" + dependency + "')"
For further information on this answer: the initial parameters were being read as a string, thus the javascript threw 'undefined'.
The solution works due to String Concatenation, which is a very important concept on OOP.
For more on string concatenation consult: How to Concatenate Multiple Strings (C# Programming Guide)

Setting setRequestBody for Rest web services using Post method

Hi I'm trying to create a rest response using post method, I want to dynamically pass the variables instead of hard coding,But where i fail is,when I'm trying to to send an array as a parameter to the Rest web service using post method(example array ["CN=XXX_XX,OU=XXXXX,OU=1_XXXX XXXXity Groups,DC=XXXX,DC=local"]) and I know that there is a better way to do that Please find my code sample.This is the method that gives me a appropriate result.
First Method:(Works)
`
try {
var r = new sn_ws.RESTMessageV2('SailPoint_IdM', 'post');
var txt = "{\r\n\t\"workflowArgs\":\r\n\t{\r\n\t\"identityName\":\"SiamR\",\r\n\t\"appName\":\"Active Directory\",\r\n\t\"listEntitlements\":[\"CN=ER_CxxxK,OU=xxxxx,OU=1_xxxxxx Security xxx,DC=xxxx,DC=local\"],\r\n\t\"operation\":\"Add\",\r\n\t\"ticketNumber\":\"RITM1234567\"\r\n\t}\r\n}";
r.setRequestBody(txt);
var response = r.execute();
var ResponseBody = response.getBody();
var HTTPCode = response.getStatusCode();
gs.log(ResponseBody);
gs.log(HTTPCode);
} catch (ex) {
var message = ex.getMessage();
}
output:
Script: {"attributes":{"requestResult":{"status":"Success"}},"complete":false,"errors":null,"failure":false,"metaData":null,"requestID":"2c988d8c5bd47cf7015bebfb64cf01e6","retry":false,"retryWait":0,"status":null,"success":false,"warnings":null}
Script: 200
2n Method (Does not Work):
try {
var r = new sn_ws.RESTMessageV2('SailPoint_IdM', 'post');
r.setStringParameter('"listEntitlements"', '["CN=Exxx_xxxK,OU=xxxxion,OU=1_xxxxx Security xxxx,DC=xxx,DC=xxxx"]');
r.setStringParameter('"identityName"', '"SiarmR"');
r.setStringParameter('"appName"', '"Active Directory"');
r.setStringParameter('"ticketNumber"', '"RITM1234567"');
r.setStringParameter('operation', '"Add"');
//override authentication profile
//authentication type ='basic'/ 'oauth2'
//r.setAuthentication(authentication type, profile name);
var response = r.execute();
var responseBody = response.getBody();
var httpStatus = response.getStatusCode();
gs.log(responseBody );
}
catch(ex) {
var message = ex.getMessage();
}
output:
Script: {"attributes":{"requestResult":{"errors":["An unexpected error occurred: sailpoint.tools.GeneralException: The application script threw an exception: java.lang.NullPointerException: Null Pointer in Method Invocation BSF info: script at line: 0 column: columnNo"],"status":"FAIL","GroupStatus":null,"AppStatus":null}},"complete":false,"errors":["Status : failed\nAn unexpected error occurred: sailpoint.tools.GeneralException: The application script threw an exception: java.lang.NullPointerException: Null Pointer in Method Invocation BSF info: script at line: 0 column: columnNo\n"],"failure":false,"metaData":null,"requestID":null,"retry":false,"retryWait":0,"status":null,"success":false,"warnings":null}
Script: 200
Im facing issue with this parameter as im trying to pass this as aray paramenter '["CN=Exxx_xxxK,OU=xxxxion,OU=1_xxxxx Security xxxx,DC=xxx,DC=xxxx"]'
Please suggest a way to implement this and to pass all the variables dynamically if suggesting first method
Below is one of my function, to handle dynamic parameters in either appear in request endpoint (url), headers or body;
For eg: parameter p
var p = {abc: 'def'};
and outbuond rest settings:
rest url = https://xxxx.sss.com/api/showme?name=${abc}
rest headers name = custom-header; value = ${abc}
rest body = {name: "${abc}"}
so it will replace all ${abc} to 'def'
_.isNullOrEmpty - check is obj, string or array is null or empty;
_.loop - loop an obj or array, pass in function(nm/i, val) {}
_.isArray - to check if is array
_.str - convert anything to string
_.rpl - replace all string A to B
restParameters: function (restRequest, obj, endpoint) {
var _ = this;
if ((_.isNullOrEmpty(restRequest)) || (_.isNullOrEmpty(obj))) return;
if (_.isNullOrEmpty(endpoint)) endpoint = restRequest.getEndpoint();
var body = restRequest.getRequestBody();
var headers = restRequest.getRequestHeaders();
_.loop(obj, function(nm, val) {
if (_.isArray(val)) {
val = (_.isNullOrEmpty(val)) ? '[]' : JSON.stringify(val);
} else val = _.str(val);
//for my case my array pass in as string become: "[\"1\", \"2\"]"
//comment below if pass in as object
if (val.contains('"')) val = _.rpl(val, '"', '\\"');
restRequest.setStringParameterNoEscape(nm, val);
var sch = '${' + nm + '}';
endpoint = _.rpl(endpoint, sch, val);
body = _.rpl(body, sch, val);
_.loop(headers, function (hn, hv) {
headers[hn] = _.rpl(hv, sch, val);
});
}, true);
restRequest.setEndpoint(endpoint);
restRequest.setRequestBody(body);
_.loop(headers, function (hn, hv) { restRequest.setRequestHeader(hn, hv); });
}

Using third party js libraries with Jint

I'm working on a feature where user defined, anonymous, javascript functions retrieved from a database need to be executed server side in the context of ASP.Net application.
I'm evaluating Jint for this purpose (Latest version from NuGet). I have been able to run functions that do basic operations and return values without an issue as below.
public void Do()
{
var jint = new Engine();
var add = jint.Execute(#"var f = " + GetJsFunction()).GetValue("f");
var value = add.Invoke(5, 4);
Console.Write("Result: " + value);
}
private string GetJsFunction()
{
return "function (x,y) {" +
" return x+y;" +
"}";
}
My question is whether Jint facilitates the execution of javascript functions which uses third party libraries like lodash? If so, how would I go about making the Jint engine aware of it (i.e third party library)?
An example would be the execution of following function.
private string GetFunction()
{
return "function (valueJson) { " +
" var value = JSON.parse(valueJson);" +
" var poi = _.find(value,{'Name' : 'Mike'});" +
" return poi; " +
"}";
}
Thanks a lot in advance.
I think I have figured this out. It's no different to executing a custom function. You just read the third party library from a file (project resource) and invoke execute on Jint engine. See below;
private void ImportLibrary(Engine jint, string file)
{
const string prefix = "JintApp.Lib."; //Project location where libraries like lodash are located
var assembly = Assembly.GetExecutingAssembly();
var scriptPath = prefix + file; //file is the name of the library file
using (var stream = assembly.GetManifestResourceStream(scriptPath))
{
if (stream != null)
{
using (var sr = new StreamReader(stream))
{
var source = sr.ReadToEnd();
jint.Execute(source);
}
}
}
}
We can call this function for all the third party libraries that needs to be added.

Passing json object from Android/iOS native to javascript

Is there any way to pass JSONObject from android to javascript. We are using WebView.evaluateJavascript mehtod and are able to send only String type object. In JS if we are checking the method paramter;s typeof(data) then it is displaying as string but in iOS it displays typeof(data) as OBJECT.
In both android and iOS we are passing String and NSString.
JS method is:
response: function(id, err, data) {
var dataObj;
if(typeof(data) == 'string' ){
dataObj = JSON.parse(data || '{}');
}
}
Android call:
String responseStr = "{\"ok\":\"ok\"}";
String nativeToWebMethod = "javascript:window.nativeService.response("1",'','"+responseStr+"')";
webView.evaluateJavascript(nativeToWebMethod, null);
Just send it as if you were loading a url:
private void loadJS(String jsonResponse){
mWebView.loadUrl("javascript:" + "(function(){" + "yourJsMethodName" + "(" +jsonResponse + ");" + "})()");
}
This will execute a JS Code that will call a function called yourJsMethodName and will pass the JSON as parameter.
Consider execute the last code in the Main Thread
I find out the issue, it was in the way I was sending data:
String nativeToWebMethod = "javascript:window.nativeService.response("1",'','"+responseStr+"')";
should be replaced with
String nativeToWebMethod = "javascript:window.nativeService.response("1",'',"+responseStr+")";
removed single quote around the responseStr.

Categories

Resources