From javascript to java (A GWT story)

2019-06-24 13:54发布

问题:

So, I'm designing an app in GWT for an embedded web browser (Sketchup). I can control Sketchup by changing the window.location value to "skp::myFunciton@myParams". Sketchup can execute javascript in the browser. What I want to do is ask sketchup to give me the contents of its model.

public static native void getModel() /*-{
    $wnd.location = "skp:getModel@";
}-*/;

After a second sketchup has a result. But how do we get it back to gwt? The problem is the entrypoint instance launched the request and JSNI can only map static methods to javascript.

I thought I had a solution with events and elements...

//Sketchup javascript
var gwtwidget = document.getElementById("myTextArea")
gwtwidget.value = "blahblah";
gwtwidget.onchange();

and then listening for the change in GWT. Alas, it doesn't work. Gwt's own event system overrides, sinks, deters (or whatever) the event. What approach should I take? I've been through the web in search of info but I certainly can't get my head round it. I'm guessing the answer is either...

1 Call an entrypoint instance method from javascript (somehow)
2 Fire an event from javascript that will be picked up by gwt (somehow)
3 Setup an async callback interface mechanism of sorts (somehow)

回答1:

Interface should be pretty simple.

For example, let's say we have some object in GWT. Let's say we have some function in JS which accept some callback as parameter. So in gwt we will have something like this:

    public static native void executeFunctionWithCallBack(MyCallback callback)/*-{
           var callBackWrapper =function(param) {
              callback.@com.package.MyObject::onSuccess(*)(param);
           } 
           $wnd.invokeFunctionWithCallback(callbackWrapper)  
     }-*/;

If you want to call instance methods, you need to expose not only method, but instance on which it should be called as well. E.g. you have to pass an instance as parameter to the JSNI method (or obtain it from JSNI in some other way). Then you create a JS function which will invoke method on instance. That's all. No more magic=)