Override current Javascript functions with Android Webview - javascript

I'm porting my website to Android, and using an Webview to show the content to user. There are a lot of Javascript functions in my website, and I want to intercept them. I already seen a "solution" here.
However, I think there should be a more proper way, using Javascript Interface:
this.webView.addJavascriptInterface(this.webJavascriptInterface, "Android");
This way, I have to modify my website to call both myFunction() and Android.myFunction(). I tried to leave a blank String in the interface:
this.webView.addJavascriptInterface(this.webJavascriptInterface, "");
but the result was as I guess, it couldn't work. Is there a way to override current Javascript functions in Webview?

// android
webView.setWebViewClient(new WebViewClient() {
#Override
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
webView.loadUrl("javascript:function inputClick(val){native.abcd(val);}"); // override js function
}
});
webView.loadUrl("file:///android_asset/test.html");
webView.addJavascriptInterface(new Object() {
#JavascriptInterface
public void abcd(int val) {
Log.e(TAG, "#js abcd" + val);
}
}, "native");
<!-- html -->
<input type="button" onclick="inputClick(2)" value="button">
== add some explain at Sep 07,2015
because javascript function could be override, so you can override javascript function while page finished.
if not, normal implement maybe like this:
// js code
function inputClick(val) {
native.abcd(val); // native and abcd defined in WebView method addJavascriptInterface
}
but this normal implement is seems not work in iOS(Object-C), and must edit HTML page.
is just move the java-javascript bridge code from HTML to Java. (see method onPageFinished in example code)

You can do this by injecting a new javascript that redefines old function, basically you can override existing function with this.
For example, to override window.print() function, I use this
webView.loadUrl("javascript:window.print = function() {Android.printPage();}")

Related

how to solve window.close() not work in Android webview c#

i just new using this visual studio c# android...
have system develop in vb.net... working fine in website... problem when wanted using mobile app... used this vs c# xamarin android....
protected override void OnCreate(Bundle bundle) { base.OnCreate(bundle);
SetContentView(Resource.Layout.Main);
WebView localWebView = FindViewById<WebView>(Resource.Id.LocalWebView);
localWebView.SetWebViewClient(new WebViewClient()); // stops request going to Web Browser
localWebView.Settings.JavaScriptEnabled = true;
localWebView.Settings.JavaScriptCanOpenWindowsAutomatically = true;
localWebView.SetWebChromeClient(new WebChromeClient());
localWebView.LoadUrl("http://www.facebook.com");
}
success run on this webview.... but have form have window.open....problem is how to window.close after used javascript to opened it.. means going back to my previous window.. and pass some information.... like: window.opener.document.getElementById(StrCtrlName2).value = MemberCode;
find and want to try this code... but look different for c#... how to convert it in visual studio c# because have error??... help me.. where to pun also i'm not sure... just learn c#
WebChromeClient webClient = new WebChromeClient(){
public void onCloseWindow(Window w){
super.onCloseWindow(w);
Log.d(TAG, "Window close");
}
};
thanks...
Welcome #haris!
The code you found is java. It's different from c# but also have a lot similarities.
If you want this particular java snippet in c# you would have do write something like this:
using Android.Webkit;
public class CustomWebChromeClient : WebChromeClient {
public override void OnCloseWindow(Android.Webkit.WebView window)
{
base.OnCloseWindow(window);
//Your favorite logging library call.
}
}
A quick explanation (in case you are interested).
In java snippet a ref to anonymous class which extends WebChromeClient is created and then we extend base onCloseWindow method by adding addition logging.
In c# the same can not be done so what I did, just created a named class CustomWebChromeClient which extends WebChromeClient and overrides OnCloseWindow
For more info refer to official Xamarin docs.

How to call existing javascript function from android activity

