Android 控件WebView設置Cookie

WebViewCookie

引言:網頁需要設置登錄狀態等情形。開發使用過程中自我經驗簡單記錄。

時間:2017年03月13日20:53:12

作者:JustDo23

01. 設置方式

同步的問題很常見,網上搜到的解決方法基本類似。

  /**
   * 給WebView同步Cookie
   *
   * @param context 上下文
   * @param url     可以使用[domain][host]
   */
  private void syncCookie(Context context, String url) {
    CookieSyncManager.createInstance(context);
    CookieManager cookieManager = CookieManager.getInstance();
    cookieManager.setAcceptCookie(true);
    cookieManager.removeSessionCookie();// 移除舊的[可以省略]
    List<HttpCookie> cookies = new PersistentCookieStore(context).getCookies();// 獲取Cookie[可以是其他的方式獲取]
    for (int i = 0; i < cookies.size(); i++) {
      HttpCookie cookie = cookies.get(i);
      String value = cookie.getName() + "=" + cookie.getValue();
      cookieManager.setCookie(url, value);
    }
    CookieSyncManager.getInstance().sync();// To get instant sync instead of waiting for the timer to trigger, the host can call this.
  }

這里簡單說明:

  • 參數中的 URL 在使用過程中基本是域名。例如 https://www.baidu.com/ 就可以使 www.baidu.com
  • Cookie 列表的獲取根據自己項目的存儲方式不同而不同。例如使用 SharedPreferencesHashMap
  • 注意使用 for 循環 進行 setCookie(String url, String value) 調用。網上有博客表示使用分號手動拼接的 value 值會導致 Cookie 不能完整設置或者無效
  • 注意 value 的值是使用 key=value 的完整形式。文檔提示 the cookie as a string, using the format of the 'Set-Cookie' HTTP response header
  • CookieSyncManager 是個過時的類,Api21 中 WebView 可以自動同步。
  • CookieSyncManager.getInstance().sync(); 方法的替代方法是 cookieManager.flush();
  • Cookie 同步方法要在 WebView 的 setting 設置完之后調用,否則無效。
  • 調用 loadUrl(url); 前一句調用此方法進行 Cookie 同步操作。
/**
 * 獲取URL的域名
 */
private String getDomain(String url){
  url = url.replace("http://", "").replace("https://", "");
  if (url.contains("/")) {
    url = url.substring(0, url.indexOf('/'));
  }
  return url;
}

02. 保存Cookie

在這里記錄一下使用 SharedPreferences 保存整個 Cookie 串并使用 HashMap 存儲鍵值對

/**
 * 獲取本地存儲的 Cookie 集合
 *
 * @return Cookie 鍵值對
 */
public Map<String, String> getCookieMap() {
    Map<String, String> cookieMap = new HashMap<>();
    String cookie = getCookie();// 從SharedPreferences中獲取整個Cookie串
    if (!TextUtils.isEmpty(cookie)) {
        String[] cookieArray = cookie.split(";");// 多個Cookie是使用分號分隔的
        for (int i = 0; i < cookieArray.length; i++) {
            int position = cookieArray[i].indexOf("=");// 在Cookie中鍵值使用等號分隔
            String cookieName = cookieArray[i].substring(0, position);// 獲取鍵
            String cookieValue = cookieArray[i].substring(position + 1);// 獲取值
            cookieMap.put(cookieName, NetCodeUtil.encodeURL(cookieValue));// 存至Map
            // 解碼使用 URLEncoder.encode(str, "UTF-8");
        }
    }
    return cookieMap;
}

注意:編解碼,從請求頭中獲取到的 Cookie 是經過 URL 編碼 的,解碼后可以獲取到姓名之類中文,在給 WebView 或者是其他請求設置 Cookie 的時候需要進行編碼

CookieUtil cookieUtil = new CookieUtil(this);// 將 Cookie 保存在了 SharedPreferences
Map<String, String> cookieMap = cookieUtil.getCookieMap();// 獲取鍵值對
for (Map.Entry<String, String> entry : cookieMap.entrySet()) {// 遍歷 Map
    String value = entry.getKey() + "=" + entry.getValue();// 鍵值對拼接成 value
    cookieManager.setCookie(url, value);// 設置 Cookie
}

