2

I want to pass the 'this' parameter from javascript to the native layer in android.

function abc() {

    function callf() {
        // 'this' should refer to the instance of the 
        // abc object
        Native.call(this);
    }
 }

This is to make it possible to call a function on the 'abc' instance from the native layer.

When I do pass an object, either using 'this' or just an object directly, it gives 'null'.

Does anyone know how to solve this?

Thanks,
Rajath

2
  • 3
    AFAIK, what you want is not supported -- the only data types supported by addJavaScriptInterface() are ones that are available in both Java and JavaScript, like strings and ints. Commented Oct 13, 2012 at 21:09
  • @CommonsWare, I guess it does look like that. Thanks. Commented Oct 19, 2012 at 5:02

4 Answers 4

2

when i need to do something like this i use a substrate layer like this:

javascript

(function() {

  var callbacks = {};

  function getNewId() {
    return Math.round(Math.random() * 999999999);
  }

  window.__withCallback = function(func, context, callback, params) {

    var cbId = getNewId(),
        args = Array.prototype.slice.call(arguments, 2);

    while (cbId in callbacks) {
      cbId = getNewId();
    }

    args.unshift(cbId);
    callbacks[cbId] = { context: context, callback: callback };

    func.apply(Native, args);

  };

  window.__callbackFromNative = function(id, params) {

    var args,
        cbItem = callbacks[id];    

    if (cbItem && typeof(cbItem.callback) === 'function') {
      args = Array.prototype.slice.call(arguments, 1);
      cbItem.callback.apply(cbItem.context, args);
    }

    delete callbacks[id];
  };


}());

so now when you have the Java code like (assuming you exposed the same object as "Native"):

java

class Native {
    public void test (long callbackId, String param1, String param2) {

        // do java stuff in here
        // webView is your webView
        webView.loadUrl("javascript:__callbackFromNative(" + callbackId + ", 'yay', 69)");

    }
}

and use it like this:

javascript

var awesome = {

  test2: function(arg1, arg2) {
    // callback
  },

  startTest: function() {
    // here's the way you pass "this" to "Native.test", 
    // this.test2 is the function you want to "callback" to
    // the rest are all params 
    __withCallback(Native.test, this, this.test2, "xxx", 'yay');
  }
};


awesome.startTest();

the substrate layer is now reusable and standard so you don't have to worry about setting global variables or anything crazy like that, plus it works with any number of arguments both in and out of the native layer...

hope this helps -ck

Sign up to request clarification or add additional context in comments.

Comments

1

Assuming Native is mapped as a named java object with method "call" that you bound to the web view using addJavascriptInterface() (see related https://stackoverflow.com/a/12832132/1367983), I think you should skip trying to invoke any operation on a javascript bound object outside of the webview and just generate the logic you want to run on it with dynamically generated javascript urls you can then execute using the webview's loadUrl() method.

in js of html content rendered by webview:

var myVar;

...

myVar = this;
Native.call('myVar');
...

in javascript interface class Native's implementation of call()

webView.loadUrl("javascript:myVar.doSomething('" + stringFromApp1 + "', " + numberFromApp1 + ");");

2 Comments

I should reiterate the addJavascriptInterface warning: Protect your interface implementation from abuse by rogue pages' script.
What aspect? Were you able to create the javascript interface and add it to the webview? If so, are you saying invoking javascript functions using "loadUrl" didn't work? Also, please keep in mind that "myVar", in the code above, needs to be scoped somewhere in your page in a global way -- that is, so any script on the page may refer to it.
1

Note that your example is passing the this of callf. You'd have to pass abc's this to callf:

function abc() {
    function callf() {
        Native.call(this);
    }
    // ...
    callf.call(this);
    // ...
}

Or with a closure:

function abc() {
    var that = this;
    function callf() {
        Native.call(that);
    }
    // ...
    callf();
    // ...
}

EDIT:

You're still limited on what kind of values you can pass to Java, see this question.

1 Comment

this did not work with an object. I guess the link you mention points to the right answer
0

This is a long shot, but you could stringify the "this" object and use it as a JSON object in Java

in JavaScript

function abc() {

  function callf() {
    // 'this' should refer to the instance of the 
    // abc object
    Native.call(JSON.stringify(this));
  }
}

in Java

    class Native {
    public void call (String object)
    {
        try {
            JSONObject thisObject = new JSONObject(object);
            // do whatever you want to the thisObject
        } catch (JSONException e) {
            e.printStackTrace();
        }

    }
}

I don't remember if the object will be encoded when you receive it. If it is, you can use:

URLDecoder.decode(object, "UTF-8")

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.