Understanding Android webview javascript interface - javascript

I have created an android WebView, and injected javascript interface using addJavascriptInterface(mObject, "jsinterface"). It works fine until I create an object with same name (jsinterface) in JavaScript using the new operator.
My Java Code:
WebView mWebView = findViewById(R.id.myWebView);
mWebView.getSettings().setJavaScriptEnabled(true);
mWebView.setWebChromeClient(new MyWebChromeClient((Activity)mContext));
mWebView.addJavascriptInterface(new testClass(), "jsinterface");
mWebView.loadUrl("UrlToLoad");
testClass.java
public class testClass{
public testClass() {
}
#JavascriptInterface
public String testNativeMethod() {
return "Java method called!!";
}
}
My Java Script Code
test.js
function test(msg){
this.message = msg;
this.testJSMethod = function(){
return this.message;
}
}
alert(jsinterface.testNativeMethod()); // prints Java method called!!
jsinterface= new test("JS method called...");
alert(jsinterface.testJSMethod()); // prints JS method called...
alert(jsinterface.testNativeMethod()); // errors "NPMethod called on non- NPObject"
Problem:
Is this possible for a javascript object to have access to both , i.e javascript methods and native JAVA methods(exposed to it via javascriptinterface) ? Is there any possibility of setting any property to webview OR executing any JS script to get this done?

Think about document in javascript. When you are in a web browser, this is a global object that you have access to at any point. If you make your own new var called document, you are going to have problems accessing the global document.
When you execute this line:
mWebView.addJavascriptInterface(new testClass(), "jsinterface");
you are adding a global object called jsinterface. This is the same situation as document. If you create a var with the same name, it will overwrite the existing global reference.
Once you add a javascript interface to the WebView, you don't need to create a new reference to the interface. addJavascriptInterface has already done that for you.

TRY
You may try to make another object, which will retranslate calls to javascript interface.Implement onPageStarted method in WebViewClient , and inject javascript in onPageStarted method, in the following way.
mWebView.setWebViewClient(new WebViewClient() {
#Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
view.loadUrl(url);
return true;
}
#Override
public void onPageStarted (WebView view, String url, Bitmap favicon){
String jsScript= "javascript:var functions_array = ['testNativeMethod'];";
jsScript+="var jsinterface = {};"
jsScript+="functions_array.map(function(id){"
jsScript+="jsinterface[id]= function() {"
jsScript+="try{return temp_obj[id].apply(temp_obj, arguments);}"
jsScript+="catch(e) { console.log('ERROR: ' + e + ', method ' + id);"
jsScript+="return false;}}})"
view.loadUrl(jsScript);
}
});
Hope this helps :-)

Related

using Javascript to set Java fields

Setting variables directly in Java classes doesn't seem to be working. Why not? What is the proper syntax? Where does the variable go??
The following prints out 2 and 1. Thus the f.x=2; never happened according to the object f of Foo.
#Test
public void testJS2Java() throws IOException, ScriptException, Exception {
ScriptEngineManager factory = new ScriptEngineManager();// create JavaScript engine
ScriptEngine engine = factory.getEngineByName("JavaScript");
class Foo {
int x = 1;
}
Foo f = new Foo();
engine.put("f", f);
System.out.println(engine.eval("f.x=2;"));
System.out.println(f.x);
}
The f.x=2; executes without error but which x was set?
Three issues with your test:
Nashorn allows access only to public members of public classes (from
exported modules for jdk9+) only. The local class Foo is
not public. So its members are not accessible from JavaScript.
Nashorn allows access to static members only from "Java type
objects" and not from instances of Java types. (different from Java).
Nashorn would ignore property sets on Java object if no public
field or public bean property with appropriate setter is found.
A working sample demonstrating access to a static Java field from Nashorn:
import javax.script.*;
public class Main {
public static int x = 10;
public static void main(String[] args) throws Exception {
ScriptEngine e = new ScriptEngineManager().
getEngineByName("JavaScript");
// access type object for Java class "Main" using Java.type
e.eval("var M = Java.type('Main');");
// access public static field 'x' of Main class
e.eval("print(M.x)");
// assign to public static field 'x' of Main class
e.eval("M.x += 10;");
// change is seen from Java
System.out.println(Main.x);
}
}

Call JavaScript methode from another Js in GWT

I attempt to call a javascript method from another javascript method from java method
here is my code:
public void print(){
Excec();
}
native String flipName(String tst) /*-{
// ...implemented with JavaScript
alert(tst);
}-*/;
native String Excec() /*-{
alert("exe");
flipName("1");
alert("exe1");
}-*/;
when i run the application it show me an error :
Excec()([]): flipName is not defined
com.google.gwt.dev.shell.BrowserChannelServer.invokeJavascript(BrowserChannelServer.java:249)
com.google.gwt.dev.shell.ModuleSpaceOOPHM.doInvoke(ModuleSpaceOOPHM.java:136)
com.google.gwt.dev.shell.ModuleSpace.invokeNative(ModuleSpace.java:576)
This must be done in about the same way as calling a Java method from within a JSNI method.
You must specify the fully qualified name of the method you wish to call, and you also have to specify the type of the argument.
More information can be found here : http://www.gwtproject.org/doc/latest/DevGuideCodingBasicsJSNI.html
In practice this will work (replace be.knarf.gwt.client.Example with the correct package name and class name of your class) :
private native void flipName(String tst)
/*-{
alert(tst);
}-*/;
private native void excec()
/*-{
alert("exe");
this.#be.knarf.gwt.client.Example::flipName(Ljava/lang/String;)("hi");
alert("exe1");
}-*/;

