I'm using Android, and I've created a Webview which nicely opens my HTML page (page "A").
Now, I want to follow some links I have on page "A", which go to page "B".
If I click on a linkl defined with
<a href="page_b.html"> everything is fine, and the Webview behaves just like a normal browser, goinmg to the selected page.
But if I click a link defined as <a href="page_b.html?param=x"> all I get is a "Web page not found".
The same if I use an anchor like <a href="page_b.html#2">.
How can I pass parameters between different HTML pages within the same Webview?
EDIT:
Nevermind, I managed to pass the parameter I needed using localStorage.
Of course, after a gazillion dry runs, I discovered I had to enable it in the WebView with settings.setDomStorageEnabled(true) :D
In the end, I discovered I had to set settings.setDomStorageEnabled(true) in the WebView, and the easiest solution for my problem I found was:
In "Page A.html", I intercept the onClick event of the links, and use localStorage to store the id:
$(".link").each(
function()
{
divId=+$(this).attr('id');
$('#'+divId).click(function(e)
{
localStorage.my_id=divId;
});
});
In "Page B.html", I retrieve the stored id:
$(document).ready(
function()
{
divId=localStorage.my_id;
isReady();
});
I can't reproduce the problem, try this:
this.getWindow().requestFeature(Window.FEATURE_PROGRESS);
...
vw = new MyWebView(this);
vw.setWebChromeClient(new WebChromeClient() {
public void onProgressChanged(WebView view, int progress)
{
activity.setProgress(progress * 100);
if(progress == 100)
activity.setTitle(title);
}
})
;
Related
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.
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've done alot of Googling on this and haven't found an answer. I have a webview as part of an overall layout with other controls. I use the webview to show formatted text (recipe descriptions with bold and italic fonts) and URLs. The URLs point to Youtube and are fully qualified (ie. http://www.youtube.com/watch?v=fyzyhuVgzRE). When I click on the link in my web view, the web view control itself disappears from the layout (leaving the rest of the controls on the page intact) and the default web browser does not launch.
It behaves as if I've set the visibility of the web view to GONE, but I do not manipulate the visibility of any of the controls on the layout.
One interesting clue in the LogCat output is an INFO level message from the OS:
MotionRecognitionManager .unregisterListener : / listener count = 0->0,
listener=android.webkit.ZoomManager$1#41ac2fc0
Any ideas what would cause this behavior?
EDIT
Here is how I setup the webview in the onCreate() method of the activity:
webView1 = (WebView)findViewById(R.id.webView1);
webView1.getSettings().setJavaScriptEnabled(true);
webView1.getSettings().setAllowFileAccess(true);
webView1.setWebViewClient(new MyWebViewClient());
And the MyWebViewClient class:
private class MyWebViewClient extends WebViewClient {
public boolean shouldOverrideUrlLoading(WebView view, String url) {
if (url != null && url.startsWith("http://")) {
view.getContext().startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(url)));
return true;
} else {
return false;
}
}
}
Oddly enough the shouldOverrideUrlLoading is never called.
Well, I'm a dope. It turns out that the double quotes in the href attribute of the anchor were doubled. My system integrates with a MySQL db over the web and I have to do alot of transformation of data between MySQL/PHP and Android/SQLite. During one of these transformations I double-escaped the quotes in the href. So what should have been:
Link Text
was instead rendered as:
Link Text
In the web view the resulting URL looked fine. It was underscored properly and looked like any other URL. It is odd though that simple doubling the quotes causes the behavior. I'll see if there is a known bug like this for Android. At the very least the WebView should through some kind of exception, not simply disappear from the screen.
I faced this type of behavior when webview tries to load content it cant handle. Intercept ref clicks using WebViewClient and send intent to open this ref in external application. Check this thread.
My Android app uses a WebView to display a bunch of HTML code that I generate 'on the fly'. The HTML code is loaded using the following code:
StringBuilder builder = new StringBuilder();
// HTML
builder.append("<html><head><link rel=\"stylesheet\" href=\"file:///android_asset/style.css\" type=\"text/css\">");
builder.append("</link></head><body>");
builder.append(getThreadBody());
builder.append("</body></html>");
webview.loadDataWithBaseURL("file:///android_asset/", builder.toString(), "text/html", "utf-8", null);
This all works really nice. Note that I'm not loading an actual HTML file, I'm merely creating a string that represents some (hopefully valid) HTML and load it in the WebView.
Anyway, the HTML I generate (the part in the 'getThreadBody' method) contains named anchors, for example like this;
<div>
<a name="949823">Anchor 1</a>
<div>All kinds of stuff</div>
<a name="895984">Anchor 2</a>
<div>...</div>
</div>
Now in some cases I want the WebView to navigate to one of those anchors as soon as I load the HTML. As far as I understand the WebView supports navigating (scrolling in this case) to named anchors, but the catch is that nobody is clicking any hyperlinks to those anchors, I want the WebView to scroll when it is loaded (it is no problem if there is a short delay between loading the HTML and scrolling, my point is that it should not require user interaction).
I believe the behavior can be achieved by using the WebView's loadUrl method and supplying a URL with the anchor in place, eg
webview.loadUrl("file:///android_asset/page.html#895984", ...)
However, since I am not saving the HTML to any file I cannot use this method... Of course saving the HTML to a temporary file may be a solution but I'd like to keep that as a last resort, there must be a simpler way?
How can I achieve this? Thanks!
Resolved
Here's the code that works. I found a short delay was required to let the page load before executing the javascript otherwise it was kind of 50/50 whether it worked or not...
StringBuilder builder = new StringBuilder();
// HTML
builder.append("<html><head><link rel=\"stylesheet\" href=\"file:///android_asset/style.css\" type=\"text/css\">");
builder.append("</link>");
builder.append("<script>");
builder.append("function scrollAnchor(id) {");
builder.append("window.location.hash = id;}");
builder.append("</script>");
builder.append("</head><body>");
builder.append(getThreadBody());
builder.append("</body></html>");
webContents.loadDataWithBaseURL("file:///android_asset/", builder.toString(), "text/html", "utf-8", null);
Timer timer = new Timer();
timer.schedule(new TimerTask() {
#Override
public void run() {
String id = "895884";
webContents.loadUrl("javascript:scrollAnchor(" + id + ");");
}
}
}, 250);
How about control it by JavaScript? I didn't try it but maybe this is a clue.
builder.append(getThreadBody());
builder.append("<script>window.location.hash="949823";</script>");
builder.append("</body></html>");
Remember enable javascript for WebView.
----Additional Answer----
I saw that you use TimerTask to load the javascript, That works but I think there is another better way. WebView have a callback named onPageFinished and it will be trigger when WebView finish loading webpage. You could inject your JS there.
webContents.setWebViewClient(new WebViewClient(){
#Override
public void onPageFinished(WebView view, String url) {
String id = "895884";
webContents.loadUrl("javascript:scrollAnchor(" + id + ");");
}
});
Hope this is useful!
First of all, you don't need to use javascript. If you loaded content with
webContents.loadDataWithBaseURL("some://dummy/url",...);
you can simply scroll to anchor with
webContents.loadUrl("some://dummy/url#anchor");
Secondly, doing that on onPageFinished without additional control results in never ending loop! When loadUrl finishes onPageFinished get's called again and again.
If you have external action (eg: onclick event), try this code
public static void scrollToAnchor(String id) {
sWebView.loadUrl("javascript:document.getElementById(\"" + id + "\").scrollIntoView()");
}
If you have in your layout the webview inside a nestedScrollView the nesting will prevent the scrolling events from working properly. Once you take it out it will work without any need to reload or add javascript.
Additionally if you want to keep the nestedScrollView and dont care if the user cannot scroll past that section you can add fillViewPort=true to the nestedScrollView and android:layout_height="wrap_content" to the webview.
It would look something like:
<androidx.coordinatorlayout.widget.CoordinatorLayout>
<com.google.android.material.appbar.AppBarLayout>
...
</com.google.android.material.appbar.AppBarLayout>
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewPort=true
app:layout_behavior="#string/appbar_scrolling_view_behavior">
<WebView
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</androidx.core.widget.NestedScrollView>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
if you load the html from the assets:
webView.loadUrl("file:///android_asset/htmls/mypage.html#anchor");
and you can move to the anchor inside a web page:
webView.loadUrl("http://www.stackoverflow.com/mypage.html#anchor");
is there a way to hide or disable the URL field in the locationbar? In my case the device is a tablet run as a kiosk browser, so only one URL is allowed.
I fixed this by changing the code in the ChildBrowser.java to
private void navigate(String url) {
InputMethodManager imm = (InputMethodManager)this.ctx.getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(edittext.getWindowToken(), 0);
if (!url.startsWith("http")) {
this.webview.loadUrl("http://" + url);
}
this.webview.loadUrl("http://www.my-only-allowed-site.example.org");
this.webview.requestFocus();
}
This works well, but is not nice. You can still see the URL. I´d like to have any of this possible solutions:
1) completely hide the URL field
2) hide the softkeyboard when clicking on the URL field
3) set the URL fonts color to black
Any idea?
thanks in advance
If you modify the source code for the plugin, you can hide the url field and close button by modifying the source code for the plugin and just comment out the following line:
toolbar.addView(back); //shows the back button
toolbar.addView(forward); //shows the forward button
//toolbar.addView(edittext); //shows the URL - comment this line out to hide the URL
toolbar.addView(close); //shows the close button
Edit: oops, I just saw from your comment that you figured this out in the same way!
I don't know anything about Phonegap but I'm assuming you're using a standard Android WebView?
If you're seeing a URL bar then it usually means that the default system browser is being invoked to handle the loading of the page. To prevent this set a WebViewClient as follows...
this.webview.setWebViewClient(new WebViewClient() {
public boolean shouldOverrideUrlLoading(WebView view, String url) {
return false;
}
});
The shouldOverrideUrlLoading(...) method is called by the host application to see if it should override the loading by using Activity Manager to find a suitable app (usually the stock browser app). Returning false means the WebView instance wants to handle its own URL loading and you won't see a URL bar at all.
EDIT: If that fixes it but also looses the navigation buttons then I suggest you maintain your own history collection and provide your own buttons for back/forward/exit.