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

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.

Related

Android WebView and JavaScript programmtically clicking button not working

I have a very simple use case i.e to programmatically call a button of a web page loaded inside my webview. Below is the code
webView.getSettings().setDomStorageEnabled(true);
webView.getSettings().setAppCacheEnabled(false);
webView.getSettings().setCacheMode(WebSettings.LOAD_NO_CACHE);
webView.getSettings().setJavaScriptEnabled(true);
webView.setWebViewClient(new WebViewClient(){
#Override
public void onPageFinished(WebView view, String url) {
//super.onPageFinished(view, url);
switch (view.getOriginalUrl()){
case Properties.LOGIN_URL:
webView.evaluateJavascript(
"javascript:" +
"var usernameField = document.getElementById('loginUserName');" +
"usernameField.value = '" + Properties.USERNAME + "';" +
"var passwordField = document.getElementById('loginPassword');" +
"passwordField.value = '" + Properties.PASSWORD + "';", null
);
webView.evaluateJavascript(
"javascript:" +
"document.getElementById('loginButton').click();", new ValueCallback<String>() {
#Override
public void onReceiveValue(String s) {
}
}
);
break;
}
}
});
view.loadUrl(Properties.LOGIN_URL);
The username and password field injection is working fine but the code to perform button click isn't working.
I have searched a lot and experimented a lot but no luck, Is this even possible?
EDIT:
The URL I'm accessing is private to our organization, is on http and not secured, not sure if it's relevant.
I have tried another public page with login fields and the same code works and the button gets clicked successfully.
Okay I found the reason. So the onPageFinished was getting called while all the DOM elements are not loaded hence the javascript was failing. For time being it to work I have added a delayed Handler with 5 sec delay and it worked. The right solution should be to check for the page to complete to load (may be use jquery to check when the document is ready).
You can handle the webview button click this way
#JavascriptInterface
public void handleClick(String id) {
startActivity(new Intent(mContext, MainActivity.class));
}
In javascript
Android.handleClick(_id);

Android WebView run Javascript in all frames (including iframes)

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.

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

Parse HTML contents of Webview - Android

I'd like to detect when my webview loads a certain page, for example, an incorrect login page. I've tried using onLoadResource and shouldOverrideUrlLoading, but I can't get either to work, and I'm thinking a better way would to parse the HTML whenever the webview starts loading a page, and if a certain string is found within the HTML, then do whatever.
Is there a method to do this? I've tried using TagSoup, but I have no clue how to relate it into my webview. Here's what my code looks like now:
String fullpost = "pass=" + passwordt + "&user=" + usernamet + "&uuid=" + UUID;
String url = "mydomain.com";
mWebview.postUrl(url, EncodingUtils.getBytes(fullpost, "BASE64"));
mWebview.setWebViewClient(new WebViewClient() {
public void onPageFinished(WebView mWebview, String url) {
String webUrl = mWebview.getUrl();
if (webUrl.contains("/loginf")) {
MainActivity.this.mWebview.stopLoading();
MainActivity.this.setContentView(R.layout.preweb);
}
}
});
Basically, the postUrl is initiated from a user click on a button in a layout, and that's what starts the WebView, and then I call setContentView to the layout that contains the webview.
From there, if the login info is correct, the webpage goes to XXX, and if it's incorrect, it goes to YYY. So, I want to detect immediately (and on every page load from there on out), if YYY is loaded, then //domagic. Hope that makes sense. Being the page redirect from url to XXX or YYY is automatic and not initiated by the user, shouldOverrideUrlLoading doesn't work, and I can't figure out how to use onLoadResource, so I'm just completely lost.
My current thought is loading everything in a separate thread and then using the WebView to display the content (that way I can parse the HTML), but I'm not sure how that'd work or even how to do it.
Anyone have any ideas or suggestions?
I think I've read a way to get a text string of a webview's content. Then, you could use jsoup to parse it. [neh, don't even need jsoup; just indexOf string check]
I'll suggest that you do consider handling the login with an HTTP client. It gives you flexibility, and seems the more proper way to go. I've been using the loopj library for HTTP get and post requests. It allows for simpler code. For me, anyway, a relative Android newbie. Here's some code from my project, to get you thinking. I've left out stuff like progress bar, and cookie management.
private void loginFool() {
String urlString = "http://www.example.com/login/";
// username & password
RequestParams params = new RequestParams();
params.put("username", username.getText().toString());
params.put("password", password.getText().toString());
// send the request
loopjClient.post(urlString, params, new TextHttpResponseHandler() {
#Override
public void onStart() {
// called before request is started
//System.err.println("Starting...");
}
#Override
public void onSuccess(int statusCode, Header[] headers, String responseString) {
// called when response HTTP status is "200 OK"
// see if 'success' was a failed login...
int idx = responseString.indexOf("Please try again!");
if(idx > -1) {
makeMyToast("Sorry, login failed!");
}
// or actual success-ful login
else {
// manage cookies here
// put extractData in separate thread
final String responseStr = responseString;
new Thread(new Runnable() {
public void run(){
extractData(responseStr);
selectData(defaultPrefs.getInt("xyz_display_section", 0));
// start the next activity
Intent intent = new Intent(MainActivity.this, PageViewActivity.class);
startActivity(intent);
finish();
}
}).start();
}
}
#Override
public void onFailure(int statusCode, Header[] headers, String responseString, Throwable throwable) {
// called when response HTTP status is "4XX" (eg. 401, 403, 404)
makeMyToast("Whoops, network error!");
}
#Override
public void onFinish() {
// done
}
});
}
You can see that, in the response handler's onSuccess callback, I can test for a string, to see if the login failed, and, in the onFailure callback, I give a network error message.
I'm not experienced enough to know what percent of web servers this type of post login works on.
The loopj client receives and manages cookies. If you will be accessing pages from the site via a webview you need to copy cookies from the loopj client, over to the webview. I cobbled code from a few online posts, to do that:
// get cookies from the generic http session, and copy them to the webview
CookieSyncManager.createInstance(getApplicationContext());
CookieManager.getInstance().removeAllCookie();
CookieManager cookieManager = CookieManager.getInstance();
List<Cookie> cookies = xyzCookieStore.getCookies();
for (Cookie eachCookie : cookies) {
String cookieString = eachCookie.getName() + "=" + eachCookie.getValue();
cookieManager.setCookie("http://www.example.com", cookieString);
//System.err.println(">>>>> " + "cookie: " + cookieString);
}
CookieSyncManager.getInstance().sync();
// holy crap, it worked; I am automatically logged in, in the webview
EDIT: And, I should have included the class variable definitions and initializations:
private AsyncHttpClient loopjClient = new AsyncHttpClient();
private PersistentCookieStore xyzCookieStore;
xyzCookieStore = new PersistentCookieStore(this);
loopjClient.setCookieStore(Utility.xyzCookieStore);

Categories

Resources