Android WebView run Javascript in all frames (including iframes) - javascript

In a Soundcloud iframe within a WebView I want to execute the following js: (document.getElementsByClassName('mobilePrestitial__link')[0]).click()
In iOS I achieved this by setting forMainFrameOnly: false, however I can't seem to find this setting on Android. What can I do to execute said js on all frames so the click gets through?
This is how I am trying it right now but it doesn't work.
webView.setWebViewClient(new WebViewClient() {
#Override
public void onPageFinished(WebView view, String url) {
String javascript = "javascript:(document.getElementsByClassName('mobilePrestitial__link')[0]).click()\n" +
"setTimeout(function() {\n" +
"(document.getElementsByClassName('mobilePrestitial__link')[0]).click()\n" +
"}, 5000);";
view.loadUrl(javascript);
}
});
Update: if anyone else gets stuck with this with the exact same website, namely Soundcloud: they offer you to have a popup-free frame if you upgrade your channel. Maybe that fits your use case, it was what I eventually went with.

Related

Executing JavaScript instructions after loading HTML file in a WebView

I realized an Android program that loads a HTML file into a WebView, the HTML file loads Leaflet.js that shows different styles of maps based on the provider you gave it.
I load the page in the OnCreate() method with this instruction:
myWebView.loadUrl("file:///android_asset/test.html");
After that, I need to take the list of different maps from a Handler (with class name JavascriptInterface.java) that I added to the WebView like this:
myWebView.addJavascriptInterface(new JavaScriptInterface(this, myWebView), "MyHandler");
The final code needs to look like this:
myWebView.loadUrl("file:///android_asset/test.html");
myWebView.loadUrl("javascript:window.MyHandler.getMaps()");
The problem is that the first loadUrl() isn't fast enough, so the second loadUrl goes before the map is initialized, causing a lot of problems.
The temporary, and also horrible, solution that I found is to hold the second loadUrl for 1 second before executing it, like this:
myWebView.loadUrl("file:///android_asset/test.html");
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
public void run() {
// Actions to do after 1 second
myWebView.loadUrl("javascript:window.MyHandler.getMaps()");
}
}, 1000);
There is a better way of executing an instruction after another one? I already tried using an ASyncTask, but there is the possibility that I didn't implemented it well.
Please call myWebView.loadUrl("javascript:window.MyHandler.getMaps()"); inside Webview onPageFinished event.
myWebView.setWebViewClient(new WebViewClient() {
#Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
Log.d("WebView", "onPageStarted " + url);
}
#Override
public void onPageFinished(WebView view, String url) {
myWebView.loadUrl("javascript:window.MyHandler.getMaps()");
}
});
myWebView.loadUrl("file:///android_asset/test.html");

Android WebView call JavaScript function

I using WebView to show this website
http://app.wlojii.com
I want to make control panel in notification bar to play/stop music.
The problem i cant find the function that play/stop the music.
I inspected the button element and tried some variants of functions unsuccessfully (play, play(), player.play()), and i used this method to call the functions:
mWebView.loadUrl("javascript: ...")
I am not so familiar with JavaScript and web, i need some help.
Pavel
I have added a git repo with the working code https://github.com/premithk/webviewclickeventexample
The problem last time was that getElementsByClassName returns an array. So i have changed the code to
mWebview.loadUrl("javascript(function({l=document.getElementsByClassName('mejs-playpause-button');
e=document.createEvent('HTMLEvents');
e.initEvent('click',true,true);
l[0].dispatchEvent(e);})()");
Any ways the code in repo works such that there is a button (native) that will act as play/pause
Register a Javascriptinterface or use this library.
https://github.com/lzyzsd/JsBridge/blob/master/README.md
The library acts as a bridge between webview and the Java part of the app
Yes, The idea is to inject an object to the JS part and use that as a bridge to call a function inside the native part. Have updated the git repo reflecting the change. Only thing is that before we inject the event listener we have to make sure the page is fully loaded, so it might take some time. So first thing is to add the interface mWebview.addJavascriptInterface(new JSInterface(), "jsnativebridge");
Then define the class
private class JSInterface {
#JavascriptInterface
public void playPauseClicked(String string) {
Log.d("console", "" + string);
}
}
Then wait for page load and add the event listener like below
mWebview.setWebViewClient(new WebViewClient() {
public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
Toast.makeText(activity, description, Toast.LENGTH_SHORT).show();
}
public void onPageFinished(WebView view, String url) {
Log.d("console", "" + "loaded");
mWebview.loadUrl(
"javascript:(function() { " +
"var ch=document.getElementsByClassName('mejs-playpause-button');" +
"ch[0].addEventListener('click', function(){" +
" jsnativebridge.playPauseClicked('Yes');" +
"});"+
"})()"
);
}
});
You can refer the git repo, have added a working demo.
Cheers

Could someone once and for all please explain Cannot call determinedVisibility() - never saw a connection for the pid

