In my Android app I implemented a common approach to "go back on back-button pressed":
private WebView webView; // my WebView
#Override
public void onBackPressed() {
if(webView.canGoBack()) webView.goBack();
else super.onBackPressed();
}
But today I noticed a weird thing. If, on the very first webpage loaded on webView, it calls history.pushState(...) automatically, then webView.canGoBack() will return false, causing the approach above to fail (even if I execute webView.goBack() directly, nothing happens in the webView), although executing history.back() still works within the webpage itself. I've also tried calling history.pushState automatically using setTimeout, with the same result. However, if history.pushState is called manually, i.e. triggered by some user events, then webView.canGoBack() is true and the code works.
It seems to me that this is a bug of WebViews. Any ideas?
Related
If you have a webview open in Android, you can inspect it in Chrome devtools. However, I can't open the devtools first, then open the webview to log network requests that occur on page load. Is there a way to log network requests that occur as soon as the webview loads?
Also, refreshing the page behaves differently from the initial load because the page modifies the URL.
You can intercept various components of WebView communication by implementing your own WebViewClient. A short snippet is below:
webView.webViewClient = object : WebViewClient() {
override fun shouldInterceptRequest(view: WebView,
request: WebResourceRequest): WebResourceResponse? {
// Use the `request` object as needed.
}
}
More information regarding the WebViewClient, including other possible overrides, can be found here.
I have a WebView in an app that loads a specific web page.
On that web page is a button that uses JavaScript to call a method within the Android activity to reload the URL in the WebView (effectively resetting the web app to its default state).
I've got all of the JavaScript interface to Android bit working thanks to a few threads here and I can pop up a Toast to show that the app is about to reload, but I'm getting an error with the WebView.loadUrl() call as follows.
java.lang.RuntimeException: java.lang.Throwable: A WebView method was called on thread 'JavaBridge'. All WebView methods must be called on the same thread. (Expected Looper Looper (main, tid 1) {1d015c84} called on Looper (JavaBridge, tid 122148) {33703881}, FYI main Looper is Looper (main, tid 1) {1d015c84})
I'm guessing that this is because the method that is doing the reload is not within the onCreate method for this activity which does all of the other WebView stuff but I'm not sure if this really is the problem and how to resolve it if it is - as the method that reloads the URL needs to be within the JavascripInterface class to be reachable from within the web-page.
Loading a page in a WebView componenet (or reloading) needs to be done on the UI thread for some reason, so simply wrapping the reload call in runOnUiThread resolves this issue.
#JavascriptInterface
public void reloadSite(){
Toast.makeText(mContext, getString(R.string.reloadingWebApp), Toast.LENGTH_LONG).show();
runOnUiThread(new Runnable() {
#Override
public void run() {
mWebView = (WebView) findViewById(R.id.activity_main_webview);
mWebView.loadUrl(getString(R.string.web_app_url));
}
});
}
I have a GWT application that opens a second browser window. I would like my second window to be able to call a method within the entry point of the first window.
The code sample below works in production (web) mode, but when I try running it in hosted mode, IE detects XSS and overwrites the page with a single "#" to protect against the detected attack. I'm guessing this is because my GWT code server is running on localhost while the application I'm testing is deployed on a virtual machine.
Update: It appears that IE XSS Filtering is sporadic. Sometimes I'm able to get the page to load. But awhile later it starts filtering again.
public class MainWindow implements EntryPoint {
...
#Override
public void onModuleLoad() {
registerJSNIFunctions(this);
}
private native void registerJSNIFunctions(MainWindow mw) /*-{
$wnd.sayHi = function (name) {
mw.#MainWindow::sayHi(Ljava/lang/String;)(name);
}
}-*/;
public void sayHi(String name) {
alert("Hi " + name); // not valid, but you get the point
}
...
}
public class SecondWindow implements EntryPoint {
...
#Override
public void onModuleLoad() {
...
sayHi("kylos");
}
public static native void sayHi(String name) /*-{
$wnd.opener.window.$wnd.sayHi(name);
}-*/;
}
Any ideas on how I could get this to work in hosted mode? Or is there a better way to do cross-window communication with GWT?
Your question is quite interesting, see other´s opinion but I have done something similar using OAuth.
So, if the idea at the end is call from one Window to other some method I´d something like:
....
#Maybe if you use window instead of top works as well
$wnd.opener.top.location.replace(url);
$wnd.close();
....
....
And in the other browser wait for the new request, parse the url, and call "locally" to sayHi. Is this approach valid to you?
If you want further details about the Windows properties you can see W3Schools page
But basically:
$wnd.opener #returns Returns a reference to the window that created the window.
top #returns the topmost browser window
So the issue seems to be sporadic. I'm not sure how exactly the filter gets triggered, but when it does, the rewritten page gets cached by IE so future requests are guaranteed to fail until the browser cache is emptied.
I also found this Microsoft document that describes a custom header, X-XSS-Protection, that can be used to disable the filter. Obviously, this should only be used on a dev system in hosted mode.
To disable the filter, add the following header to your server configuration:
X-XSS-Protection: 0
I'm using the method shouldOverrideUrlLoading for an app that is personalised for multiple clients. Each client has it's own webpage that wants to be loaded into the webview. My problem is this: the app works perfect for client A and his webpage, but doesn't for client's B webpage (which isn't related with client A in any way). The difference, as I've tested, is that in client's B situation for the links that are accessed within the loaded content into the webview, shoulOverrideUrlLoading isn't working (NEVER gets called) and for client's A webpage works perfectly. Another thing is that client's B webpage doesn't work only on some Android versions, like 2.1 or 2.3.6 but it works fine on 2.3.3, 2.3.5, 4.0.2 or 4.0.3.
So this is kinda odd. If you happen to know anything, please help! Thanks!:)
EDIT: I noticed that shouldOverrideLoading isn't called when the webpage does NOT load the requested link through javascript and it works when javascript isn't used!!! but when I set webview.setJavaScriptEnabled(false) it works!!! I really need javascript to be enabled for my app cause the webpages usually use javascript for other things besides loading so I cannot disable it just because shouldOverrideUrlLoading doesn't get called!
EDIT 2: To be more exact:
This one works and shouldOverrideUrlLoading gets called:
<p onclick="location.href='linkHere'">
NewLink
<span class="icon-arrow"></span>
</p>
This one does NOT work and shouldOverrideUrlLoading does NOT get called:
<a class="link-inherit" href="linkHere">
NewLink
<span class="icon-arrow"></span>
</a>
Solution for shouldOverrideUrlLoading not called
public void onPageStarted(WebView view, String url, Bitmap favicon) {
if (url.contains("success")) {
Intent intent = new Intent(WebviewActivity.this, OrderConfirmActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
} else {
super.onPageStarted(view, url, favicon);
}
}
I have a webview in my program.
I loaded a string into this webview that contains javascript function. When i loaded it in the emulator it's not working
i.e if I write a simple alert the webView won't display the alert.
I have enabled the javascript. But then also its not working.
what may be the reason?
Please help
Thankyou
Alerts will not normally work in a WebView. You will need to write the code to do that yourself. You can easily do that by implementing your own version of WebChromeClient. In otherwords:
class ChromeClient extends WebChromeClient {
public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
Toast.makeText(view.getContext(), message, Toast.LENGTH_SHORT).show();
}
}
...
mWebView.setWebChromeClient(new ChromeClient());
Another thing I would recommend is implementing the onConsoleMessage as well. This way you can just use "console.log" in your JavaScript and have it directed to Toast or the Android Log.