I'm thinking of implementing a HTML welcome panel to our Android app, which presents news and offers on the start-up screen. My question is now, if I present an offer to a specific place (with an id string) can I trigger a callback from the WebView (maybe via Java Script) to the Android app and passing that id string to make it start a new Activity which loads and shows data from a server (JSON) depending on that id string?
The second part is already implemented and working. My main concern is how to get the id string from the HTML WebView back to the Android app when the user clicks on it.
We prefer to use a WebView for that specific welcome panel, because it gives us more flexibility to customize by using HTML.
It's probably better to use WebView.addJavascriptInterface, rather than overload onJsAlert.
yes indeed you can good sir! If you show the data in a javascript Alert, then you can capture it like this. It might not be the most neat way, but it works =)
private void loadWebViewStuff() {
myWebView.setWebChromeClient(new MyWebChromeClient());
myWebView.loadUrl(URL);
}
final class MyWebChromeClient extends WebChromeClient {
#Override
public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
//"message" is what is shown in the alert, here we can do whatever with it
}
}
Related
I have a web app thats working with Javascript alerts on most pages. Now I have recently created a WebView application for the same app. The app works fine, the alerts show.
I've seen solutions that suggest binding JavaScript code to Android code and then call these methods for example to show toast.
I have no doubt that this works, but now, for me, this means I'd have to re-write the code(s) that trigger these alerts.
My question is, is there a way to automatically capture all the alerts and display their contents as toasts instead?
You can use a WebChromeClient:
https://developer.android.com/reference/android/webkit/WebChromeClient
Create an instance of it, set it to your webview, and override onJsAlert.
Be sure to read the docs, to return the correct value, so it doesn't show the javascript alert also.
Thanks to Moonbloom's answer and this answer also.I managed to come with a solution that works exactly as I wanted. So for anyone who will stumble upon the same issue in the future, the snippet below is for you:
mWebView.setWebChromeClient(new WebChromeClient() {
#Override
public boolean onJsAlert(WebView view, String url, String message,
final JsResult result) {
Toast.makeText(getApplicationContext(), message, Toast.LENGTH_LONG).show();
result.confirm();
return true;
}
});
Where mWebView is a WebView instance.
I need to load an HTML page with a form that has only one number input field. The desired behavior is:
When the user enters some data in this field and clicks on forward button from the Android's keyboard, a function is executed and a value appears, without taking him to another page.
The problem is that when the user clicks forward, the app crashes due to a FileUriExposedException. After searching a bit, I saw that this error is related to this bug.
One of the solutions shown in (2) was add an extra invisible form field, but does anyone know another solution? Because I think that changing all HTML forms will be something much more time consuming than trying a solution via Android.
Not sure if avoiding clicking forward would help, but here is a way you can submit to the form without the user typing in the form directly, if you have them enter the number into an edittext, save its value and then use something like this. You can set the webview visibility to invisible if you want to start and then make it visible after it submits. You can find out the IDs of the elements in the form by right clicking and hitting Inspect.
mWebView.getSettings().setJavaScriptEnabled(true);
mWebView.getSettings().setDomStorageEnabled(true);
mWebView.loadUrl(getString(R.string.form_url));
mWebView.setWebViewClient(new WebViewClient(){
#Override
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
String fieldID;
String submitButtonID;
int numberTypedInByUser
mWebView.loadUrl("javascript: {" +
"document.getElementById('"+fieldID+"').value = '"+numberTypedInByUser+"';" +
"var z = document.getElementById('"+submitButtonID+"').click(); };");
}
});
I want to make an app that allows users to log-in multiple accounts of same site using different webview.
For example, I have 2 WebView.
Each WebView will load the same site such as gmail.com.
And user can log-in using separate account in separate WebView.
But the problem I am facing is that the 2 WebView always log-in to same account.
I've googled a lot, and here are some related titles,
Facebook MultiLogin in Android Webview
Using WebView for multi-page login to website and fetch data
Multiple Log-Ins on Separate WebViews? (Android)
but still no acceptable answer is found.
Would it be possible in Android using WebView?
How can I achieve what I want?
The tricky part is android.webkit.CookieManager, used by WebView to keep cookies, is designed to be a singleton. This means there'll be only one CookieManager instance per Java/Dalvik process, and your multi WebView instances inside the same process share a same set of cookies.
Like #ToYonos proposed, you may try overriding certain hooks to work around this, but I don't think it will 100% work...Also think about android.webkit.WebStorage: it's another singleton!
That said, this might work a bit more reliably: duplicate your top level WebView activity in manifest and assign them to run in different processes:
<activity
android:name=".WebViewActivity" />
<activity
android:name=".WebView1Activity"
android:process=":web1" />
<activity
android:name=".WebView2Activity"
android:process=":web2" />
...
So that you'll have isolated processes and different CookieManager/WebStorage instances.
But be warned: different WebStorage instances still writes to same path(s) in your app data folder! This may be worked around by calling webView.getSettings().setDatabasePath() to use different db paths for different processes, but this API has been deprecated in API level 19 (KitKat). Well as long as the web page you're visiting doesn't use HTML5 local storage this should be fine...
I think that you'll have to implement your own system. You could try something like that :
private static final String DOMAIN = "http://cookiedomain.com";
private final Map<WebView, String> cookiesMap = new HashMap<WebView, String>();
// [...]
WebView w = new WebView(this);
// Loading url and stuff
w.setWebViewClient(new WebViewClient()
{
public void onLoadResource (WebView view, String url)
{
// If cookies have already been stored for this WebView
if (cookiesMap.get(view) != null)
{
CookieManager.getInstance().removeAllCookie();
CookieManager.getInstance().setCookie(DOMAIN, cookiesMap.get(view));
}
}
public void onPageFinished(WebView view, String url)
{
// Check if the url matches the after-login page or whatever you want
boolean condition = ...;
if(condition)
{
// Getting new cookies
String cookies = CookieManager.getInstance().getCookie(DOMAIN);
cookiesMap.put(view, cookies);
}
}
});
// Do the same for the 2nd WebView
This is a simple example, to be improved, but it could be a good start for a sustainable solution.
Limits :
It will only work if each WebView does not make request at the same time as others. Otherwise, it will surely tangle cookies.
This will work for one domain only
I have an android application that loads a webview from a server. I do not have the server code so I cannot change anything in Javascript. I want to figure out when a button is being clicked in a webview and what is the label in the button. I do not know the Id, I just want to get the label.
I tried searching for this but could not find an answer. I found solutions where you can work in the javascript but in my case I cannot.
This suggestion may help to find useful information that could lead to determination of your button label. Override shouldOverrideUrlLoading(), shouldInterceptRequest() and/or onLoadResource() for the WebViewClient so you can get at the URL of any redirects.
Example:
webview.setWebViewClient(new WebViewClient() {
public boolean shouldOverrideUrlLoading(WebView view, String url) {
// Try to learn something useful from the 'url' here.
// Continue as normal, loading the 'url' within this WebView.
view.loadUrl(url);
return false; // Allow the WebView to handle the request.
}
// Optional: Add similar for "shouldInterceptRequest()" and/or "onLoadResource()".
});
Note: Overriding shouldOverrideUrlLoading() as above is the standard way to keep redirects within the same WebView rather than redirecting to the default browser application.
You might really want to check this page:
Building Web Apps in WebView (Google API Guides)
Specifically, it seems that addJavascriptInterface might be what you are looking for:
addJavascriptInterface(Object object, String name)
It allows you to execute your Java code from javascript and, paired with the ability to insert code in a page, it's an incredibly powerful tool for granting you a high level of coupling between your Activity and your page.
I think that at this point you will already know what to do, but I'll sketch a possible course of action anyway:
create a javascript interface with the callbacks you want executed in your activity when a button is pressed
as soon as your page loads, install the code to call your javascript interface in each button (or link) by injection
Hope this helps
Is it possible to capture touch events over a WebView in the activity that contains it, without loosing link functionality?
Consider a WebView showing a webpage with links. If the user taps on a link I would like the WebView to handle the touch event. If the user taps somewhere else I would like the activity to handle the touch event.
How can this be done?
Yes, it is.
(I can't elaborate more on this unless you are more specific on your question.)
If i understand your question correctly it'd seem difficult to interpret whether something is a link or not in the onTouchEvent() since all it knows about is X,Y coordinates (not html). However, off the top of my head it seems you could probably use the javascript binding piece in WebView to have javascript decide if the something is a link or not and act accordingly. Again, I haven't done this before nor tested it...just thinking out loud.
When initializing your WebView, try:
mWebView.setWebViewClient(new WebViewClientOverrider());
Then create a private class:
private class WebViewClientOverrider extends WebViewClient {
#Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
//TODO handle the link
return true;
}
}
Lastly, replace the TODO handle the link line with your own code for handling the link selection.
Or you can monitor the stack trace for:
android.webkit.CallbackProxy.uiOverrideUrlLoading()
See http://www.javapractices.com/topic/TopicAction.do?Id=78 for how to determine your stack trace from a throwable (created in an overriden WebView.loadUrl() method).