Android webview activity,how to get js return value?

js code like this:
function a(){return "hello";}
in android webview activity, how to call js function a() get the return value "hello" ?
webview.addJavaInterface? webview.loadUrl()? i can`t get it.
please tell me how to solve the problem.
My advice would be:
1- Define a Javascript interface
A plain Java class with some methods and attributes, use annotation to expose the method you desire to the webview JS scope
public class MyInterface {
private WebView webView;
//pass the reference to the webview in your constructor
public JavascriptCallback(WebView webView) {
this.webView = webView;
}
//expose this method to the JS scope using annotation
#JavascriptInterface
void sumNumbers(final String num1, final String num2, final String JScallbackFn) {
this.javascriptCallback(JScallbackFn, num1 + num2);
}
//run the callback into the JS scope
void javascriptCallback(final String callback, final String result) {
webView.post(new Runnable() {
#Override
public void run() { webView.load("javascript:"+callback+"("+result+")", null);
}
});
}
2- Inject the JavaScript interface in your webview
webview.addJavascriptInterface(new MyInterface(this.getActivity(), webview), "MyInterface");
3- Invoke the JS method (from within the webview)
MyInterface.sumNumbers(12, 34, showResult);
function showResult(res) {
document.getElementById('myDiv').innerHTML(res);
}
For more extensive explanation about how webviews works on Android check the official documentation http://developer.android.com/guide/webapps/webview.html

How to call javascript method from android

Hi In my android phonegap app i need to call the javascript method from android code (DroidGap).I have tried the sample code.
Here is my code:
super.loadUrl("file:///android_asset/www/index.html");
super.loadUrl("javascript:onload()");
When i use super.loadUrl("javascript:alert('hai')"); i am getting this alert.But when i use the method "onload" i am getting the error.
Here is my error in logcat:
Uncaught TypeError: Property 'onload' of object [object DOMWindow] is not a function at null:1
Here is my script in index.html:
<script type="text/javascript">
function onload()
{
alert("hai");
}
</script>
I dont know where i am wrong.Please guide me.Thanks in Advance.
Try this one and add this line also
super.setWebChromeClient(new WebChromeClient());
super.loadUrl("file:///android_asset/www/index.html");
After this line call like this onPageFinished
webview.setWebViewClient(new WebViewClient() {
#Override
public void onPageFinished(WebView view, String url) {
webview.loadUrl("javascript:(function() {alert("hai") }
);
}
});
Android can only call the javascript method if an html page is currently loaded in webView
first call
webview.loadUrl("Your html page url");
then call
webView.loadUrl("javascript:hello()");
Try to handle the alert function in the java file, like this :
mWebView.setWebChromeClient(new MyWebChromeClient());
final class MyWebChromeClient extends WebChromeClient {
#Override
public boolean onJsAlert(WebView view,String url,
String message,JsResult result) {
new AlertDialog.Builder(MainActivity.this).
setTitle("Alert").setMessage(message).setPositiveButton("OK",
new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface arg0, int arg1) {
}
}).create().show();
result.confirm();
return super.onJsConfirm(view,url,message, result);
}
}
I had the same problem when I moved the target javascript function from the main page to an separate .js file. For some reason, the loadUrl() function can't find externally-loaded functions - only the ones in the main page. Once I moved the function back, it immediately started working.
Go figure.

How to handle Javascript events via WebBrowser control for WinForms

I have read WebBrowser Control from .Net — How to Inject Javascript, Is it possible to call Javascript method from C# winforms and many others. Those examples were returns function value or alert window (synchronous calls). I have to get result from event handler (async call):
<script type="text/javascript">
window.onload = function() {
var o = new M.Build(document.getElementById("ZID"));
M.Events.observe(o, o.Events.Success, function() {
// I have to get some value!!
});
M.Events.observe(o, o.Events.Fault, function() {
// I have to get some value!!
});
}
</script>
Calling C# from JavaScript
Simply put, you can expose a C# object
to the WebBrowser that the JavaScript
can call directly The WebBrowser
class exposes a property called
ObjectForScripting that can be set by
your application and becomes the
window.external object within
JavaScript. The object must have the
ComVisibleAttribute set true
C#:
[System.Runtime.InteropServices.ComVisibleAttribute(true)]
public class ScriptInterface
{
public void callMe()
{
… // Do something interesting
}
}
webBrowser1.ObjectForScripting = new ScriptInterface();
Javascript:
window.external.callMe();
Calling JavaScript in a WebBrowser control from C#
This is code I have. In the DocumentCompleted event ('cause I'm getting a page from online)
var wb = (WebBrowser)sender
//Lots of other stuff
object obj = wb.Document.InvokeScript("MyFunctionName");
Create a function that returns whatever value you need and invoke away.
You can also inject a script into the page
string js = "function MyFunctionName(){alert('Yea!');}";
HtmlElement el = wb.Document.CreateElement("script");
IHTMLScriptElement element2 = (IHTMLScriptElement)el.DomElement;
element2.text = js;
head.AppendChild(el);
which can then be invoked. That's what I've done.
If your webBrowser control is in a form, you can do the following:
[System.Runtime.InteropServices.ComVisibleAttribute(true)]
public class Form1
{
public Form1()
{
InitializeComponent();
webBrowser1.ObjectForScripting = this;
}
public void CallMe()
{
//.... this method can be called in javascript via window.external.CallMe();
}
}

Categories