安卓中原生与H5(webview)之间交互时cookie的同步

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/you__are_my_sunshine/article/details/55505665

一、问题描述

最近的项目中使用了H5页面和原生之间的交互,主要是原生通过js调用webview来加载H5页面,但是在进行通信时,涉及到一个cookie同步的问题,如果没处理好,真的是问题多多,纠结了好久,遇到了不少坑,今天在这里记录下:

首先是在网上找到很多地方都有的通用的webview同步cookie的方法如下:

 SharedPreferences spf = getSharedPreferences("Cookie", Context.MODE_PRIVATE);
 String cookieString = spf.getString("cookieString", "");

 CookieSyncManager.createInstance(this);
 CookieManager cookieManager = CookieManager.getInstance();
 cookieManager.setCookie(url, cookieString);
 CookieSyncManager.getInstance().sync();

 webview.loadUrl(url); 

后来发现还是会有问题,回来通过打印日志和后台跟踪配合发现,当H5页面中的页面请求有ajax请求时,发送到后台的cookie一直是OK的,当请求道后台的最后一步时,cookie会丢失,至今未找到具体原因,有知道的可以告诉我下,后来在网上找到如下的解决方案:

private void syncCookie(String url) {  
   try {  
       CookieSyncManager.createInstance(mWvSignUp.getContext());//创建一个cookie管理器  
       CookieManager cookieManager = CookieManager.getInstance();  
       cookieManager.setAcceptCookie(true);  
       cookieManager.removeSessionCookie();// 移除以前的cookie  
       cookieManager.removeAllCookie();  
       StringBuilder sbCookie = new StringBuilder();//创建一个拼接cookie的容器,为什么这么拼接,大家查阅一下http头Cookie的结构  
       sbCookie.append(_mApplication.getUserInfo().getSessionID());//拼接sessionId  
       sbCookie.append(String.format(";domain=%s", ""));  
       sbCookie.append(String.format(";path=%s", ""));  
       String cookieValue = sbCookie.toString();  
       cookieManager.setCookie(url, cookieValue);//为url设置cookie  
       CookieSyncManager.getInstance().sync();//同步cookie  
   } catch (Exception e) {  
       e.printStackTrace();  
   }  
} 

在执行webview的loadurl之前,先执行cookie同步,即上述操作。

二、一些ajax请求需要带入cookie怎么办?

在项目中因为有时候一些点击事件是用ajax请求实现的,同时也需要判断是否登陆。浏览器会自动保存cookie,并传送给服务器,但是android不会,这个时候我们需要拦截这个请求并将cookie附带上去

5.0以下:

mWebView.setWebViewClient(new WebViewClient() {  
   /** 
    * 5.0以下 
    * @param view 
    * @param url 
    * @return 
    */  
   @Override  
   public WebResourceResponse shouldInterceptRequest(WebView view, String url) {  
       syncCookie(url);  
       return super.shouldInterceptRequest(view, url);//将加好cookie的url传给父类继续执行  
   }  
}); 

5.0以上:

mWebView.setWebViewClient(new WebViewClient() {  
 @SuppressLint("NewApi")  
 @Override  
 public WebResourceResponse shouldInterceptRequest(WebViewview, WebResourceRequest request) {  
   String url = request.getUrl().toString();  
   syncCookie(url);   
   return super.shouldInterceptRequest(view, url);//因为跟5.0以下的方法返回值是同一个类,所以这里偷懒直接调动4.0方法生成请求  
 }); 

试了以上的方法,确实能解决部分问题,可是还是有问题的

也有人说这个问题:

设置cookie之后,是不能设置以下属性的,否则cookie是无效的(不只是这些属性,这里只是举例,最好的方式是在执行loadurl之前再设置cookie)

webview.getSettings().setCacheMode(WebSettings.LOAD_NO_CACHE);  
webview.getSettings().setJavaScriptEnabled(true);  
webview.getSettings().setDatabaseEnabled(true);  
webview.getSettings().setDomStorageEnabled(true);  

可是实际上本来就如此,依旧同步的cookie有问题,到底问题在哪里?

三、解决问题

那自己写的同步方法为何就是不能用呢?打印cookie一路跟踪都是好的,就是后面不行了,后来有人说webview的cookieManager.setCookie(url, cookieValue);方法中,cookie要严格按照"Set-Cookie"的格式设置,结果还是不行,又看到有人说cookieValue的值在读取时时读取到分号时即认为读取结束,分号后面的cookie的值将不会读取,实际测试确实是这样,后台经过一份折腾,通过改造下面的方法终于解决了问题:

 public static void synchronousWebCookies(Context context,String url,String cookies){
	if ( !TextUtils.isEmpty(url) )
		if (!TextUtils.isEmpty(cookies) ) {
			if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP){
				CookieSyncManager.createInstance( context);
			}
			CookieManager cookieManager = CookieManager.getInstance();
			cookieManager.setAcceptCookie( true );
			cookieManager.removeSessionCookie();// 移除
			cookieManager.removeAllCookie();
			StringBuilder sbCookie = new StringBuilder();//创建一个拼接cookie的容器,为什么这么拼接,大家查阅一下http头Cookie的结构  
			sbCookie.append(cookies);//拼接sessionId  
//			sbCookie.append(String.format(";domain=%s", ""));  
//			sbCookie.append(String.format(";path=%s", ""));  
			String cookieValue = sbCookie.toString();  
			cookieManager.setCookie(url, cookieValue);//为url设置cookie  
			CookieSyncManager.getInstance().sync();//同步cookie
                        String newCookie = cookieManager.getCookie(url);
			LogManager.i("同步后cookie", newCookie);
		}
    }

该段代码在webView.loadUrl();方法调用之前执行即可。

这里提一下需要注意的几点问题:

1.cookie同步的时候一定要loadurl()方法之前执行

2.cookie同步好之后不能设置以上提到的属性,如果有需要一定要在同步之前设置

3.setCookie()方法的cookie值读取到分号就结束了,不注意会导致部分cookie信息丢失

4.setCookie()方法,cookie的值如果是字符串的形式,不能直接截取拼接,那样会有问题(表面上看没问题),尤其是当cookie中包含多个信息时,一定要通过StringBuilder的方式拼接

5.cookie同步不能再onPageStarted()方法中执行,会有问题(之前偷懒统一在那里同步一次,结果被坑了)

 

------更新--------

在最近的项目中又发现一个新的问题,当后台有多台服务器的时候,cookie同步还是有问题的,尤其是当cookie信息不止一条的时候,按照上面的方法同步cookie发现cookie有丢失现象,经过反复折腾跟踪发现,有一个细节一定要重视,就是服务器返回的path和domain,这两个不容忽视,而安卓的webview在同步cookie的时候以分号结束为一个cookie,即使拼接cookie同步过去,没有path和domain服务器不认识,也是有问题的。多个cookie信息一定要分开对应自己的path和domain,每次setcookie()都要拼接一条完整cookie信息,可以先对获取到的cookie进行以分号结尾为标志进行截取,然后采用for循环的方式分别设置给webview再进行同步即可。

 

 

没有更多推荐了,返回首页