I am using a webview to submit a form and redirect. When the form is submitted successfully it will print a json response to the console.
My question is how can I get the jsonData String from the client?
chromium: [INFO:CONSOLE(1)] "Callback....jsonData, etc"
webView.setWebViewClient(new WebViewClient() {
#Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
// Insert your code here
return true;
}
#Override
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
}
});
You could extend the WebViewClient class and create a method to intercept the POST request made from clicking the form post button in the HTML in your WebView. Then, make the HTTP POST request in the code, rather than in the WebView and parse the results anyway you wish, then refresh the WebView any way you wish at the end of it all. There is an example of doing so here:
https://github.com/KeejOow/android-post-webview/blob/master/PostWebview/postwebview/src/main/java/com/solidsoftware/postwebview/InterceptingWebViewClient.java
I need to show a login webpage link in webview and the link is something like below
url = "https://test-dev.test.com/as/authorization.oauth2?client_id=com.test.td&response=code&value=id test mail&redirect_uri=com.test.ap://oauth2/test";
[Modifed the actual URL with different names]
On this page, we have to enter username and password. Clicking on login will take you to OTP screen, after entering the OTP result will be a url response and from this I need to read the code. Using this code I have to make a request to get the authentication token for the session. For token request, response will be Json.
Now I need help in resolving the below:
Currently its opening in browser and not in webview. But other links are opening in webview within the app except the above link.
Which is the call back method for handling response from this transaction.
Below is my code:
private WebView webView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
webView = (WebView) findViewById(R.id.webView);
webView.setWebViewClient(new MyWebViewClient());
WebSettings settings = webView.getSettings();
settings.setJavaScriptEnabled(true);
webView.loadUrl(getAuthorizationURL());
webView.setHorizontalScrollBarEnabled(false);
webView.setWebContentsDebuggingEnabled(true);
// webView.addJavascriptInterface(new MyJavaScriptInterface(this), "HtmlViewer");
}
private String getAuthURL() {
Uri.Builder builder = new Uri.Builder();
builder.scheme("https")
.authority("test-dev.test.com")
.appendPath("ta/authorization.oauth2")
.appendQueryParameter("client_id", "com.test.td")
.appendQueryParameter("response", "code")
.appendQueryParameter("value", "id test mail").appendQueryParameter("redirect_uri", "com.test.ap://oauth2/test")
String url = Uri.decode(builder.build().toString());
//url = "https://www.google.com/";
// url = "https://developers.google.com/webmaster-tools/search-console-api/about";
return url;
}
private class MyWebViewClient extends WebViewClient {
#Override
public boolean shouldOverrideUrlLoading(WebView webView, String url) {
System.out.println(" shouldOverrideUrlLoading :============ " + Uri.parse(url).getHost() + " url " + url);
// if(url.contains("dev.test.com")){
// webView.loadUrl(url);
// return false;
// }
Intent i = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
startActivity(i);
return true;
}
}
This sounds like you're doing an OpenID authentication. You're implementation of shouldOverrideUrlLoading() is both firing an intent which will most likely go to the default web browser, and returning true. The return value tells Android whether you're taking control of loading the page (true) or leaving it to the web view (false). If you don't take control of handling the URL, the web view will try to load it like a normal page.
You're also immediately directing the web view to your authorization URL in your onCreate code. I'm thinking this is part of the confusion over the navigation behavior you're seeing.
For this kind of authentication process, you don't want to override loading the OTP page. Let the web view handle that just like anything else. What you want to do is capture the URL response. Your if statement within shouldOverrideUrlLoading should trap the response URL, consume the contents, and respond true to let the web view know you've taken care of that URL. Everything else should be handled by the web view.
Finally, the commented version of the code looks to me like it would send you into an infinite loop, the way you have it written. You're telling the web view to load the authorization URL, which will lead back to your web client code, which will trap the URL, causing it to load the URL...
The problem is rather simple.
In the application we want to keep track of the current url being displayed. For that we use shouldOverrideUrlLoading callback from the WebViewClient by saving the url into a class field for every update. Here is the relevant code:
mWebView.getSettings().setJavaScriptEnabled(true);
mWebView.getSettings().setDomStorageEnabled(true);
mWebView.setWebViewClient(new WebViewClient() {
#Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
mCurrentUrl = url;
// If we don't return false then any redirect (like redirecting to the mobile
// version of the page) or any link click will open the web browser (like an
// implicit intent).
return false;
}
#Override
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
...
}
});
mWebView.loadUrl(mInitialUrl);
However, there is at least one scenario, where the callback never gets triggered and the mCurrentUrl field doesnt get updated.
The url: https://m.pandora.net/es-es/products/bracelets/556000
Last updated url (shouldOverrideUrlLoading never gets called when clicking the product): https://m.pandora.net/es-es/products/bracelets
I have tried with callbacks like onPageStarted(), but the url also gets filtered and there doesn't seem to be an accessible one upstream since its protected code.
Reading android documentation about WebView I found this:
https://developer.android.com/guide/webapps/migrating.html#URLs
The new WebView applies additional restrictions when requesting resources and resolving links that use a custom URL scheme. For example, if you implement callbacks such as shouldOverrideUrlLoading() or shouldInterceptRequest(), then WebView invokes them only for valid URLs.
But still doesnt make sense since the above url is generic and should meet the standard.
Any alternative or solution to this?
When you click a product on that web page, it loads the new content in with JavaScript and updates the visible URL in the address bar using the HTML5 History APIs.
From the above MDN article:
This will cause the URL bar to display http://mozilla.org/bar.html, but won't cause the browser to load bar.html or even check that bar.html exists.
These are sometimes called single-page applications. Since the actual loaded page doesn’t change, the WebView callback for page loads isn’t called.
In case you know precisely what kind of HTTP request you want to intercept, you could use the shouldInterceptRequest callback that gets called for each request. It’s likely that the web application loads some data from an API, for example when a product is shown, which you could then detect.
If detecting this isn’t possible, but you’re in control of the web application, you could use the Android JavaScript interface to invoke methods within the Android application directly from the web page.
If you’re not in control of the loaded page, you could still try to inject a local JavaScript file into the web page and observe when the history APIs are used, then call methods in your Android application over the JS interface. I tried observing these events in Chrome with the method described in the previous link and it seems to work fine.
Maybe this helps someone, although the signature in the question is correct, but Android Studio suggests the following method signature:
public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
which then never called. It took me a while to notice that the right signature is:
public boolean shouldOverrideUrlLoading(WebView view, String url) {
Sorry if this not 100% fit the question, but I believe this may help someone in the same situation. It's not always easy to notice that the second parameter is different.
Please omit mWebView.getSettings().setDomStorageEnabled(true);
Then again try, if a new url found then will invoke shouldOverrideUrl()
I had the same problem like you, and I've finished with extending of WebViewChromeClient with listening for callback to
public void onReceivedTitle(WebView view, String title)
mWebView.setWebChromeClient(mSWWebChromeClient);
private WebChromeClient mSWWebChromeClient = new WebChromeClient() {
#Override
public void onReceivedTitle(WebView view, String title) {
super.onReceivedTitle(view, title);
if (!view.getUrl().equals(mCurrentUrl)) {
mCurrentUrl = view.getUrl();
//make something
}
}
};
For me the problem was below line -
mWebView.getSettings().setSupportMultipleWindows(true);
After removing it shouldOverrideUrlLoading was being called.
after stumbling on this problem and searching for solutions, I've found the one that worked perfectly for me
https://stackoverflow.com/a/56395424/10506087
override fun doUpdateVisitedHistory(view: WebView?, url: String?, isReload: Boolean) {
// your code here
super.doUpdateVisitedHistory(view, url, isReload)
}
Another approach you can try: Catch the url by javascript side. Initialize your webView with this:
webView.addJavascriptInterface(new WebAppInterface(getActivity()), "Android");
After page is completely loaded (You can use an algorithm to check this like this https://stackoverflow.com/a/6199854/4198633), then:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
webView.evaluateJavascript("(function() {return window.location.href;})", new ValueCallback<String>() {
#Override
public void onReceiveValue(String url) {
//do your scheme with variable "url"
}
});
} else {
webView.loadUrl("javascript:Android.getURL(window.location.href);");
}
And declare your WebAppInterface:
public class WebAppInterface {
Activity mContext;
public WebAppInterface(Activity c) {
mContext = c;
}
#JavascriptInterface
public void getURL(final String url) {
mContext.runOnUiThread(new Runnable() {
#Override
public void run() {
//do your scheme with variable "url" in UIThread side. Over here you can call any method inside your activity/fragment
}
});
}
}
You can do something like that to get url, or anything else inside the page.
Add
webView.getSetting().setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW);
then shouldOverrideUrl will be triggered.
onProgressChanged is always triggered when reloading, loading new page with userclick or XmlHttpRequest.
Compare the URL of previous load and the current load, you'll know it's reloading or loading a new page. This works perfect in my single page Web App.
First declare a global variable to store last URL.
String strLastUrl = null;
Then override onProgressChanged(WebView view, int progress)
mWebView.setWebChromeClient(new MyWebChromeClient(){
#Override
public void onProgressChanged(WebView view, int progress) {
if (progress == 100) {
//A fully loaded url will come here
String StrNewUrl = view.getUrl();
if(TextUtils.equals(StrNewUrl,strLastUrl)){
//same page was reloaded, not doing anything
}else{
//a new page was loaded,write this new url to variable
strLastUrl = StrNewUrl;
//do your work here
Log.d("TAG", "A new page or xhr loaded, the new url is : " + strLastUrl);
}
}
super.onProgressChanged(view, progress);
}
});
I've also tried above solutions, but most of them have issue in my case:
doUpdateVisitedHistory sometimes can not return correct url after "#" made by XmlHttpRequest.
My case is a single page web App. The web App uses javascript with
xhr to display new page when user click an item. For example, user is
currently at http://example.com/myapp/index.php , after clicking, the
browser url becomes
http://example.com/myapp/index.php#/myapp/query.php?info=1, but in
this case, doUpdateVisitedHistory returns
http://example.com/myapp//myapp/
onReceivedTitle doesn't work in my case because the response retrieved by XMLHttpRequest does not have <title></title> tag.
The JavascriptInterface method also works, but I'm afraid it will cause
security related issues with javascript.
public class AndroidMobileAppSampleActivity extends Activity {
/** Called when the activity is first created. */
String mCurrentUrl="";
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
WebView mWebView = (WebView) findViewById(R.id.mainWebView);
WebSettings webSettings = mWebView.getSettings();
webSettings.setJavaScriptEnabled(true);
mWebView.setWebViewClient(new MyCustomWebViewClient());
mWebView.setScrollBarStyle(View.SCROLLBARS_INSIDE_OVERLAY);
mWebView.loadUrl("https://m.pandora.net/es-es/products/bracelets/556000");
}
private class MyCustomWebViewClient extends WebViewClient {
#Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
mCurrentUrl = url;
Log.i("mCurrentUrl",""+mCurrentUrl);
view.loadUrl(url);
return true;
}
}
}
try this one...
In my android app the user can like my facebook page. Therefore I use a webview that loads a webpage that contains a facebook like box. The page is loaded well into the webview and then the following happens:
WebView loads my webpage with a facebook like box
By clicking on the Like button the user is redirected to the facebook login page
After login the user is redirect again back to my custom like page
But when clicking the like button the user is again redirected to the facebook login page
So I would expect, that the like is possible after logging in. It seems somehow as if the webview does not remember the login. Therefore, what do I have to do to repair this.
The following screenshot sequence shows what's happening:
I want to avoid using the facebook sdk for android! Especially this procedure works very good in my iphone version of the app.
Here is some code that is used to implement my desired functionality:
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final WebView fbWebView = (WebView) findViewById( R.id.facebookWebView );
fbWebView.getSettings().setJavaScriptEnabled(true);
fbWebView.setWebViewClient( new WebViewClient() {
#Override
public WebResourceResponse shouldInterceptRequest (WebView view, String url) {
Log.d("call url", url );
if ( url.contains("login.php?skip_api_login") ) {
fbWebView.loadUrl("http://www.example.de/iphone_facebook_like_page.html");
return null;
}
if( url.contains("user_successfully_liked") )
fbWebView.loadUrl("http://www.example-success.de");
return null;
}
});
fbWebView.loadUrl("http://www.example.de/iphone_facebook_like_page.html");
}
EDIT: I also tried the following to accept cookies but none of this worked
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
CookieSyncManager.createInstance(this);
CookieSyncManager.getInstance().startSync();
CookieManager.setAcceptFileSchemeCookies(true);
CookieManager.getInstance().setAcceptCookie(true);
//rest is the same...
Overrding didn't work either
#Override
public boolean shouldOverrideUrlLoading(WebView view, String url)
{
view.loadUrl(url);
return true;
}
You have that error, because WebView isn't remembering cookies. Read that question on SO : WebView and Cookies on Android
Not sure if you've gotten an answer to your problem, but I tried a combination of these instructions and the code below, and that worked for me:
#Override
protected void onCreate(Bundle bundle) {
super.onCreate(bundle);
...
WebView webView = new WebView();
WebSettings settings = webView.getSettings();
settings.setJavaScriptEnabled(true);
settings.setAppCacheEnabled(true);
settings.setDomStorageEnabled(true);
settings.setGeolocationEnabled(true); // this last one is probably optional
webView.setWebViewClient(new WebViewClient());
webView.loadUrl(<your url here>);
...
}
You will then need to call the corresponding methods for the CookieSyncManager singleton class as outlined in the link above. Note that the sync class is deprecated in API Level 21: see details on CookieSyncManager class
I'm trying to allow users in my android app to log in to their google account so i can access their contacts for the purpose of creating a friends list, and I'm trying to use OAuth to do this.
So far I have formed the URL and have created the webview which loads the page. I proceed to sign in but i dont know how to assign the code from the URL to the code value in my activity. also i don't know whether my Onpagestarted method is working correctly
Can someone either tell me either an alternate method/technique to authenticate with google using OAuth2 or tell me what are the issues with my current way as once I reach the page with the code my view remains the WebView and not the textview with the code as I want it to?
I would like to automate the entire process after the User has signed into the google page in my WebView but so far my code keeps getting stuck at the page with the Authcode which leads me to believe that the Authcode is not being detected by my program.
NOTE: I do not want to simply use the account that is signed into the Android Device (unless obviously the user chooses to enter the same account)
This is the code from the Activity in which I want to acquire the Auth Code/Token and get the Contacts for my User though I don't mind displaying the contacts in a later activity.
WebView browser;
final String username = "gotsingh#gmail.com";
private myWebViewClient client;
String code;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_add_friends);
browser = (WebView) findViewById(R.id.webview);
client = new myWebViewClient();
WebSettings webSettings = browser.getSettings();
webSettings.setJavaScriptEnabled(true);
browser.setWebViewClient(client);
getAuthCode(client);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.add_friends, menu);
return true;
}
public void getAuthCode(myWebViewClient myClient){
browser.loadUrl(url4);
while (myClient.authCode!= null){
showCode(myClient);}
}
public void showCode(myWebViewClient myClient){
code = myClient.authCode;
TextView text = new TextView(this);
text.setText(code);
setContentView(text);
}
Below is my modified WebViewClient class
public class myWebViewClient extends WebViewClient{
boolean authComplete = false;
String authCode = null;
#Override public void onPageStarted(WebView view, String url, Bitmap favicon){
super.onPageStarted(view, url, favicon);
if (url.contains("?code=") && authComplete != true) {
int codeStart = url.indexOf("?code=")+6;
authCode = url.substring(codeStart);
Log.i("", "AUTHCODE : " + authCode);
authComplete = true;
System.out.println(authCode);
}else if(url.contains("error=access_denied")){
Log.i("", "ACCESS_DENIED_HERE");
authComplete = true;
}
}
}
Also, if I could get some general guidance on doing POST/GET requests in java to recieve JSON data from google. I am very new to android development and I have close to 0 experience dealing with html/http requests.
Take a look at this sample. It is not against Google, but the principles are the same. You may want to consider using the "implicit" flow in OAuth to avoid storing secrets in the device.