I'm trying to track what links my users click in the browser and failing miserably:
My code:
browser = new XWalkView(getMainActivity());
browser.setResourceClient(new XWalkResourceClient(browser)
{
#Override
public boolean shouldOverrideUrlLoading(XWalkView view, String url)
{
log.i("juhu 1", url);
return false;
}
});
This only calls the callback for URLs that I give it (browser.load()), but not for URLs that user then clicks on the rendered page. What's worse, it's not consistent: sometimes the callback gets called, sometimes not.
Here's an example that fails:
<html>
<body>
<p>my link 1</p>
<p>my link 2</p>
</body>
</html>
I tried this with XWalk 15.44.384.13 (latest) and 14.43.343.24 (a couple revisions back), both with no success.
I looked all over the place for similar methods, but neither resource client nor ui client seem to provide something that would work.
This looks fixed as of at least XWalk 16.45.421.19 with the call being made as expected.
Related
I'm using the API 17 emulator to test a page containing a web view.
The webview first loads a page using the GET method.
Then the user submits the web form using HTTP POST method which causes a second page to load.
At this point if I rotate the screen I receive the "Webpage not available" error seen below. This only occurs if the page was loaded using the POST method. Note: I'm trying to restore the webview's state using webview.restoreState (see code below). Is there any way to tell Android to re-post the form data and reload the page instead of displaying this error message?!
I can't reproduce this same issue on KitKat, Lollipop, or Gingerbread... I can only reproduce this issue on Jellybean and Ice Cream Sandwich so far...
I've also confirmed this is an issue on an actual Nexus 7 device running Jellybean, so it's not an emulator-only problem.
Note: I'm not particularly interesting in using something like android:configChanges="orientation|keyboardHidden". As I understand it, this might solve my rotation issues, but the problem may still resurface if the activity state needs to be restored for other reasons.
Screenshots:
Step #1: Load the WebView Normally
Step #2: Submit the Form (uses HTTP Post Method)
Step #3: Rotate the screen to trigger webview.restoreState - error occurs
Code:
Here is some sample code to go along with my question. The code is in Mono C# but should be very nearly identical to Java.
public class MainActivity : Activity
{
WebView webview;
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
webview = new WebView(this);
SetContentView(webview);
if (bundle == null)
webview.LoadUrl("http://2-dot-npwc-services.appspot.com/test-post.jsp");
else
webview.RestoreState(bundle);
}
protected override void OnSaveInstanceState(Bundle bundle)
{
base.OnSaveInstanceState(bundle);
webview.SaveState(bundle);
}
}
The sample HTML page that is performing the POST method looks like this:
<html>
<form action="test-post.jsp" method="post">
<input type="text" name="test" value="test"/>
<input type="submit"/>
</form>
<p>You entered: <%=request.getParameter("test")%></p>
</html>
The browser it's doing good (although it's a pain for us), you have 2 ways:
1- Keeping the webView instance and restoring the state, adding like you said android:configChanges="orientation|keyboardHidden"
2- Or reloading the post petition again.
I take the first one and if i get some error, i will go back to the last page. Doing static content, so on rotation no network or a new petition it's needed on each rotation, which if not, on server side will be a pain too.
To achieve the "if error go back" you need to set a Custom WebClient and override this method
webview.setWebViewClient(new WebViewClient() {
#Override
public void onReceivedError(WebView webView, int errorCode, String description, String failingUrl) {
if ( webView.canGoBack() ) {
Toast.makeText(MainActivity.this, R.string.error_web, Toast.LENGTH_SHORT).show();
webView.goBack();
}
}
});
You can filter by errorCode to go back when you want, in some kind of error you can go back on other do other thing. I dont' know which error raises this POST request or if you want more filter on other situations, so i'm sure you can do a fine grain filter using it.
Edit: You have here the possible error codes
WebViewClient Error Codes
I hope this helps.
I have a webview that shows ads (not my ads), the problem is when user clicks the "x" button to exit the ad, the ad still directs them to a site. What I wonder is since I can't control the ads, can I instead Disable page directing/forwarding inside webview? that means even if user clicks a link inside my webview nothing should happen.
You are looking for WebClient.shouldOverrideUrlLoading method.
webview.setWebViewClient(new WebViewClient() {
public boolean shouldOverrideUrlLoading (WebView view, String url){
//True if the host application wants to leave the current WebView and handle the url itself, otherwise return false.
return true;
}
});
I tried using shouldOverrideUrlLoading, but it didn't work. It looks like that this method is called only once when the html is loaded. After that, you click a link but the method is no more invoked.
I am also making a WebView embedding Youtube Player. Instead of forwarding ads redirect from the WebView, I prefer to open ads in a browser. So I override onLoadResource method:
#Override
public void onLoadResource(final WebView view, final String url) {
if(url.indexOf("googleadservices.")>-1){
view.getSettings().setJavaScriptEnabled(false);
view.stopLoading();
view.postDelayed(
new Runnable(){
#Override
public void run(){
Uri uri=Uri.parse(url);
Intent i=new Intent(Intent.ACTION_VIEW,uri);
i.setClassName("com.android.browser","com.android.browser.BrowserActivity");
startActivity(i);
}
}
,100
);
}
}
It worked. When I clicked the ads link, a new browser is opened in which ads site is displayed well, and the WebView was not redirected. When I push the return button, WebView show up again and I can continue watching video.
But there were still problems. If I repeat opening browser and returning to WebView for many times, the WebView might fail to block redirecting to the ads site. It is just redirected to the ads site. If I am lucky I could repeat opening and returning for 100 times. But sometimes It failed just when I repeat several times. I don't know why.
Does anyboday have any idea about how to improve it? Or is there another way to disable ads redirect?
You can build undetected webview build-id adblocker
I know it is too late for answering this question, however, for the sake of others who have the same question.
Well, you can build webview build-id adblocker, if you wish to prevent ads from loading, and provide smooth experience to the users, I am confident, because I have already implemented it in may app.
The Idea
Is to have a black list of all possible ad-serves domain name, then while webview load resources, you will prevent loading from black list domains. so it depends on how many ads-serves domain you have in the black list, fortunately, there is one website (pgl.yoyo.org/as/) which provide you with a very long list of ad-serves domai names, and listed them in many flavoures.
you can read this article for:
how to implement webview build-id adblocker
, you will build it %100 as long as you follow step by step instructions.
A summary of what we need to do:
Get the list of ad hostnames from pgl.yoyo.org.
Save the list somewhere, load it when application starts.
UseWebViewClient.shouldInterceptRequest(WebView, String) to intercept
requests.
Check if the request URL belongs to one of the hostnames in
the list and override it, returning a dummy resource instead of the
actual one, which is supposed to be ads
I have an application showing a WebView which shows information that includes street addresses like "123 Main St., Citytown, NY". However, when any of these addresses are tapped, it highlights briefly and the usual browser behavior of launching the Google Maps app is triggered.
I would like to prevent that behavior from occurring because some of the addresses aren't meant to be selectable. Is there anything I can do?
Update:
A commenter asked me to paste an example HTML snippet that triggers the behavior.
<hgroup class="unit list_item_body">
<h2 class="thick truncated heading">
Foobar
</h2>
<h3 class="truncated subheading">
123 East Market St., Charlottesville, VA, 22902
</h3>
</hgroup>
Notice there's no link on the address. Nevertheless, tapping the address triggers the behavior of launching Maps. This occurs whether I'm accessing the site through the WebView or viewing the site itself.
I figured this out. This meta tag will preclude the browser controls from hijacking address strings:
<meta name="format-detection" content="address=no">
Take a look at WebViewClient.shouldOverrideUrlLoading
webView.setWebViewClient(new WebViewClient() {
public boolean shouldOverrideUrlLoading(WebView view, String url) {
boolean shouldHandle = true;
//Check if you want to override the loading of the URL and set shouldHandle accordingly
return shouldHandle ;
}
});
I have a WebView in one of my Activities where I want to load a Html page. The page contains jquery-mobile and some html. So I do the following in my Activity :
mWebView=(WebView) findViewById(R.id.MyWebView);
mWebView.getSettings().setJavaScriptEnabled(true);
mWebView.setWebViewClient(new WebViewClient(){
[...]
});
mWebView.loadUrl("http://www.mymobilepage.html");
The problem is that the page gets loaded and displayed on the emulator, and on a HTC Desire, but when I try to load it on a LG Optimus One nothing gets displayed. The events onPageStarted and onPageFinished both get fired in my WebViewClient but just a blank page is displayed, and also I don't have any errors in my LogCat.
Thanks in advance.
When onPageFinished is called, the page may not be completely rendered. The documentation states:
Notify the host application that a page has finished loading. This method is called only for main frame. When onPageFinished() is called, the rendering picture may not be updated yet. To get the notification for the new Picture, use onNewPicture(WebView, Picture).
However, note that onNewPicture is documented as deprecated and obsolete. I ask about a replacement/alternative here.
This should be a comment, but since there is a bit of code on it I've added as response.
Try changing default background to transparent and alerting as soon as the page is loaded, just to be sure that at least the html is being interpreted:
mWebView = (WebView) this.findViewById(R.id.webview);
mWebView.setBackgroundColor(0);
mWebView.getSettings().setJavaScriptEnabled(true);
mWebView.getSettings().setJavaScriptCanOpenWindowsAutomatically(false);
mWebView.setWebViewClient(new WebViewClient(){
#Override
public void onPageFinished(WebView view, String url)
{
super.onPageFinished(view, url);
view.loadUrl("javascript:(function() { alert('hello'); })()");
} });
and when loading the webpage:
mWebView.clearView();
mWebView.loadUrl("http://yourmobilepage.something/");
and let us know if something happened.
Try this:
webView.post(new Runnable() {
#Override
public void run() {
// Your code here...
}
});
Have you checked your html/js code with different versions on the emulator? Newer Android versions have newer versions of WebKit, that might be the problem.
I would also check if you have LogCat set to show Error messages only, or Debug+Info+Warning+Error messages. According to this, the javascript errors should show up as Debug messages.
I had a similar issue to this, I found that calling clearview and then reload seemed to clear it up -- as in:
mWebView.clearView();
mWebView.loadUrl("http://yourmobilepage.something/");
mWebView.reload();
My experience is that loading websites in a WebView is much slower than performing the same actions in the Android Web Browser. I can see that all files have been loaded in my Apache log, it will take a few seconds until the page is displayed in the WebView control, however. Opening the same page in the native Web browser will result in an immediate display. It seems that rendering is somehow crippled.
Which browser settings do we have to apply in order to achieve the same performance as loading the page in the native web browser?
Our current settings:
browserset.setLoadsImagesAutomatically(true);
browserset.setJavaScriptEnabled(true);
browserset.setDatabaseEnabled(true);
browserset.setDatabasePath("data/data/com.xxx/databases");
browserset.setDomStorageEnabled(true);
browserset.setRenderPriority(WebSettings.RenderPriority.HIGH);
browserset.setSupportZoom(false);
browserset.setUserAgentString( browserset.getUserAgentString() + " (XY ClientApp)" );
browserset.setAllowFileAccess(true);
browserset.setSavePassword(false);
browserset.setSupportMultipleWindows(false);
browserset.setAppCacheEnabled(true);
browserset.setAppCachePath("");
browserset.setAppCacheMaxSize(5*1024*1024);
I finally got the reason of android webview bad performance issue.
Notice the image below... It used 12 seconds from OnPageStarted to OnPageFinished. Because it should load CSS,javascript and ... AJAX...
I notice that JQuery and JQueryMobile need load all DOM struct in Html.So if I lazy load the javascript after OnPageFinished,it should show page faster.
First use setTimeout instead of $(document).ready(function() {}); in JQuery.Then use lazyload javascript file.
The final html and javascript is:
<script src="/css/j/lazyload-min.js" type="text/javascript"></script>
<script type="text/javascript" charset="utf-8">
loadComplete(){
//instead of $(document).ready(function() {});
}
function loadscript()
{
LazyLoad.loadOnce([
'/css/j/jquery-1.6.2.min.js',
'/css/j/flow/jquery.flow.1.1.min.js',
'/css/j/min.js?v=2011100852'
], loadComplete);
}
setTimeout(loadscript,10);
</script>
You can find lazyload-min.js in http://wonko.com/post/painless_javascript_lazy_loading_with_lazyload
After do that,you can see the log image below:
Now, it only takes 2 seconds from OnPageStarted to OnPageFinished.
I posted the article at https://wenzhang.baidu.com/page/view?key=22fe27eabff3251f-1426227431
But it was written in Chinese:)
I ran into a similar issue, and after some heavy debugging noticed the native browser and WebView browser seem to be using different caches.
This code can be used to disable the WebView cache, and made WebView much faster for me (though at the expense of not caching). Note that it uses private APIs, so by using it you're risking the code will break in future releases:
try
{
Method m = CacheManager.class.getDeclaredMethod("setCacheDisabled", boolean.class);
m.setAccessible(true);
m.invoke(null, true);
}
catch (Throwable e)
{
Log.i("myapp","Reflection failed", e);
}