How can I change a display of element dynamically in android WebView? - javascript

I have a WebView in Android. I load page in webview from url and i want to hide some elements that the webpage actually has. I did it after page has loaded. And it give me only 'none' text in the webview nothing more. I tried as follows
#Override
public void onPageFinished(WebView view, String url) {
view.loadUrl("javascript:window.document.getElementsByClassName('cdo-search')[0].style.display='none';");
if (pd.isShowing()) {
pd.dismiss();
}
}
How can we hide element that webpage actually has?

My previous answer was not it. after testing I found out that this solved the problem. The issue is not with android or webview. it's the way url based javascript execution works.
#Override
public void onPageFinished(WebView view, String url) {
view.loadUrl("javascript:function a(){window.document.getElementsByClassName('cdo-search')[0].style.display='none';}; a()");
if (pd.isShowing()) {
pd.dismiss();
}
}
I'm not entirely sure what's the reason but if i had to guess, what ever is returned by the statement you write in this format other than undefined, will be set as the document's html.
in other words, you cannot do any kind of assignment operation in outer scope, while executing JS in this format.
my testing method:
i put these two in the address-bar of this particular Stack overflow page.
javascript:function a(){window.document.getElementsByClassName('question-hyperlink')[0].style.display='none';}; a()
javascript:window.document.getElementsByClassName('question-hyperlink')[0].style.display='none';
in the first attempt the qustion disappeared as expected but in second one, the page turned into "none".

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");

Stop Android WebView from trying to load/capture resources like CSS on loadData()

Background
This may seem to be a duplicate to many other questions. Trust me that it isn't.
I'm trying to load html data into a WebView, being able to capture user hyperlink requests. In the process I've found this answer which does exactly what I want to do, except it captures other requests to things like CSS files and images:
// you tell the webclient you want to catch when a url is about to load
#Override
public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request){
return true;
}
// here you execute an action when the URL you want is about to load
#Override
public void onLoadResource(WebView view, String url){
if( url.equals("http://cnn.com") ){
// do whatever you want
}
}
I've shut off automatic image loading, network loads, and Javascript execution:
settings.setBlockNetworkLoads(true);
settings.setBlockNetworkImage(true);
settings.setJavaScriptEnabled(false);
But these do nothing as to preventing the capture of these requests.
Maybe there's a different procedure to capturing the link click, but it was either this or to stop the loading of external resources.
Question
How do I prevent WebView from capturing (or attempting to load) resource requests like CSS, JS, or images?
Otherwise if I can't prevent capturing or attempting to load, how can I differentiate between links clicked and web resources?
Thanks ahead!
You could override WebViewClient's shouldInterceptRequest and return some non-null response instead of the CSS, JS, images, etc. being fetched.
Example:
#Override
public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
Log.d(TAG, "shouldInterceptRequest: " + url);
if (url.contains(".css")
|| url.contains(".js")
|| url.contains(".ico")) { // add other specific resources..
return new WebResourceResponse(
"text/css",
"UTF-8",
getActivity().getResources().openRawResource(R.raw.some_css));
} else {
return super.shouldInterceptRequest(view, url);
}
}
where R.raw.some_css is:
body {
font-family: sans-serif;
}
Note:
I'm not sure what pages you're loading, but this approach may ruin the look of the page.
I've found a way to ignore automated WebView resource requests.
By ignoring requests in the first second of WebView initialization, I am able to isolate user based clicks from the rest:
final Long time = System.currentTimeMillis()/1000;
//load up a WebView, define a WebViewClient for capturing link clicking
WebView webview = new WebView(this);
WebViewClient webviewClient = new WebViewClient() {
#Override
public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request){
return true;
}
#Override
public void onLoadResource(WebView view, String url){
Long currentTime = System.currentTimeMillis()/1000;
if (currentTime - time > 1) {
//do stuff here
}
}
};
I have not tested this solution without blocking JavaScript execution and automatic image loading, but it should work regardless:
WebSettings settings = webview.getSettings();
settings.setBlockNetworkLoads(true);
settings.setBlockNetworkImage(true);
settings.setJavaScriptEnabled(false);
Short answer is, you can't.
A longer answer could be like this: you won't be able to do that because it is designed to be "capture all or capture nothing". Web requests are a general concept, not tied to a particular resource like images or css - in fact, it does not have any clue of what does are. That's why you won't find anything.
Do like this: in shouldOverrideUrlLoading, instead of returning true all the time, you only return true for the urls you want to handle yourself. For all other cases, like css and so forth, you return false, so the webview will take care of that for you.
For example:
#Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
// Ignore css and js
if (url.endsWith(".css") || url.endsWith(".js")) {
return false;
}
return true;
}

onPageFinished Javascript WebView

