Login to website with WebView

warwound

Expert
Licensed User
Longtime User
I want to login to a website without using a WebView in one Activity and then, once successfully logged in, start another Activity and display webpages from that website using a WebView.
The webpages to be displayed in the WebView require that the user has successfully logged in.

The login script sets a session variable when i log in but that session is not available to the WebView so my user appears not to be logged in.

Does anyone know how i can create a logged in session without a WebView and that login will apply when i then use a WebView?

The login used an HTML form in a previous version of this app and it used a WebView to successfully login - all worked ok but now i need to do that login without using a WebView.
(This is not HTTP basic authentication).

I have complete control over the login script so can make any changes needed.

Any suggestions?

I've searched the www but found nothing that could be used in B4A.

Martin.
 

warwound

Expert
Licensed User
Longtime User
The best way to explain is this:

An HTML form can POST a username and password to a PHP script.

The PHP script does a database check on username and password and if successful it sets a SESSION variable.

So within a WebView or browser all the webpages check for this SESSION variable and offer logged in or not logged in content.

The WebView mainatains this session through use of cookies i believe.

Now i use a URLConnection in a library to POST the same username and password to the login script.
I added some debug statements to the login script and the username and password are being successfully sent.

For testing i didn't even bother checking with the database that the username and password were valid i simply set the same SESSION variable that is set when a WebView is used to login.

So the session stared with the URLConnection login is successful but of course the cookie that would exist if a WebView had been used to login does not get created and the WebView displays content for not logged in users.

I've been thinking about this and think it's a security issue - only a WebView should be able to create such a cookie and it's not good design to try and create that cookie with say a URLConnection.

BUT if it's possible to somehow get that cookie from the URLConnection and pass it to the WebView that would save me having to re-write a few scripts.

Otherwise i shall have to go back to the drawing board.
I'm using PreferenceActivity and could ask the user to enter their username and password in the preferences.
Then i could add a hidden form to the first webpage that the WebView displays and automatically log them in.

The app would still maintain two seperate logged sessions - one for the URLConnection and one for the WebView but to the user it would be transparent.

Martin.
 
Upvote 0

barx

Well-Known Member
Licensed User
Longtime User
Why are you against logging in with web view in the first place?

Sent from my HTC Desire Z
 
Upvote 0

lagore

Active Member
Licensed User
Longtime User
Hi can you save the returned cookies from the login process then load them into the webview before calling for the post login page.
 
Upvote 0

warwound

Expert
Licensed User
Longtime User
Why are you against logging in with web view in the first place?

The login form isn't the only form to submit without WebView - i mean replicate submit HTML form using URLConnection.

This other form has 25 text input elements/textareas holding a lot of text.
If i load this form in a WebView then i have the problem of saving restoring the user entered text on orientation change and the HTML form doesn't scale well to make full use of the available screen space.

So i want to create an Activity with 25 EditText inputs to replicate this form and submit to the same script that the original webpage form submits to - hence the need to be logged in.

A WebView displaying an HTML form just doesn't look as good or work as well as an Activity with EditText inputs.

Why are you using URLConnection? You should use Http library. It is much more powerful.

No real reason - i copy/pasted some java from one project to this and that copied code happened to use URLConnection.
I was under the impression that URLConnection was a better choice on newer versions of Android and that HTTPClient was a better choice for older versions - older being say before Eclair.

Hi can you save the returned cookies from the login process then load them into the webview before calling for the post login page.

This is exactly what i've searching for examples of with no luck.

As i have control over the server-side scripts my plan now is to create new scripts where needed for the mobile app to submit to instead of trying to submit to the scripts used by the HTML forms.

I'll get the user to enter their username and password in a PreferenceActivity and use that to authenticate the URLConnection access when required and with a hidden form on webpage displayed in the WebView i can auto log the user in.

Thanks for the replies.

Martin.
 
Upvote 0

lagore

