As the title suggests, I'm trying to bind javascript code to my android app so I can react in my app to an event/message that my website is sending.
After reading the official android documentation related to javascript binding I managed to easily implement it.. as long as it's a string.
What is working fine?
I implemented the following code in my app:
/** Instantiate the interface and set the context */
class ClientInterface(private val mContext: Context) {
/** Show a toast from the web page */
#JavascriptInterface
fun postMessage(message: String) {
Toast.makeText(mContext, message, Toast.LENGTH_SHORT).show()
}
}
if the parameter of the 'postMessage' function is a String and I'm passing a String from my javascript as a parameter, everything is fine. it's passing the string.
my problem is that I am trying to get a JSONObject instead of a String, and it's not working.
I tried casting everything I thought might work.. JSONObject / JSONObject? / Any / Any? / Object / Object? and so on..
when I'm sending an object on my javascript, nothing seems to work. all I get in my app is a null response.
anyone ever tried something like that? what am I missing?
P.S - here's my javascript code for reference:
var objectMessage = {
type: "quote",
code: "My name is Inigo Montoya. You killed my father, prepare to die!"
}
window.CLIENT.postMessage(objectMessage);
You can't pass an object only primitive!
So you need to stringify your object.
var objectMessage = {
type: "quote",
code: "My name is Inigo Montoya. You killed my father, prepare to die!"
}
window.CLIENT.postMessage(JSON.stringify(objectMessage));
Related
I'm trying to get a json data and a callback from javascript using webview.
I can get the json data but the problem is I cannot get the callback.
I need to fire the callback after a condition is met.
Android Code:
--------
// Adding the interface
webView.addJavascriptInterface(new WebAppInterface(this), "code");
--------
#JavascriptInterface
public void execute(String JsonData, String callback) {
String d = data; <---HAS JSON DATA RETURNED TO ANDROID
Log.d("jSon Data", d);
mCallback = callback; <---RETURNS "undefined"
}
Javascript code (I can't edit this.):
code.execute(JsonData, function(callback){
console.log(callback);
});
Android on button click
#OnClick(R.id.callback)
void onButtonCallback() {
String s = "Hello World";
// pass Hello World back to javascript. But I'm getting "undefined"
// for the callback
mCallback.passdata(s);
}
What I'm trying to achieve is:
1) Get data from Javascript to Android -> OKAY
2) Get the Callback from Javascript to Android -> Here's my problem
3) Fire the callback along with "hello world" string on button click
Note: I can't edit the javascript code. How am I going to achieve this? Do I need to inject Js from Android? If yes, how?
I just need to solve item number 2 to move forward. Thanks!
You can't do that. At least, based on my tests addJavascriptInterface() only works with primitive types and Strings, and so you cannot pass Javascript objects like functions.
I have written a custom active X control using the IDispatch interface that I would like to communicate with javascript. I have successfully gotten the javascript -> COM path working; I can call a javascript function on my active x object and receive a corresponding INVOKE call in my dll.
To receive events on the javascript side, I am following the advice in this article: http://jeffcode.blogspot.com/2008/02/how-to-create-activex-control-that.html
When I load my test page, I get a call to FindConnectionPoint followed by a call to Advise, as I would expect. When I call Invoke on the interface given by Advise, I get a success status message, but nothing happens on the js side!
This is the javascript code I am using to test event handling:
function FooActiveX::ReceiveMessage(msg)
{
alert(msg);
}
Interestingly, if I remove that, I don't get the calls to FindConnectionPoint or Advise anymore, so it's doing SOMETHING.
Any advice on how to debug this problem or things to try would be very helpful. Thank you!
My idl interface definition file looks like this:
[
uuid("1bf6bb1a-3232-11e4-a195-a6c5e4d22fb7"),
version(1.0),
]
library FooControlLib
{
interface IFooControl;
dispinterface DFooControlEvents;
importlib("stdole2.tlb");
[
uuid("1bf6bb1a-3232-11e4-a195-a6c5e4d22fb8"),
hidden
]
dispinterface DFooControlEvents
{
properties:
methods:
[id(DISPID_RECEIVEMESSAGE)] void ReceiveMessage( [in] BSTR msg );
}
[
odl,
dual,
uuid("1bf6bb1a-3232-11e4-a195-a6c5e4d22fb9"),
oleautomation
]
interface IFooControl : IDispatch
{
[id(DISPID_SENDMESSAGE)] HRESULT SendMessage( [in] BSTR msg);
}
[
uuid("1bf6bb1a-3232-11e4-a195-a6c5e4d22fc0")
]
coclass FooControl
{
[default] interface IFooControl;
[source, default] dispinterface DFooControlEvents;
}
}
EDIT: It seems that the problem is related to the parameter in the ReceiveMessage method. If I remove the "msg" parameter, the alert box will display properly.
Found my problem. The arguments to the method are passed to Invoke as an array of VARIANTARG structures. I had set the value, but not the vt member of that struct, which identifies the type of the parameter. I don't know why invoke returned an OK status.
Store and retrieve Google Dart objects in JavaScript library containers
In a Dart application I am using an external JavaScript library to do various matrix calculations.
The specific functionality of the library is not important, what it's important is that I need to store and retrieve Dart object that I put in the matrix.
Dart Class - Lets image i have a dart object that which has a parameter called name
MyDartClass mydc = new MyDartClass(something, something);
mydc.name;
// Everything works as planned
Storing
matrix = js.context.matrix
matrix.cell(1,1).store("thing", new MyDartClass(something, something));
Retrieving
matrix.cell(1,1).has_object_of_type("thing");
// true
MyDartClass mydc = matrix.cell(1,1).retrieve("thing");
Do something with the object
mydc.name;
// Exception: The null object does not have a getter 'name'.
// NoSuchMethodError : method not found: 'name'
// Receiver: null
// Arguments: []
Does the library really work?
Yes it does. I have done the exact same thing in pure javascript many times and there are plenty of test to test the behaviour ( in Javascript )
Is Dart Broken?
When I try to use a javascriptified Hash to do the same behavoiur it works like a charm.
var options = js.map({ 'dart' : new MyDartclass(something, something));
var y = options["dart"];
js.context.console.log(y.name);
// Name is printed
What do you get out from the retrieve?
It seems that I get some kind of Dart Proxy
MyDartClass mydc = matrix.cell(1,1). retrieve("thing");
js.context.console.log(mydc);
DartProxy {id: "dart-ref-20", port: DartSendPortSync}
id: "dart-ref-20"
port: DartSendPortSync
__proto__: DartProxy
I belive that the lib stores the objects, deep down, in a hash map. But it seems like when I retrieve the object into the Dart I get something, but not in a way that I can work with it. So i need help since I don't know how to make it work.
Do I need to de-proxify the object?
Perhaps it IS a Dart bug when you try to retrieve objects from hashes inside objects
Perhaps I missunderstod everything that this is not suppose to work.
Passing and retrieving Dart objects inside the same scope is working. There's the following test case in the tests of js-interop to proove it :
test('retrieve same dart Object', () {
final date = new DateTime.now();
js.context.dartDate = date;
expect(js.context.dartDate, equals(date));
});
However there seems to be an issue with multiple scopes (and multiple event loops as well). There is no way to retain a dart object for now. So your dart object reference goes away at the end of scope. Here's a simple test case that fails :
test('retrieve same dart Object', () {
final date = new DateTime.now();
js.scoped(() {
js.context.dartDate = date;
});
js.scoped(() {
expect(js.context.dartDate, equals(date));
});
});
Please file an issue.
I'm using Play! v2 and I added a JavaScript method on my page that tries to retrieve data from the server. The client sends 2 information, a deal and a boolean (withDebug).
My routes file:
GET /:deal/tailLog controllers.MyController.tailLog(deal: String, withDebug: Boolean)
I also tried that, without success:
GET /:deal/tailLog?withDebug=:withDebug controllers.MyController.tailLog(deal: String, withDebug: Boolean)
MyController class contains the following methods:
public static Result tailLog(String deal, Boolean withDebug) {
...
}
public static Result javascriptRoutes() {
response().setContentType("text/javascript");
return ok(Routes.javascriptRouter("jsRoutes",
...,
controllers.routes.javascript.MyController.tailLog()
));
}
And finally, the JavaScript call is:
function tailLog() {
var withDebug = $("#logs-debug").is(':checked');
jsRoutes.controllers.MyController.tailLog('mydeal', withDebug).ajax({
...
});
}
When this method is called, my application is calling the URL http://localhost:9000/mydeal/tailLog?withDebug=false, which is the URL pattern I want, but fails with a 404 error message.
Note that before I added the withDebug parameter, everything was working fine.
What am I doing wrong?
Thanks.
In Play 2.0.4, you must use 0/1 to bind boolean parameters (and not false/true)
A little update in your javascript should fix this error:
var withDebug = $("#logs-debug").is(':checked') ? 1 : 0;
I have an MFC application that uses CHtmlView. It displays some text in html format from some temp html file. Is it possible to handle mouse click on a paragraph to send some data to the program? I understand that javascript can be used to handle click, but how to pass the data from javascript function to the application??
Thanks.
It is possible to cleanly call the containing application from within the Javascript of the HTML page. At the Javascript level the MSHTML interface that is doing the actual work of the CHtmlView provides an "external" object that acts as a way back to the calling application.
Suppose we want to add a method "someCall()" that can be called from Javascript, and that the method takes a string as an argument. In JavaScript we would call it with something like
external.someCall("An example string");
In the MFC application, we need to write a CCmdTarget derived object to act as the implementation of the "external" object as a dispatch-based COM object, something like:
class TestExternal : public CCmdTarget
{
public:
TestExternal()
{
EnableAutomation();
}
void SomeCall(LPCWSTR str)
{
// This is where we get called when the Javascript runs...
}
private:
DECLARE_DISPATCH_MAP()
};
BEGIN_DISPATCH_MAP(TestExternal,CCmdTarget)
DISP_FUNCTION(TestExternal,"someCall",SomeCall,VT_EMPTY,VTS_WBSTR)
END_DISPATCH_MAP()
To tie this implementation of "external" with the HTML view, in a class derived from CHtmlView you need to over-ride OnGetExternal() and to point it to an instance of TestExternal that lives at least as long as the CHtmlView:
class TestHtmlView : public CHtmlView
{
// Usual implementation stuff goes here...
public:
HRESULT OnGetExternal(LPDISPATCH *lppDispatch)
{
*lppDispatch = m_external.GetIDispatch(TRUE);
return S_OK;
}
private:
TestExternal m_external;
};
Note that I haven't actually tested this, but it seems about right from memory ...