I feel pretty stupid for having to ask this but I can't for the life of me get it to work.
So I've searched around and found lots of help, guides, and etc for using the onPageFinished function in WebViewClient and my code is largely based on these.
Basically I have a function that is supposed to load a web page and then hides certain elements on that page with the onPageFinished. Instead of actually doing this though it hides the entire page and the webview displays the text "none".
When I comment out the onPageFinished function the webview loads the page just fine which leads me to believe that it has to be the javascript but according to the w3c site my javascript is correct for what I want to do...
So my question is this, Does anyone see the problem with the below code and/or anyone have a suggestion for something else that might accomplish my above stated goals?
Any help in getting this to work would be greatly appreciated.
Code:
public class MainActivity extends AppCompatActivity{
private WebView browser;
private String url = "https://www.google.com";
< onCreate calls cleanPage and other stuff >
public void cleanPage() {
browser = (WebView) findViewById(R.id.webview);
browser.getSettings().setJavaScriptEnabled(true);
browser.setWebViewClient(new WebViewClient() {
#Override
public void onPageFinished(WebView view, String url) {
browser.loadUrl("javascript:document.getElementById('lga').style.display='none';");
}
});
browser.loadUrl(url);
}
}
Notes:
-The above uses google as an example, lga is the id of the google banner div.
-browser and url are global because once I get cleanPage working I will add in other functions that will alter them as needed.
You need to add void(0); at the end of your javascript: URL. Otherwise, WebView replaces your current page with the result of the JS evaluation (in your case, that is the string "none").
So change this:
browser.loadUrl("javascript:document.getElementById('lga').style.display='none';");
to:
browser.loadUrl("javascript:document.getElementById('lga').style.display='none';void(0);");

Hiding div in Android WebView app with java doesn't work

I have a div called downloadapp that I'd like to display to users who visit my mobile website instead of using my Android app. So I need to hide that div for users who already use my app.
My code:
private void startWebView(String url) {
webView.getSettings().setJavaScriptEnabled(true);
webView.setWebViewClient(new WebViewClient() {
//On error, open local file
public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
webView.loadUrl("file:///android_asset/www/myerrorpage.html");
}
#Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
view.loadUrl(url);
return true;
}
#Override
public void onPageFinished(WebView view, String url) {
view.loadUrl("javascript:document.getElementById('downloadapp').style.display = 'none';");
}
});
webView.loadUrl(url);
}
Problem:
My app loads the div first and its actually being displayed for a couple of seconds. Then suddenly, the whole webpage loaded in the app disappears and a blank page with the word "none" is the only thing that is left on the screen.
Is there something wrong with the way I try to hide the div "downloadapp" or what am I missing here?
What I want it to do is immediately hide the div before the webpage is being displayed.
This is happening on newer versions of WebView -- if your app is targeting API level 19 or above (KitKat), then if a javascript: URL returns a value, this value is interpreted as content for a new web page to open. In your case, as 'none' is the return value of the assignment, it is used as the content for a new page.
Just put void(0); at the end of your code in javascript: to prevent it from returning a value.

Getting content out of WebView In a unit test Android, using java script

I have been able to get content out of WebView using javascript and loadUrl() method having specified an interface thats called from javascript string that is injected into WebView.The problem is that this only works for me when the loadUrl() method is present in onPageFinished() method in the WebView client. What I want to do is I want to get the content out of the WebView (with the content already loaded). The WebView is in an activity instrumentation test case and I can for instance use findAll() method and that works fine. For some reason I can not use loadUrl() and get the desired behaviour (which is injecting javascript and getting content out of the WebView with a help of an interface).
PLease help.
Thanks
Pawel
EDIT:
Just adding code to show what I am doing exactly:
Yes I understand that but my problem is that I am trying to do it within a test case this way:
public void testWebView() throws Exception {
solo.sleep(3000); // wait for views to load on the screen
WebView a=null;
ArrayList<View> views = solo.getCurrentViews(); // I am using solo object to get views for the screen currently loaded
for(View s:views)
{
if (s instanceof WebView)
{
a = (WebView)s; // this is where I get my WebView
}
}
Instrumentation inst = getInstrumentation();
inst.runOnMainSync(new Runnable()
{
public void run()
{
int d =a.findAll("something"); // this method runs fine on the object and i get the desired result
WebSettings settings = a.getSettings();
settings.setJavaScriptEnabled(true);
a.loadUrl("javascript:document.location = document.getElementById('google').getAttribute('href')"); // this javascript is never executed and that is my problem
}
});
}
You can inject javascript in a loaded page much the same way you can do it in desktop browsers - via inline javascript entered into navigation bar.
Bind some Java object so that it can be called from Javascript with WebView:
addJavascriptInterface(javaObjectExposed, "JSname")
Force execute javascript within an existing page by
WebView.loadUrl("javascript:window.JSname.passData("some data from page");");

Categories

Resources