I'm currently working on graphing data via d3 into a webview. Naturally, things are breaking as soon as I try to reload the graph and feed it new data. This lovely line keeps popping up: W/cr_BindingManager: Cannot call determinedVisibility() - never saw a connection for the pid.
I've scoured SO for an explanation, but there doesn't seem to be anything conclusive. People are just suggesting to turn on DOM storage in webview settings (which obviously doesn't fix the issue). I'm suspecting there is a race condition between reloading the graph and feeding it new data. I've overridden onPageFinished() in my WebViewClient to call the listener to load the data into the chart, thinking it would resolve the race condition, but to no avail.
Can someone please explain to me what W/cr_BindingManager: Cannot call determinedVisibility() - never saw a connection for the pid means? Am I off in my assessment? How can I debug it?
Any tips are appreciated.
EDIT: I've solved the original issue, but I would still love to learn what that line means. Bounty up.
Consecutive calls to loadUrl cause a race condition. The problem is that loadUrl("file://..") doesn't complete immediately, and so when you call loadUrl("javascript:..") it will sometimes execute before the page has loaded.
This is how I setup my webview:
wv = (CustomWebView) this.findViewById(R.id.webView1);
WebSettings wv_settings = wv.getSettings();
//this is where you fixed your code I guess
//And also by setting a WebClient to catch javascript's console messages :
wv.setWebChromeClient(new WebChromeClient() {
public boolean onConsoleMessage(ConsoleMessage cm) {
Log.d(TAG, cm.message() + " -- From line "
+ cm.lineNumber() + " of "
+ cm.sourceId() );
return true;
}
});
wv_settings.setDomStorageEnabled(true);
wv.setWebViewClient(new WebViewClient() {
#Override
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
setTitle(view.getTitle());
//do your stuff ...
}
#Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
if (url.startsWith("file"))
{
// Keep local assets in this WebView.
return false;
}
}
});
//wv.setWebViewClient(new HelpClient(this));//
wv.clearCache(true);
wv.clearHistory();
wv_settings.setJavaScriptEnabled(true);//XSS vulnerable
wv_settings.setJavaScriptCanOpenWindowsAutomatically(true);
wv.loadUrl("file:///android_asset/connect.php.html");
NOTE this line wv.setWebChromeClient(new WebChromeClient());
In API level 19 (Android 4.4 KitKat), the browser engine switched from Android webkit to chromium webkit, with almost all the original WebView API's wrapped to the counterparts of chromium webkit.
This is the method that gives the error (BindingManagerImpl.java), from Chromium source:
#Override
public void determinedVisibility(int pid) {
ManagedConnection managedConnection;
synchronized (mManagedConnections) {
managedConnection = mManagedConnections.get(pid);
}
if (managedConnection == null) {
Log.w(TAG, "Cannot call determinedVisibility() - never saw a connection for the pid: "
+ "%d", pid);
return;
}
It's a rendering warning from content.
You can dig around forever in that github source code, might be nice to see where the method determinedVisibility (in BindingManagerImpl.java) is called from...(suffix “Impl” for Implementation).
Hope this helps ;O)
This usually pops up when you are overriding the method shouldOverrideUrlLoading().
From my WebView usages on prior apps, this is due to what is being rendered on the WebView, what is being caught on the above method and in turn ignored.
I see this a lot when the websites that I load attempt to load scripts outside of the allowed domain.

Javascript doesn't work on Android webview

Good Day,
I have a webview in Android app which loads a resource that uses html and javascript:
WebView.getSettings().setJavaScriptEnabled(true);
//webView.getSettings().setDomStorageEnabled(true);
//webView.getSettings().setJavaScriptCanOpenWindowsAutomatically(true);
//webView.getSettings().setLoadWithOverviewMode(true);
//webView.getSettings().setUseWideViewPort(true);
//webView.getSettings().setBuiltInZoomControls(true);
webView.setWebViewClient(new WebViewClient() {
public boolean shouldOverrideUrlLoading(WebView view, String url) {
view.loadUrl(url);
return true;
}
});
//webView.loadUrl("file:///android_asset/Index.html");
webView.loadUrl("http://foo.com/newbilltemplate/");
The comments show you what I've tried so far. Also I tried local and online resource and the problem still exist.
The index.html page doesn't use Javascript but when a button is clicked it uses some Javascript calculations to display in the next page.
Thanks,

WebView: Wait until input field exists before starting a javascript function

I have a function to load on a website once its two input fields are loaded.
function setCredentials(name, key){
document.getElementById('zoneIdent').value=name;
document.getElementById('zonePwd').value=key;
GInterface.traiterEvenementValidation();
}
It is contained in a auto.html in the *root of project*/assets/www/ folder. (I tried putting it in the /res/assets/www/ folder but I get the following from AndroidStudio : Android Resource Packaging: [QuickPronote] invalid resource directory name: C:\Users\Yann\DEV\workspace\QuickPronote\res/assets
I have to use this function on this type of website : http://81.192.152.242:8001/mobile.eleve.html?FD=1. Note that the website doesn't load quickly.
I'm using the following code :
myWebView.loadUrl(String.valueOf(url));
myWebView.loadUrl("javascript:setCredentials('" + name + "','" + key + "')");
where url, name and key are strings that user has defined.
I tried it, even with dummy text, the two fields are completed and the validation action should be launched but it seems that either the function was loaded too quickly, or either it wasn't lauched at all, because once the website is fully loaded, there is neither the values apearing or an error message saying the credentials are wrong.
If your solution includes the use of external plugin-ins/libs like JQuery, tell me so.
PS: Not using PhoneGap or anything.
Here's where I got my code from in the first place.
First, make sure you've set javascript enabled on the webview,
webView.loadUrl(String.valueOf(url));
webView.getSettings().setJavaScriptEnabled(true);
then add a listener to load the name / key once the page has finished.
webView.setWebViewClient(new WebViewClient(){
#Override
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
view.loadUrl("javascript:setCredentials('" + name + "','" + key + "')");
}
});
edit:
I think I found your problem. The lack of the javascript "setCredentials" method in the page: http://81.192.152.242:8001/mobile.professeur.html?FD=1... did you forget to add that?
when I change the above onPageFinished method to this:
myWebView.setWebViewClient(new WebViewClient() {
#Override
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
myWebView.loadUrl("javascript:document.getElementById('zoneIdent').value='test name';");
}
});
the "Identifier" field is populated with "test name" on that page.

Categories

Resources