Maintain cookie session in Android
Okay, I have an android application that has a form in it, two EditText, a spinner, and a login button. The user selects the service from the spinner, types in their user name and password, and clicks login. The data is sent via POST, a response is returned, it's handled, a new WebView is launched, the html string generated from the response is loaded, and I have the home page of whatever service the user selected.
That's all well and good. Now, when the user clicks on a link, the login info can't be found, and the page asks the user to login again. My login session is being dropped somewhere, and I'm not certain how to pass the info from the class that controls the main part of my app to the class that just launches the webview activity.
The onClick handler from the form login button:
private class FormOnClickListener implements View.OnClickListener {
public void onClick(View v) {
String actionURL, user, pwd, user_field, pwd_field;
actionURL = "thePageURL";
user_field = "username"; //this changes based on selections in a spinner
pwd_field = "password"; //this changes based on selections in a spinner
user = "theUserLogin";
pwd = "theUserPassword";
List<NameValuePair> myList = new ArrayList<NameValuePair>();
myList.add(new BasicNameValuePair(user_field, user));
myList.add(new BasicNameValuePair(pwd_field, pwd));
HttpParams params = new BasicHttpParams();
DefaultHttpClient client = new DefaultHttpClient(params);
HttpPost post = new HttpPost(actionURL);
开发者_如何学C HttpResponse response = null;
BasicResponseHandler myHandler = new BasicResponseHandler();
String endResult = null;
try { post.setEntity(new UrlEncodedFormEntity(myList)); }
catch (UnsupportedEncodingException e) { e.printStackTrace(); }
try { response = client.execute(post); }
catch (ClientProtocolException e) { e.printStackTrace(); }
catch (IOException e) { e.printStackTrace(); }
try { endResult = myHandler.handleResponse(response); }
catch (HttpResponseException e) { e.printStackTrace(); }
catch (IOException e) { e.printStackTrace(); }
List<Cookie> cookies = client.getCookieStore().getCookies();
if (!cookies.isEmpty()) {
for (int i = 0; i < cookies.size(); i++) {
cookie = cookies.get(i);
}
}
Intent myWebViewIntent = new Intent(MsidePortal.this, MyWebView.class);
myWebViewIntent.putExtra("htmlString", endResult);
myWebViewIntent.putExtra("actionURL", actionURL);
startActivity(myWebViewIntent);
}
}
And here is the WebView class that handles the response display:
public class MyWebView extends android.app.Activity {
private class MyWebViewClient extends WebViewClient {
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
view.loadUrl(url);
return true;
}
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.web);
MyWebViewClient myClient = new MyWebViewClient();
WebView webview = (WebView)findViewById(R.id.mainwebview);
webview.getSettings().setBuiltInZoomControls(true);
webview.getSettings().setJavaScriptEnabled(true);
webview.setWebViewClient(myClient);
Bundle extras = getIntent().getExtras();
if(extras != null)
{
// Get endResult
String htmlString = extras.getString("htmlString");
String actionURL = extras.getString("actionURL");
Cookie sessionCookie = MsidePortal.cookie;
CookieSyncManager.createInstance(this);
CookieManager cookieManager = CookieManager.getInstance();
if (sessionCookie != null) {
cookieManager.removeSessionCookie();
String cookieString = sessionCookie.getName()
+ "=" + sessionCookie.getValue()
+ "; domain=" + sessionCookie.getDomain();
cookieManager.setCookie(actionURL, cookieString);
CookieSyncManager.getInstance().sync();
}
webview.loadDataWithBaseURL(actionURL, htmlString, "text/html", "utf-8", actionURL);}
}
}
}
I've had mixed success implementing that cookie solution. It seems to work for one service I log into that I know keeps the cookies on the server (old, archaic, but it works and they don't want to change it.) The service I'm attempting now requires the user to keep cookies on their local machine, and it does not work with this setup.
Any suggestions?
You need to keep the cookie from one call to another. Instead of creating a new DefaultHttpClient, use this builder:
private Object mLock = new Object();
private CookieStore mCookie = null;
/**
* Builds a new HttpClient with the same CookieStore than the previous one.
* This allows to follow the http session, without keeping in memory the
* full DefaultHttpClient.
* @author Régis Décamps <decamps@users.sf.net>
*/
private HttpClient getHttpClient() {
final DefaultHttpClient httpClient = new DefaultHttpClient();
synchronized (mLock) {
if (mCookie == null) {
mCookie = httpClient.getCookieStore();
} else {
httpClient.setCookieStore(mCookie);
}
}
return httpClient;
}
And keep the Builder class as a field of your application.
Use this in url login Activity
List<Cookie> cookies = client.getCookieStore().getCookies();
if (!cookies.isEmpty()) {
for (int i = 0; i < cookies.size(); i++) {
cookie = cookies.get(i);
}
}
Cookie sessionCookie = cookie;
if (sessionCookie != null) {
String cookieString = sessionCookie.getName() + "="
+ sessionCookie.getValue() + "; domain="
+ sessionCookie.getDomain();
cookieManager
.setCookie("www.mydomain.com", cookieString);
CookieSyncManager.getInstance().sync();
}
You could store the cookies in a shared preference and load them as needed in other activitys.
Or try this idea from a similar question.
dunno if you still need an answer, but again here comes some additional info that may help
if you want to keep cookies sync'ed
// ensure any cookies set by the dialog are saved
CookieSyncManager.getInstance().sync();
and if you want to clear Cookies
public static void clearCookies(Context context) {
// Edge case: an illegal state exception is thrown if an instance of
// CookieSyncManager has not be created. CookieSyncManager is normally
// created by a WebKit view, but this might happen if you start the
// app, restore saved state, and click logout before running a UI
// dialog in a WebView -- in which case the app crashes
@SuppressWarnings("unused")
CookieSyncManager cookieSyncMngr =
CookieSyncManager.createInstance(context);
CookieManager cookieManager = CookieManager.getInstance();
cookieManager.removeAllCookie();
}
When any new activity is launched (so I assume this is the same when you launch a new webview) it is effectively launching a new program from scratch. This new activity will not have access to data from any previous activity (unless that data is passed by being attached to the intent).
2 possible solutions:
1) putExtra can only be used to pass primitive data, so to pass something more complex you need to either
a) Wrap the more complex structure in a class that implements the
Parcelable interface, which can be stored in an extra.b) Wrap the more complex structure in a class that implements the
Serializable interface, which can be stored in an extra.
Either of these approaches is fairly complicated and a fair bit of work.
2)Personally I much prefer the approach suggested by rds. To clarify, when rds says:
keep the Builder class as a field of your application.
I think he means extend the application class. Any properties stored there are available globally to all activities. This article explains very clearly how to do this: http://www.screaming-penguin.com/node/7746 You can ignore the stuff about the AsyncTask (although I'm sure you will find a need for that at some point) and just concentrate on the part about extending the application class.
I have this similiar problem several week ago, that is because you create new DefaultHttpClient each time you click the button.. try create one DefaultHttpClient, and using the same DefaultHttpClient for each request you trying to send. it solved my problem
You have used this line -
if (sessionCookie != null) {
cookieManager.removeSessionCookie();
}
To ensure you receive new cookie everytime.
Seems like you have gone through same issue as I faced, check below link -
removeSessionCookie() issue of android (code.google.,com)
it says that removeSessionCookie()
is implemented in a thread, so whenever it is called; a thread starts and after your setCookie(url, cookieString);
is called, it removes the new cookie you just set.
So for some devices it works well as removeSessionCookie()
is already executed, while, for some, it remove the cookie, and we get that problem.
I suggest you remove this removeSessionCookie();
as you are setting only one cookie, so it won't conflict with other cookies. Your code will work seamlessly.
Sever use the sessionID stored in the cookies to identify the specfic user.Every language has a different sessionID name in the http headers.You can use some network tool or browser to see what is the name the sessionID called.
And other way,I GUESS,the facebook and twitter way,you will remove all the session-related code, it's server use Access Token to identify a user.
Am i clear?
精彩评论