Android利用Cookie实现码源登录效果
上一篇講了界面的實現,詳情請戳Android利用Cookie實現碼源登錄效果(一) - 界面實現,本篇將對功能的實現進行分析。
具體實現
功能實現
使用HttpClient進行post請求
在進行post請求的時候,我們先看看網頁版登錄是如何發送數據的。打開登錄頁面,點擊鍵盤上的F12,在Sources中找到login,找到發送ajax請求進行登錄的部分,加入斷點:
點擊登錄,然后在Network中看到有個發送到http://www.codefrom.com/login/ajax 的網絡請求,點開它,我們看看Header里面有什么數據:
可以看到,有三部分數據:Request URL 、 Request Header 和 Form Data,他們的含義我想大家應該都很清楚。那么我們就嘗試在LoginActivity中模擬一下這個操作。
首先,我們寫一個方法,封裝我們的登錄請求:
public String sendPost(String url, String username, String password) {// 根據url獲得HttpPost對象HttpPost httpRequest = new HttpPost(url);// 取得默認的HttpClientDefaultHttpClient httpclient = new DefaultHttpClient();String strResult = null;// NameValuePair實現請求參數的封裝List<NameValuePair> params = new ArrayList<NameValuePair>();params.add(new BasicNameValuePair("_tk", "codefrom"));params.add(new BasicNameValuePair("name", username));params.add(new BasicNameValuePair("pass", password));httpRequest.addHeader("Accept", "application/json, text/javascript, */*; q=0.01");httpRequest.addHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");httpRequest.addHeader("Origin", "http://www.codefrom.com");httpRequest.addHeader("Referer", "http://www.codefrom.com/login");httpRequest.addHeader("X-Requested-With", "XMLHttpRequest");try {// 添加請求參數到請求對象httpRequest.setEntity(new UrlEncodedFormEntity(params, HTTP.UTF_8));// 獲得響應對象HttpResponse httpResponse = httpclient.execute(httpRequest);// 判斷是否請求成功if (httpResponse.getStatusLine().getStatusCode() == 200) {// 獲得響應返回Json格式數據strResult = EntityUtils.toString(httpResponse.getEntity());return strResult;} else {strResult = "錯誤響應:" + httpResponse.getStatusLine().toString();}} catch (ClientProtocolException e) {strResult = "錯誤響應:" + e.getMessage().toString();e.printStackTrace();return strResult;} catch (IOException e) {strResult = "錯誤響應:" + e.getMessage().toString();e.printStackTrace();return strResult;} catch (Exception e) {strResult = "錯誤響應:" + e.getMessage().toString();e.printStackTrace();return strResult;}return strResult; }(注:當前版本網絡請求只能異步操作)
String res = sendPost("http://www.codefrom.com/login/ajax", mEmail, mPassword); Log.d("CodeFromLogin", res);
然后,在UserLoginTask的doInBackground中,當睡眠結束后,我們對登錄方法進行調用:我們運行項目,看看日志中打印:
沒錯,將Unicode轉成中文之后,得到“操作成功”的返回信息!
需要注意一點,一開始,我沒有添加httpRequest.addHeader這部分的內容,得到的結果如下:
感興趣的同學可以嘗試一下,服務器返回提示我們操作失敗,缺少ajax頭部信息!保存來自服務器的Cookie
// 取得Cookie CookieStore mCookieStore = httpclient.getCookieStore(); List<Cookie> cookies = mCookieStore.getCookies();
能夠成功發送數據給服務器,并且服務器能響應結果,那么,我們能否獲取更多內容呢?當然可以!HttpClient提供了下面的方法供我們獲取Cookie:那么,Android又是如何對Cookie進行管理的呢?
// 設置cookie public static void synCookies(Context context, String url) { CookieSyncManager.createInstance(context); CookieManager cookieManager = CookieManager.getInstance(); cookieManager.setCookie(url, "uid=1243432"); CookieSyncManager.getInstance().sync(); }// 清除cookie private void removeCookie(Context context) {CookieSyncManager.createInstance(context); CookieManager cookieManager = CookieManager.getInstance(); cookieManager.removeAllCookie();CookieSyncManager.getInstance().sync(); }接下來,我們就可以對sendPost方法進行一些改造了:
public CookieManager cookieManager = null; public static String cookies; public String sendPost(String url, String username, String password) {CookieSyncManager.createInstance(LoginActivity.this);// 每次登錄操作的時候先清除cookieremoveAllCookie();// 根據url獲得HttpPost對象HttpPost httpRequest = new HttpPost(url);// 取得默認的HttpClientDefaultHttpClient httpclient = new DefaultHttpClient();String strResult = null;// NameValuePair實現請求參數的封裝List<NameValuePair> params = new ArrayList<NameValuePair>();params.add(new BasicNameValuePair("_tk", "codefrom"));params.add(new BasicNameValuePair("name", username));params.add(new BasicNameValuePair("pass", password));httpRequest.addHeader("Accept", "application/json, text/javascript, */*; q=0.01");httpRequest.addHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");httpRequest.addHeader("Origin", "http://www.codefrom.com");httpRequest.addHeader("Referer", "http://www.codefrom.com/login");httpRequest.addHeader("X-Requested-With", "XMLHttpRequest");try {// 添加請求參數到請求對象httpRequest.setEntity(new UrlEncodedFormEntity(params, HTTP.UTF_8));// 獲得響應對象HttpResponse httpResponse = httpclient.execute(httpRequest);// 判斷是否請求成功if (httpResponse.getStatusLine().getStatusCode() == 200) {// 獲得響應返回Json格式數據strResult = EntityUtils.toString(httpResponse.getEntity());// 取得CookieCookieStore mCookieStore = httpclient.getCookieStore();List<Cookie> cookies = mCookieStore.getCookies();if (cookies.isEmpty()) {System.out.println("Cookies為空");} else {for (int i = 0; i < cookies.size(); i++) {// 保存cookieCookie cookie = cookies.get(i);Log.d("Cookie", cookies.get(i).getName() + "=" + cookies.get(i).getValue());cookieManager = CookieManager.getInstance();String cookieString = cookie.getName() + "=" + cookie.getValue() + "; domain=" + cookie.getDomain();cookieManager.setCookie("http://www.codefrom.com/", cookieString);}}return strResult;} else {strResult = "錯誤響應:" + httpResponse.getStatusLine().toString();}} catch (ClientProtocolException e) {strResult = "錯誤響應:" + e.getMessage().toString();e.printStackTrace();return strResult;} catch (IOException e) {strResult = "錯誤響應:" + e.getMessage().toString();e.printStackTrace();return strResult;} catch (Exception e) {strResult = "錯誤響應:" + e.getMessage().toString();e.printStackTrace();return strResult;}return strResult; }private void removeAllCookie() {cookieManager = CookieManager.getInstance();cookieManager.removeAllCookie();CookieSyncManager.getInstance().sync(); }運行改造之后的代碼,我們先進行登錄,然后點擊按鈕打開碼源首頁,可以看到,首頁導航是可以看到登錄信息的!
使用本地廣播更新界面
localBroadcastManager = LocalBroadcastManager.getInstance(MainActivity.this); IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction("com.codefrom.broadcastreceiver.LOGIN_BROADCAST");//建議把它寫一個公共的變量,這里方便閱讀就不寫了。 loginBroadcastReceiver = new BroadcastReceiver() {public void onReceive(Context context, Intent intent) {Bundle bundle = intent.getExtras();boolean result = bundle.getBoolean("result");String user = bundle.getString("username");if (result) {username.setText(user);Toast.makeText(MainActivity.this, "登錄成功", Toast.LENGTH_SHORT).show();loginbtn.setText("退出登錄");isLogin = true;} else {Toast.makeText(MainActivity.this, "登錄失敗", Toast.LENGTH_SHORT).show();username.setText("未登錄");loginbtn.setText("登錄");isLogin = false;}} }; localBroadcastManager.registerReceiver(loginBroadcastReceiver, intentFilter);
完成登錄之后,我們需要修改主界面的控件文字,比如我們想顯示用戶名等等。理論上來講,使用startActivity將數據通過Intent從登錄界面傳遞給主界面的方法是可行的。但是,我們需要考慮在實際中,如果多個地方校驗到用戶沒有登錄,都需要彈出登錄界面,然后登錄完了之后,我們需要返回的界面不一定都是主界面(如果PM要求返回主界面,當我沒說),那我們該怎么辦呢?
這時,我們可以通過本地廣播來實現:在主界面(或者其他需要得到登錄信息的界面),動態注冊一個本地廣播,通過廣播獲取到的Intent來進行數據分析,部分代碼如下:同時,在登錄界面,登錄成功之后,我們可以發送一個廣播告知其他界面登錄結果,由于登錄在子線程中進行,我們就需要借助Handler進行廣播發送:
Handler handler = new Handler() { public void handleMessage(android.os.Message msg) {LoginInfo loginInfo = (LoginInfo) msg.obj;Toast.makeText(LoginActivity.this, loginInfo.getStatus() + " - " + loginInfo.getMsg() + " - " + Uri.decode(loginInfo.getMsg()) , Toast.LENGTH_SHORT).show();if("1".equals(loginInfo.getStatus())) {Intent intent = new Intent("com.codefrom.broadcastreceiver.LOGIN_BROADCAST");Bundle bundle = new Bundle();bundle.putBoolean("result", true);bundle.putString("username", "單車武士");intent.putExtras(bundle);localBroadcastManager.sendBroadcast(intent);} }; };其實,如果觀察LoginActivity,在成功以后,它做的操作是調用Activity的finish(),也就是直接關閉登錄界面了,我猜系統應該也是不推薦直接使用startActivity進行顯示跳轉的。
由于服務器并沒有給我們返回更多用戶的信息,我們先返回一個寫死的username過去……當然,在網頁中是根據cookie來獲取用戶信息的,這方面的東西在Android上面的實現我們今后再探討。
以上就是我們實現的模擬登錄碼源效果,如果有什么不對的地方或者更好的建議,歡迎回復交流。
附:Demo下載
- 2015年06月04日發布
- 新浪微博
- 微信
總結
以上是生活随笔為你收集整理的Android利用Cookie实现码源登录效果的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 没错,我们和美帝的差距就是这么大!
- 下一篇: 【Grades Crawler】利用p