I have business logic that is written in JavaScript, this code is shared with other non-android apps.
What is the best way to use the functions in this piece of JavaScript from within a Service in Android.
AFAIK, there are 2 options?
V8 that is built into the standard WebView and superfast, no extra apk bloat.
Rhino, which is tricky to get going on Android?
Focusing on V8/Webview, when I attempt to access the WebView, with any function, I get;
All WebView methods must be called on the UI thread. Future versions of WebView may not support use on other threads.
The warning being noted, it doesn't even work now. When I set the webviewclient up, I get nothing after loading an URL.
My question is in 3 parts;
1) Has anyone had any success with running javascript in a webview without a UI thread?
2) How do I get results from the functions inside the javascript, does the webview interface "addJavascriptInterface " support loading a parameter and sending it back to the java?
3) If either of the above are impossible.. I guess I'll go get Rhino, any tips would be appreciated, I've only seen a few blogs complaining of issues with regards to getting it going on Android and wondering if there is a "go to" version for android maintained somewhere.
Couldn't find anything with regards to V8 from deep down in a service.
Ended up using Rhino, however a word of warning to anyone following down my footsteps, it's incredibly slow.
Just grab the jar from the official latest distribution of Rhino from
https://developer.mozilla.org/en-US/docs/Rhino/Download_Rhino?redirectlocale=en-US&redirectslug=RhinoDownload
js.jar is what you need in the zip. js-14 is a bigger java 1.4 compatible version you don't need.
Integration was a snap just chuck the jar into your libs folder.
Below is me scraping a webpage using javascript (turning the data into better formatted json). With the parse.js script I made coming from the assets folder.
Rhino doesn't come with DOM, and env.js crashes out with stackoverflow errors. Overall, I'd say this solution is slow and not well supported...
public static void sync(Context context, ){
String url = BASE_URL;
String html = Utils.inputStreamToString(Utils.getHTTPStream(url));
timeList.add(System.currentTimeMillis());
if(html == null){
Utils.logw("Could not get board list.");
return;
}
String parsingCode = null;
try {
parsingCode = Utils.inputStreamToString(context.getAssets().open("parse.js"));
} catch (IOException e) {
Utils.logw("Could not get board parser js");
return;
}
// Create an execution environment.
org.mozilla.javascript.Context cx = org.mozilla.javascript.Context.enter();
// Turn compilation off.
cx.setOptimizationLevel(-1);
try {
// Initialize a variable scope with bindnings for
// standard objects (Object, Function, etc.)
Scriptable scope = cx.initStandardObjects();
ScriptableObject.putProperty(
scope, "html", org.mozilla.javascript.Context.javaToJS(html, scope));
//load up the function
cx.evaluateString(scope, parsingCode,"parseFunction", 1 , null);
// Evaluate the script.
Object result = cx.evaluateString(scope, "myFunction()", "doit:", 1, null);
JSONArray jsonArray = new JSONArray(result.toString());
Related
I am sorry if this is an unclear title because I do not know all the terminology, so please bear with me.
So I am trying to create a controlled environment to run any JavaScript code in a Java application. Note: code is created by a user so I have to block/prevent code that is specifically trying to access/modify java variables that are not supposed to be at reach. (preferably by throwing a compile error for user feedback)
Edit 1: By the way I tried to use Rhino and Nashorn.
Here is a simple example.
public class ScriptRunner{
public Foo foo=new Foo();
//this is not supposed to be accessed by the script
public int money=0;
public Object run(){
return compiler.compile(STRING START (obtained from a file)
function main(someObject){
//this is not allowed
someObject.money=10000000000000000000000;
//or this
var someBlacklistedJavaObject=.....
someBlacklistedJavaObject.someFuncton();
//but this is allowed
someObject.foo.name="Bob";
return someObject.foo.someFunction();
}
STRING END).run("main",this);
}
}
Also I am not sure if this would be one of the possible solution but I can't use the built in java security class due to some unreachable code implementing it and not allowing to set the security object to anything else.
What comes to my mind is that an easy implementation of this would be to create wrapper Java classes in some package. Than check if a java object in script does not have that path and throw an error. But the problem is that I have no idea how to do that.
Here is a simple visualization of what I am trying to do.
Edit 2: It is desirable to maintain a low Java compatibility profile, but it's not 100% necessary.
Use a ClassFilter with Nashorn (note: requires Java >= 1.8.0_40)
I just started playing around with Windows Dev and please pardon me if this issue does not seem logical or legit to you.
I am trying these Chakra Host samples on Microsoft GitHub and when input js cond like console.log or alert, I get error like 'console' is undefined. Am I missing something obvious. I tried looking up but unfortunately could not find the relevant docs or code sample.
Any help/pointer is appreciated.
The console is a web browser (and Node) feature. It doesn't exist within JavaScript. So, you need to add it (or something similar).
There's an example in the Win32 Edge/Chakra host code on Github that demonstrates how to add a callback function to the global namespace.
Example callback for Echo
You should be able to do something similar. You can also expose existing Windows runtime namespaces to Chakra.
private static void DefineHostCallback(JavaScriptValue globalObject, string callbackName, JavaScriptNativeFunction callback, IntPtr callbackData)
{
var propertyId = JavaScriptPropertyId.FromString(callbackName);
// Create a function
var function = JavaScriptValue.CreateFunction(callback, callbackData);
// Set the property
globalObject.SetProperty(propertyId, function, true);
}
I'm new to JavaScript environment and it's the one running on the system i'm newly at.
We're using GWT for JavaScript.
What is the best way to detect the connections between the back-end processes
and front-end actions? Eg. which back-end method is invoked when "that" button is pressed, tab is clicked,
window is opened, ... .
The only way I can think of is using the debugger and Eclipse search/call hierarchies facilities: keep putting breakpoints
in places where I anticipate will run-- until i hit the spot.
Is/n't there a more efficient way of doing this?
How do other developers do?
I'm a back-end developer.
In a previous system, I put a port monitor-- Fiddler,
saw the contents of the request the FE is sending and went from there.
I'm aware that this is a naive Q-- please bear with me.
TIA.
//======================
EDIT:
the best would be a
debugger-like tool showing the stack-trace, or even the
execution path in any way, telling the back-end methods that are running and/or spawning the threads.
is there such a tool?
The following takes for granted that you are using a decent IDE and that you have imported the GWT project into such IDE. There's some help at the end if this is not your case.
If you know which Java class contains the front-end logic, and the element you're interested in
Find the object representing the element (a Button, a ListBox, whatever) and look at the event handlers attached to it.
Something like this:
//...
#UiField
ListBox myDropDownList;
//...
myDropDownList.addChangeHandler(new ChangeHandler() {
#Override
public void onChange(ChangeEvent changeEvent) {
SomeService.someRPCmethod(... params, callback, ...);
}
});
The SomeService.someRPCmethod method implementation should contain all the backend calls.
If you know the Java class, but not which one of all the buttons is the one you're looking for
Most GWT apps make use of *.ui.xml files which are like a skeleton for the actual web page. This XML files reference the actual Java objects used in the Java class, and are usually named like the class they represent.
Locate the ui.xml file and look for something like this:
...
<g:ListBox ui:field="myDropDownList" styleName="cssClassName"/>
...
This should appear in your webpage like this:
<select class="cssClassName" ...>
<option ...>
The position inside the XML file, and the CSS class name, should help you pinpoint the element you're looking for. Once you find it, the ui:field attribute points to the Java object (try ctrl+clicking it in your IDE).
Now you just have to look at the handlers as explained before.
If you don't know the Java class which contains the front-end logic
To find the Java class for a given webpage, you can resort to the good ol' string search.
Locate a not-so-common string literal used in the web page. Not something like "Add" but more like "User registration".
Use your IDE to search the project's code base for that string. It should appear inside a .properties file, or a class with constants and literals, or maybe even hardcoded inside the front-end Java class.
Now just use your IDE to follow the references. It might be something like .properties file -> Constants interface -> .ui.xml file -> front-end Java class, or literals Java class -> front-end Java class.
If you don't have access to the front-end source code
You can try to use your Developer Tools / Fiddler to look for REST calls, which is how GWT implements RPC.
So the call to SomeService.someRPCmethod above might appear in Fiddler as a http:://yourwebpage/somepath/SomeService call with a bunch of GET/POST parameters, one of which should be someRPCmethod (the method's name). But this is not always the case.
If you're running GWT 2.6+ in SuperDev mode with Sources enabled, you can also try to debug the Javascript in the front-end until you reach the RPC calls. See abhinav3414's answer.
Last (or maybe first!) resource
Ask the front-end developers, they put the calls in there and can get you on track in minutes ;)
I had similar issue, so I installed an extension in my chrome.Below is the name of the extension. You can try once.
Visual Event 2.1
Know what event is bound on each dom element
There is one more approach, You can debug your code from front end. You can inspect element in your browser and then open Source tab.
Press ctrl + P to search the file in which you want to put the debug points.
Put debug points by clicking on the row number.
This way you need not to go to eclipse that often.
I would start by searching the code for the listeners of whatever events you are interested in and go from there. I work in EXT JS and I do this all the time.
Following all code paths through is the only guarantee unless all calls to the backend go through some known class.
Monitoring the network is also a good way to go.
This can be done in Chrome through the "Developer Tools" on the Network tab.
In GWT you have on the client side "import java.util.logging.Logger;" which output your debug info to the browsers console. On the server side you just use "System.out.println("debug");" for debugging which goes to the Apaches Tomcat log files. Which makes debugging on a live server a bit easier.
GWT uses RPC's for communication between the client and server. The data sent is serialized and can be a whole class if needed. The three folder for source in a module as 'client', 'server' and 'shared'.
For example a shared class used for sending data back and forth: (The blank constructor is required to serialise the class)
public class MySharedData implements Serializable {
private static final long serialVersionUID = 1987236748763652L; // used for serializing data
public List<String> lotsOfStrings = new ArrayList<String>(); // use most java vars
public int width, height;
public MySharedData() {} // 'need' a blank constructor
public MySharedData(MySharedData data) { //do stuff } // also can
}
On the server side it may look something like this:
public class MyServerRPCImpl extends RemoteServiceServlet implements MyServerRPC {
private static final long serialVersionUID = 4435555929902374350L;
public List<String> getStringList(int var, List<String> strs) {
// do stuff
System.out.println("debugging output"); // to tomcat log file
return stringList;
}
}
The client will use an Asynchronous callback with two methods, onSuccess() and onFailure() so you can handle call failures. To use this is something along the lines of:
public class MyGWTApp implements EntryPoint {
// the server RPC class
final MyServerRPCAsync server = GWT.create(MyServerRPC.class); // create RPC instance
final Logger log = Logger.getLogger("tag");
public void doSomething() {
MySharedData data = new MySharedData();
server.getStringList(data, new AsyncCallback<List<String>>() {
#Override
public void onFailure(Throwable caught) {
log.info("error"); // logging goes to the javascript console output
}
#Override
public void onSuccess(List<String> result) {
log.info("call worked");
}
};)
}
}
The above is my way of managing logging as my projects have to run straight from a Tomcat server. I also believe the server logging when run from Eclipse will go to Eclipse's console log, but I'm unsure on that. All server output and errors, including stack traces will be in the /var/log/tomcat/ folder on linux, or the equivalent on Windows. I can honestly say, I've yet not used breakpoints debugging with GWT.
Client and server code is in separate classes in their own folders within the project.
Just want to mention that sometimes debugger is used in situations where other tools can also help (not sure if this is the situation here - but bear with me just another two sentences):
(1) you can grep the relevant html asset , grep is a wonderful tool to learn large systems
(2) you can add log , in some cases you can switch to debug mode and see tons of log traces
Use Network tab in developer tools of your preferred browser you are using to test.
CHROME
Press F12 or alternatively choose from menu - tools > developer tools
FIREFOX
Press F12 or alternatively choose from menu - Developer > toggle tools
IE
Press F12
Well here's a problem.
I've got a website with large javascript backend. This backend talks to a server over a socket with a socket bridge using http://blog.deconcept.com/swfobject/
The socket "bridge" is a Flex/Flash .swf application/executable/plugin/thing for which the source is missing.
I've got to change it.
More facts:
file appExePluginThing.swf
appExePluginThing.swf Macromedia Flash data (compressed), version 9
I've used https://www.free-decompiler.com/flash/ to decompile the .swf file and I think I've sorted out what's the original code vs the libraries and things Flash/Flex built into it.
I've used FDT (the free version) to rebuild the decompiled code into MYappExePluginThing.swf so I can run it with the javascript code and see what happens.
I'm here because what happens isn't good. Basically, my javascript code (MYjavascript.js) gets to the point where it does
window.log("init()");
var so = new SWFObject("flash/MYappExePluginThing.swf"", socketObjectId, "0", "0", "9", "#FFFFFF");
window.log("init() created MYappExecPluginThing!!!");
so.addParam("allowScriptAccess", "always");
log("init() added Param!!");
so.write(elId);
log("init() wrote!");
IE9's console (yeah, you read that right) shows
init()
created MYappExecPluginThing!!!
init() added Param!!
init() wrote!
but none of the debugging i've got in MYappExePluginThing.as displays and nothing else happens.
I'm trying to figure out what I've screwed up/what's going on? Is MYappExePluginThing.as running? Is it waiting on something? Did it fail? Why aren't the log messages in MYappExePluginThing.as showing up?
The first most obvious thing is I'm using FDT which, I suspect, was not used to build the original. Is there some kind of magic "build javascript accessible swf thing" in FlashBuilder or some other IDE?
First noteworthy thing I find is:
file MYappExePluginThing.swf
MYappExePluginThing.swf Macromedia Flash data (compressed), version 14
I'm using Flex 4.6 which, for all I know, may have a completely different mechanism for allowing javascript communication than was used in appExePluginThing.swf
Does anyone know if that's true?
For example, when FDT runs this thing (I can compile but FDT does not create a .swf unless i run it) I get a warning in the following method:
private function init() : void
{
Log.log("console.log", "MYappExePluginThing init()");
//var initCallback:String = Application.application.parameters.initCallback?Application.application.parameters.initCallback:"MYjavascript.MYappExePluginThing_init";
var initCallback:String = FlexGlobals.topLevelApplication.parameters.initCallback?FlexGlobals.topLevelApplication.parameters.initCallback:"MYjavascript.MYappExePluginThing_init";
try
{
ExternalInterface.addCallback("method1Callback",method1);
ExternalInterface.addCallback("method2Callback",method2);
ExternalInterface.call(initCallback);
}
catch(err:Error)
{
Log.log("console.log", "MYappExePluginThing init() ERROR err="+err);
}
}
I got a warning that Application.application was deprecated and I should change:
var initCallback:String = Application.application.parameters.initCallback?Application.application.parameters.initCallback:"MYjavascript.MYappExePluginThing_init";
to:
var initCallback:String = FlexGlobals.topLevelApplication.parameters.initCallback?FlexGlobals.topLevelApplication.parameters.initCallback:"MYjavascript.MYappExePluginThing_init";
which I did but which had no effect on making the thing work.
(FYI Log.log() is something I added:
public class Log{
public static function log(dest:String, mssg:String):void{
if(ExternalInterface.available){
try{
ExternalInterface.call(dest, mssg);
}
catch(se:SecurityError){
}
catch(e:Error){
}
}
trace(mssg);
}
}
)
Additionally, in MYjavascript.js MYappExePluginThing_init looks like this:
this.MYappExePluginThing_init = function () {
log("MYjavascript.js - MYappExePluginThing_init:");
};
Its supposed to be executed when MYappExePluginThing finishes initializing itself.
Except its not. The message is NOT displaying on the console.
Unfortunately, I cannot find any references explaining how you allow javascript communication in Flex 4.6 so I can check if I've got this structured correctly.
Is it a built in kind of thing all Flex/Flash apps can do? Is my swf getting accessed? Is it having some kind of error? Is it unable to communicate back to my javascript?
Does anyone have any links to references?
If this was YOUR problem, what would you do next?
(Not a full solution but I ran out of room in the comment section.)
To answer your basic question, there's nothing special you should need to do to allow AS3-to-JS communication beyond what you've shown. However, you may have sandbox security issues on localhost; to avoid problems, set your SWFs as local-trusted (right-click Flash Player > Global Settings > Advanced > Trusted Location Settings). I'm guessing this not your problem, though, because you'd normally get a sandbox violation error.
More likely IMO is that something is broken due to decompilation and recompilation. SWFs aren't meant to do that, it's basically a hack made mostly possible due to SWF being an open format.
What I suggest is that you debug your running SWF. Using break-points and stepping through the code you should be able to narrow down where things are going wrong. You can also more easily see any errors your SWF is throwing.
Not really an answer, but an idea to get you started is to start logging everything on the Flash side to see where the breakage is.
Since you're using IE, I recommend getting the Debug flash player, installing it, then running Vizzy along side to show your traces.
Should give you a good idea of where the app is breaking down.
Vizzy
Debug Player
Eclipse allows you debug applets using sun.applet.AppletViewer. It will actually start the applet, run it and emulate complete browser runtime. If you have javascript manipulation code in your applet this will cause JSException because the present context is not a real JS enabled engine.
How would you solve this issue? I can see several possible paths:
Wrap the exception in try {} catch () and ignore it - Not good practice.
Pass and environment flag that would tell the code we are currently in debug mode, so that it won't try to execute JS code - OK but will need manual intervention from each developer.
Identify current context is not a browser - How?
Find another AppletViewer that can emulate a complete browser behavior, including JS - Is there ?
More?
Thank for your ideas.
Not a fail safe but a workable solution I've managed to come up with:
private void notifySelectionState(){
JSObject jsObject = null;
try {
jsObject = JSObject.getWindow(applet);
// An exception can be thrown here (hopefully) only is running in debug environment...
} catch (JSException e) {
// So actually what I'm doing here is checking (in a very lame fashion) for if I'm in a the browser
// content or in the AppletViewer
}
if (jsObject != null) {
jsObject.call(...);
}
}
On certain older browsers, JSObject will throw generic RuntimeExceptions instead of JSException. So you may want to throw your net a little bit wider and leave a good comment in your wrappers.