I'm building an ebook reader, so I have a webview that is loading a page stored locally on the device which it retrieved from the ebook itself. On this page, it has a javascript function controls.nextPage() that loads and runs just fine; it's used to not actually navigate to new web pages, but instead redraw virtual pages using javascript. I have this function bound to a button on the web page itself so that I can manually click it to test, again, works just fine when I touch the button on my webview.
Now I am trying to trigger this exact function from within my app. Ideally, I want to do this from a gesture swipe but that is too complicated for this specific question, as I have other issues with the gestures I need to solve first. For now, I've set up a button in my navigation drawer to trigger it and test it:
NavigationView navigationViewRight = (NavigationView) findViewById(R.id.nav_view_webview_right);
navigationViewRight.setNavigationItemSelectedListener(
new NavigationView.OnNavigationItemSelectedListener() {
#SuppressWarnings("StatementWithEmptyBody")
#Override
public boolean onNavigationItemSelected(MenuItem item) {
// Handle navigation view item clicks here.
int id = item.getItemId();
if (id == R.id.nav_camera) {
// *** - Focus here - *** //
runOnUiThread(new Runnable() {
#Override
public void run() {
mWebview.evaluateJavascript("controls.pageNext()", null);
}
});
} else if (id == R.id.nav_share) {
}
drawer.closeDrawer(GravityCompat.END);
return true;
}
}
);
Note, I've also tried calling window.controls.pageNext() to no avail.
So my page is loaded, and I've hit my in-page button to test the function; works. I go to hit my navigation drawer button in the app? Error (when using window.controls.pageNext():
[INFO:CONSOLE(1)] "Uncaught TypeError: Cannot read property 'pageNext' of undefined", source: (1)
So it seems to be that evaluateJavascript() is being run in a fresh environment/thread. How can I tell it not to?
To get around this,I've tried to create an empty javascript interface in the hopes that I could simply initialize my page javascript into it and thus be able to call it from Android.
mWebview.addJavascriptInterface(new TestInterface(), "TestInterface");
public class TestInterface {
#JavascriptInterface
public void test() {
runOnUiThread(new Runnable() {
#Override
public void run() {
mWebview.evaluateJavascript("console.log('test')", null);
}
});
}
}
From my webapp, the javascript can call the interface just fine. calling TestInterface.test(); yields:
[INFO:CONSOLE(1)] "test", source: (1)
But when I tried to assign a new function to that interface from my webapp:
TestInterface.testTwo = function() {
console.log('testTwo');
};
TestInterface.testTwo();
Android wouldn't have it:
[INFO:CONSOLE(674)] "testTwo", source: http://127.0.0.1:8080/js/main.js (674)
What's weird is that it's not really giving me much info to go on. I do know that the rest of my page has issues loading after the testTwo() attempt that test() did not, so I'm assuming failure to load the rest of the script.
Lastly, out of curiousity, I changed my navigation drawer button to try and run the new function like this:
mWebview.evaluateJavascript("TestInterface.testTwo()", null);
Log:
[INFO:CONSOLE(1)] "Uncaught TypeError: TestInterface.testTwo is not a function", source: (1)
Yes but is it something else? I dunno. Thoughts? Thank you.
So I figured out in the end what my issue was. By running mWebview.evaluateJavascript("window.location", null); I realized that I in fact was not actually on the page I thought I was. My ebook page was being loaded into an iframe or some other type of skeleton/wrapper in such a way that the webapp functions were not in fact available when running evaluateJavascript().
So once figured that out, I can confirm some things that I originally questioned above:
So it seems to be that evaluateJavascript() is being run in a fresh
environment/thread. How can I tell it not to?
It does not. Just make sure you know what page is actually loaded.
To get around this,I've tried to create an empty javascript interface in the hopes that I could simply initialize my page javascript into it and thus be able to call it from Android.
This does in fact work. I'm not sure what my mistake was before, but if I create a javascript interface in Android, it's functions are available to the webapp AND I can in fact write new objects to the interface object from within the webapp. So, initializing new objects into TestInterface from within the webapp can be run within the Android app via:
mWebview.evaluateJavascript("TestInterface.someNewFunctionFromWebapp()", null);
I can NOT however overwrite any existing objects/properties of that javascript interface object. so TestInterface.test() is immutable.

Android WebView Async Call to Java Function