Active Member
Licensed User
Longtime User
Do you know if it is possible to use the reflection library to pass the cookie string to the webview because we can get the cookies/headers from 'hc_ResponseSuccess'.
 
Upvote 0

salmander

Active Member
Licensed User
Longtime User
Can this be done in b4a? I am after the same thing.

Android SDK webview class has a postURL() method. which sends a post data to the url. I can't seem to find it in b4a webview.

Can someone please post a solution?

Thanks
 
Last edited:
Upvote 0

warwound

Expert
Licensed User
Longtime User
Take a look at the reference for my new (but not yet released) version of WebViewExtras: WebViewExtras.
Search that page for PostUrl and you'll see the WebViewExtras object has this method:

PostUrl (Url As String, PostData() As Byte)
Loads the URL with postData using "POST" method into this WebView.

I haven't uploaded this new version yet as i am busy and have little time to provide any technical support.
But you are welcome to test it.
Here's an example showing the syntax:

B4X:
Sub Process_Globals

End Sub

Sub Globals
   Dim WebView1 As WebView
   Dim WebViewExtras1 As WebViewExtras

End Sub

Sub Activity_Create(FirstTime As Boolean)
   WebView1.Initialize("")
   Activity.AddView(WebView1, 0, 0, 100%x, 100%y)
   
   WebViewExtras1.Initialize(WebView1)
   '   WebViewExtras1 is now an 'extended' version of a WebView
   '   it has all properties and methods of a WebView plus many more
   '   you can use WebView1 or WebViewExtras1 to call WebView methods and set WebView properties
   '   but only WebViewExtras1 can call the new methods and set the new properties
   
   WebViewExtras1.PostUrl("my url goes here", Array As Byte(1, 2, 255))
   
End Sub

Sub Activity_Resume

End Sub

Sub Activity_Pause (UserClosed As Boolean)

End Sub

Example and library files attached.

Martin.
 
Last edited:
Upvote 0

salmander

Active Member
Licensed User
Longtime User
Thanks Martin I will try it out. One question I am trying to clear the cache of the webview with webviewextras but the cache is not being cleared. First time "UserAndPasswordRequired (Host As String, Realm As String) As String()" this event gets fired. but then i clear the cache and openurl again but this doesn’t gets fired.

any help please?
 
Upvote 0

warwound

Expert
Licensed User
Longtime User
ClearCache (IncludeDiskFiles As Boolean)
Clear the WebView cache. IncludeDiskFiles - If false, only the RAM cache is cleared. Note that the cache is per-application, so this will clear the cache for all WebViews used in an application.

You are passing True as the IncludeDiskFiles parameter - otherwise any files cached in memory will not be cleared.

If you use the WebViewExtras SetWebViewClient (WebViewClient1 As WebViewClient) method then the original b4a WebView will no longer have it's default WebViewClient.
A WebView can have only one WebViewClient and the WebViewClient is responsible for raising the UserAndPasswordRequired event.

To test whether this is happening - WebViewExtras is overwriting part of the default b4a WebView behavior try this:

B4X:
Sub Globals
   Dim WebView1 As WebView
   Dim WebViewExtras1 As WebViewExtras

End Sub

Sub Activity_Create(FirstTime As Boolean)
   WebView1.Initialize("")
   WebViewExtras1.Initialize(WebView1)
   
   '   WebViewExtras1 is now an 'extended' version of a WebView
   '   it has all properties and methods of a WebView plus many more
   '   you can use WebView1 or WebViewExtras1 to call WebView methods and set WebView properties
   '   but only WebViewExtras1 can call the new methods and set the new properties
   '   to keep things logical no longer use WebView1 instead use WebViewExtras1 where you previously referenced WebView1
   Activity.AddView(WebViewExtras1, 0, 0, 100%x, 100%y)
   
   Dim WebViewClient1 As WebViewClient
   WebViewClient1.Initialize("WebViewClient1")
   WebViewExtras1.SetWebViewClient(WebViewClient1)
   
   WebViewExtras1.PostUrl("my url goes here", Array As Byte(1, 2, 255))
   