03. 域名不同

使用 WebView 加載 A接口 獲取到展示的界面,界面需要填充的數據會自動請求 B接口。這兩接口域名不相同,之前服務器升級的時候搞了一個新的域名。抓包發現 AB兩個接口 域名不同 A為舊 B為新

  • 嘗試對兩個域名設置 Cookie 測試發現不沒有效果
  • 嘗試將兩個接口的域名設置為相同的測試發現兩個接口都攜帶了 Cookie

進行了一番搜索之后,發現有在強調,只有cookie的domain和path與請求的URL匹配才會發送這個cookie

/**
 * Sets a cookie for the given URL. Any existing cookie with the same host,
 * path and name will be replaced with the new cookie. The cookie being set
 * will be ignored if it is expired.
 *
 * @param url the URL for which the cookie is to be set
 * @param value the cookie as a string, using the format of the 'Set-Cookie'
 *              HTTP response header
 */
public abstract void setCookie(String url, String value);

注釋中寫到,具有相同的 hostpathname 的任何現有的 Cookie 將會被替換為新的 Cookie。

04. Cookie保存位置

項目中使用 WebView 其實會自動將 Cookie 保存在本地數據庫中。保存是路徑為 data/data/package_name/app_WebView/Cookies 雖然不是 .db 結尾的,實際就是一個 .db 文件

參考文檔

  1. 安卓學習筆記---AndroidWebview里設置Cookie遇到的坑

升級

引言:實際使用中遇到問題并進行更新。

時間:2018年04月19日21:03:12

作者:JustDo23

01. 針對一級域名

  • 不用對每個具體的 Url 進行設置 Cookie
  • 針對項目使用的一級域名進行設置 Cookie
  • 選擇合適的時機進行刷新
public void synCookies(Context context) {
  if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
    CookieSyncManager.createInstance(context);
  }
  CookieManager cookieManager = CookieManager.getInstance();
  cookieManager.setAcceptCookie(true);// 允許接受 Cookie
  if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
    cookieManager.removeSessionCookie();// 移除
  } else {
    cookieManager.removeSessionCookies(null);// 移除
  }
  List<HttpCookie> cookies = UserModle.getInstance(this).getCookies();
  for (int i = 0; i < cookies.size(); i++) {
    HttpCookie cookie = cookies.get(i);
    String value = cookie.getName() + "=" + cookie.getValue();
    cookieManager.setCookie(".baidu.com", value);
  }
  cookieManager.setCookie(".baidu.com", "Domain=.baidu.com");
  cookieManager.setCookie(".baidu.com", "Path=/");
  if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
    CookieSyncManager.getInstance().sync();
  } else {
    cookieManager.flush();
  }
}

02. UserAgent

  • 每次設置 UserAgent 會導致 WebView 重新加載
  • 根據需要進行設置
  • 注意各個添加分號
String original = webView.getSettings().getUserAgentString();// 獲取 WebView 的 UserAgent
original += " Version:" + versionName + ";";// 替換
webView.getSettings().setUserAgentString(original);// 設置新的 UserAgent

03. 參考

  1. 選擇性參考
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • Spring Cloud為開發人員提供了快速構建分布式系統中一些常見模式的工具(例如配置管理,服務發現,斷路器,智...
    卡卡羅2017閱讀 134,919評論 18 139
  • 從三月份找實習到現在,面了一些公司,掛了不少,但最終還是拿到小米、百度、阿里、京東、新浪、CVTE、樂視家的研發崗...
    時芥藍閱讀 42,366評論 11 349
  • 將cookie同步到WebView(推薦)參考:文/CrazyCodeBoy(簡書作者) android WebV...
    蒸汽飛船閱讀 23,786評論 7 28
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 173,251評論 25 708
  • 大家好,今天又是云舅不定期冒泡時間。 幾天不見,你們是不是又在想我? 老實說,最近舅有些苦惱。 放眼望去,爛片太多...
    Sir電影閱讀 1,210評論 0 21