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

Rajath
  • 11,787
  • 7
  • 48
  • 62
  • 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. – CommonsWare Oct 13 '12 at 21:09
  • @CommonsWare, I guess it does look like that. Thanks. – Rajath Oct 19 '12 at 05:02

4 Answers4

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

ckozl
  • 6,751
  • 3
  • 33
  • 50
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 + ");");
Community
  • 1
  • 1
Kirk B.
  • 456
  • 2
  • 6
  • I should reiterate the addJavascriptInterface warning: Protect your interface implementation from abuse by rogue pages' script. – Kirk B. Oct 14 '12 at 05:13
  • 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. – Kirk B. Oct 19 '12 at 12:11
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.

Community
  • 1
  • 1
acelent
  • 7,965
  • 21
  • 39
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")
Geert Weening
  • 1,480
  • 1
  • 13
  • 17