End Sub

Sub Activity_Resume

End Sub

Sub Activity_Pause (UserClosed As Boolean)

End Sub

Sub WebViewClient1_UserAndPasswordRequired(Host As String, Realm As String) As String()
   Log("WebViewClient1_UserAndPasswordRequired")
   
   '   handle the event and return an Array of String
   
   Return Array As String("i added this", "array", "to stop the b4a", "ide reporting an error")
End Sub

Or is the problem that the WebView is storing the username and password returned by the UserAndPasswordRequired Sub and you are expecting ClearCache to remove that stored username and password?

Have a read of this: Android WebView - Cannot set basic auth again after first time - Stack Overflow.
It seems to be another one of the bugs that the android WebView has!
https://code.google.com/p/android/issues/detail?id=25507

Possible solutions are to delete the database that the WebView uses to stores these values - far from ideal and who knows what side effects this could have?, or try using the WebViewExtras SetHttpAuthUsernamePassword (Host As String, Realm As String, Username As String, Password As String) method to store empty strings or Null values as the username and password for this domain.

Martin.
 
Upvote 0

salmander

Active Member
Licensed User
Longtime User
Thanks for your solution mate. I tried your given code, also tried to add clearcache(true), clearformdata, clearhistory but still the _UserAndPasswordRequired event only gets triggered once. I also tried SetHttpAuthUsernamePassword method and passed null values as username and password, still no luck. I guess the last thing to try is deleting the webview database.
Can you help me with that please?

Many thanks

B4X:
Sub Globals
    Dim WebView1 As WebView
    Dim WebViewExtras1 As WebViewExtras

End Sub

Sub Activity_Create(FirstTime As Boolean)
    WebView1.Initialize("")
    WebViewExtras1.Initialize(WebView1)
    
    '    WebViewExtras1 is now an 'extended' version of a WebView
    '    it has all properties and methods of a WebView plus many more
    '    you can use WebView1 or WebViewExtras1 to call WebView methods and set WebView properties
    '    but only WebViewExtras1 can call the new methods and set the new properties
    '    to keep things logical no longer use WebView1 instead use WebViewExtras1 where you previously referenced WebView1
    Activity.AddView(WebViewExtras1, 0, 0, 100%x, 100%y)
    
    Dim WebViewClient1 As WebViewClient
    WebViewClient1.Initialize("WebViewClient1")
    WebViewExtras1.SetWebViewClient(WebViewClient1)
    
    'WebViewExtras1.PostUrl("my url goes here", Array As Byte(1, 2, 255))
   WebViewExtras1.ClearCache(True)
   WebViewExtras1.ClearFormData
   WebViewExtras1.ClearHistory
   'WebViewExtras1.ClearSslPreferences
   'WebViewExtras1.SetHttpAuthUsernamePassword("http://www.abc.com:80", "My Realm", "", "")
   WebViewExtras1.LoadUrl("http://www.abc.com/privilege/")
    'WebViewExtras1.GetHttpAuthUsernamePassword(Null, Null)
   WebViewExtras1.SetHttpAuthUsernamePassword("http://www.abc.com:80", "My Realm", "", "")
End Sub

Sub Activity_Resume

End Sub

Sub Activity_Pause (UserClosed As Boolean)

End Sub

Sub WebViewClient1_UserAndPasswordRequired(Host As String, Realm As String) As String()
    Log("WebViewClient1_UserAndPasswordRequired")
    Log("host: " & Host & ", Realm: " & Realm)
    'handle the event and return an Array of String
    
    Return Array As String("test", "test")
End Sub

Sub WebViewClient1_PageFinished(Url As String)
   Log("page finished loading")
   ToastMessageShow("page finished", False)
End Sub
 
Upvote 0