I'm looking for a way to make async calls to Android's native code from JS
I have a Main Activity with the following code to make accessible native code to JS:
webView.addJavascriptInterface(new BindingHelper(this), "Android");
webView.loadUrl("file:///android_asset/www/index.html");
The BindingHelper Class contains something like this:
#JavascriptInterface
public void showToast(String toast) {
Toast.makeText(theContext, toast, Toast.LENGTH_SHORT).show();
}
#JavascriptInterface
public String SuperDuperComplexFunction () {
//A function that will need some time to finish...
return "{}";
}
The previous Methods can be called from the Index.html linked JS as follows:
<script type="text/js">
Android.showToast("Toast");
</script>
In that way the showToast() function is executed synchronously. What I need is to call the method SuperDuperComplexFunction(); in a aSync way (just like an AJAX Request), and when the method success take some action.
Any ideas?
One option is to use an Http Server in java code and then make the AJAX call on localhost. That way the Javascript call would be the exact same as any other AJAX call, and since you control the Http Server you can just have it call your SuperDuperComplexFunction()
I've used NanoHttpd in the past for something kind of similar but not quite the same.

Android webview javascript not working on API 18 or higher

I want to display a website in WebView with manipulating some DOM element. I mean, I want to remove a special div element or replace it with something.
For this purpose I did something like this:
For replacing something I use this model
document.getElementById("demo").innerHTML = "Hello World!";
I apply it for Android WebView like this:
public class WebClient extends WebViewClient {
#Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
view.loadUrl(url);
return true;
}
#Override
public void onPageFinished(WebView view, final String url) {
view.loadUrl("javascript:document.getElementById(\"jumbotron-company\").innerHTML = \"\";");
}
}
It is work on my device which API is 18 but not working on emulators or device which have API greater than 18
What #Mattia said is correct. Use evaluateJavascript if possible. It has another advantage of being able to return the value of the result back from JavaScript.
But if you want an API-agnostic workaround, make sure that the code you evaluate using loadUrl("javascript:...") just doesn't produce any return value. An assignment returns the assigned value. In newer versions of WebView this value is used as contents for a new page that replaces the existing one.
You can make sure that the expression you are evaluating doesn't produce a return value in two ways:
append void(0); statement at the end, e.g. loadUrl("javascript:elt.innerHTML='Hello World!';void(0);");
run your code inside a function that doesn't return a value, e.g. loadUrl("(function(){elt.innerHTML='Hello World!';})()");
From API level 19 you should use evaluateJavascript:
public void evaluateJavascript (String script, ValueCallback resultCallback)
Added in API level 19 Asynchronously evaluates JavaScript in the
context of the currently displayed page. If non-null, |resultCallback|
will be invoked with any result returned from that execution. This
method must be called on the UI thread and the callback will be made
on the UI thread.
Please refer to migration guide for WebView in Android 4.4:
http://developer.android.com/guide/webapps/migrating.html

Android Webview touch content

I want to get the content of that tag which I touch in webview in string.
Suppose I have 5 paragraph and I touch on one then I want content of that paragraph in string.
How can I achieve this?
Thanks
Well this is very easy, but you need to do it in parts, and you would need JavaScript.
1.- Enable JavaScript in your webview.
web.getSettings().setJavaScriptEnabled(true); //"web" is the object of type WebView
2.- Create a JavaScript Interface between the WebView and the Html.
public class JavaScriptInterface {
private Handler myHandler = new Handler();
public void getParagraph(final String paragraph){
myHandler.post(new Runnable() {
#Override
public void run() {
//Do something with the String
}
});
}
}
NOTE: Inside the method run, you will add whatever you need to process with the String retrieved from the Html. This class can be created inside the class where you create the WebView or as a separate class if you are going to use this same behavior from another activity.
3.- Send the Interface to the WebView.
web.addJavascriptInterface(new JavaScriptInterface(), "android");
/* In this case "android" is the name that you will use from the Html to call
your methods if is not too clear yet, please keep reading */
4.- You need to add the onClick event handler to each of your P tags.
<p onclick="android.getParagraph(this.innerText);">Text inside the paragraph</p>
/*android was the name we set for the interface in step 3, getParagraph is the name
of the method created on step2,"this.innerText" retrieves the text inside the paragraph*/
NOTE: All the names that you see on my example can be changed, BUT if you change the name on the java class remember to change all the calls in the html

Categories

Resources