warwound

Expert
Licensed User
Longtime User
Before trying to delete the WebView database can you try this update to WebViewExtras: http://android.martinpearman.co.uk/b4a/temp/WebViewExtras_20130613.zip?
I have added support for the WebViewDatabase object:

WebViewDatabase
Methods:
  • ClearFormData
    Clears any saved data for web forms.
  • ClearHttpAuthUsernamePassword
    Clears any saved credentials for HTTP authentication.
  • ClearUsernamePassword
    Clears any saved username/password pairs for web forms.
  • HasFormData As Boolean
    Gets whether there is any saved data for web forms.
  • HasHttpAuthUsernamePassword As Boolean
    Gets whether there are any saved credentials for HTTP authentication.
  • HasUsernamePassword As Boolean
    Gets whether there are any saved username/password pairs for web forms.
  • Initialize
  • IsInitialized As Boolean

So create an instance of a WebViewDatabase object, initialize it.
First call it's HasHttpAuthUsernamePassword method - maybe log the result. I'd expect this to return True.
If it is True then call the ClearHttpAuthUsernamePassword method.
Lastly again call and log HasHttpAuthUsernamePassword - does it report a value of False?

If this doesn't help and you want to try physically deleting the WebView database then we'll have to find the location of that database file.
I suspect it's location varies depending on the version of Android installed on the device.
Presumably you will release your app to run on any device so would need to be able to delete the WebView database on any version of Android?
Which version of Android are you testing on?

Martin.
 
Upvote 0

salmander

Active Member
Licensed User
Longtime User
Thanks man. It says page cannot be found when clicking your link.

EDIT: Ok got it. Thanks. Trying now.
 
Last edited:
Upvote 0

salmander

Active Member
Licensed User
Longtime User
Ok the HasHttpAuthUsernamePassword returns true before calling the ClearHttpAuthUsernamePassword method and returns false after. Even after calling ClearHttpAuthUsernamePassword method, the _UserAndPasswordRequired event doesn't gets fired.

The WebViewDatabase is a Global object. and I am initializing it after "WebViewExtras1.SetWebViewClient(WebViewClient1)".

B4X:
WebViewExtras1.SetWebViewClient(WebViewClient1)
    wvdv.Initialize
   If wvdv.HasHttpAuthUsernamePassword Then
      Log("wvdv has the auth username password, clearing it now.")
      wvdv.ClearHttpAuthUsernamePassword
   End If
   Log("After clearing, has authUP:" & wvdv.HasHttpAuthUsernamePassword)

could it be a bug?

I am testing it on 4.2.2 Galaxy S4. But, yeah, the target audience can be using any android device.

your help is much appreciated. Keep me posted please.

thanks
 
Upvote 0

warwound

Expert
Licensed User
Longtime User
Take a look at the documentation for the Android Context class and it's deleteDatabase(String name) method:

Delete an existing private SQLiteDatabase associated with this Context's application package.

Returns True if the database was successfully deleted; else false.

So this looks to be the 'brute force/hack' to physically delete the WebView database(s) and hope that that will remove cached HttpAuth values.
Though if you look on this page you'll see the posted code comments say this method does not work.

Anyway to try it i'd suggest using the Reflection library.

You want to execute this java:

B4X:
myContext.deleteDatabase("webview.db");
myContext.deleteDatabase("webviewCache.db");

Here's an attempt to use Reflection to do the same:

B4X:
Dim Success As Boolean
Dim Reflector1 As Reflector
Reflector1.Target=Reflector1.GetContext
Success=Reflector1.RunMethod2("deleteDatabase", "webview.db", "java.lang.String")
Log("deleteDatabase webview.db "&Success)
Success=Reflector1.RunMethod2("deleteDatabase", "webviewCache.db", "java.lang.String")
Log("deleteDatabase webviewCache.db "&Success)

This is untested by the way.

Martin.
 
Upvote 0
Top