0
点赞
收藏
分享

微信扫一扫

okhttp webview cookie同步

小安子啊 2022-03-26 阅读 99

        上周六开始,app主页上通过webview访问服务器H5页面的功能点开都跳转登录页,前同事做了webview cookie同步失效,这个问题把我折腾了三天,终于搞定!写个博客记录一下。

        正文开始前,咱们先简单回顾一下cookie和session。用户输入用户名和密码,服务器验证用户信息成功后创建一个session,将session id放在cookie返回给客户端。

服务端代码:

HttpSession session = request.getSession();
String sid = session.getId();
response.addHeader("Set-Cookie","JSESSIONID="+sid+";Domain=.;Path=/");

客户端代码:

private void initButtonLogin() {
        mButtonLogin = (Button) findViewById(R.id.tv_login);
        mButtonLogin.setOnClickListener(v -> {
            //防止短时间多次点击
            if(BtnUtil.isValidClick()){
                login();
                login();//为什么要向服务器发送两遍登录请求?因为一定要发第二遍(cookie的两次握手),webview cookie才会同步成功,webview才能追踪到此session。有知道的童鞋可以告知一下,互相学习~
            }
        });
    }

private void login(){
        String userId = mEditUserId.getText().toString().trim();
        String passWord = mEditPassWord.getText().toString().trim();
        InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
        imm.hideSoftInputFromWindow(mEditUserId.getWindowToken(), 0); //强制隐藏键盘
        imm.hideSoftInputFromWindow(mEditPassWord.getWindowToken(), 0); //强制隐藏键盘
        OkHttpClient client= new OkHttpClient().newBuilder()
                .connectTimeout(3000, TimeUnit.MILLISECONDS)
                .cookieJar(new MyCookieJar())
                .build();
        //get请求
        String path= ApiConstant.PROJECT_URL+"api/login?userid="+userId+"&password="+passWord;
        Request request=new Request.Builder().url(path).get().build();
        try {
            Response response = client.newCall(request).execute();
            String  result = response.body().string();
            JSONObject jsonObject = JSON.parseObject(result);
            JSONArray arr = jsonObject.getJSONArray("data");

            //此处代码无关主题,隐藏

        } catch (Exception e) {
            e.printStackTrace();
            ToastUtils.showShort("登录失败,请与管理员联系!");
        }
    }
MyCookieJar.java
import android.content.Context;
import android.content.SharedPreferences;
import android.text.TextUtils;

import androidx.annotation.NonNull;

import java.util.ArrayList;
import java.util.List;

import okhttp3.Cookie;
import okhttp3.CookieJar;
import okhttp3.HttpUrl;

/**
 * cookie管理
 */
public class MyCookieJar implements CookieJar {
    @Override
    public void saveFromResponse(@NonNull HttpUrl url, @NonNull List<Cookie> cookies) {
        try {
            String cookieStr = encodeCookie(cookies);
            saveCookie(url.host(), cookieStr);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public List<Cookie> loadForRequest(@NonNull HttpUrl url) {
        List<Cookie> cookies = new ArrayList<>();
        String cookieStr = loadCookie(url.host());
        if (!TextUtils.isEmpty(cookieStr)) {
            //获取所有 Cookie 字符串
            String[] cookieStrs = cookieStr.split("#");
            for (String aCookieStr : cookieStrs) {
                //将字符串解析成 Cookie 对象
                Cookie cookie = Cookie.parse(url, aCookieStr);
                cookies.add(cookie);
            }

        }
        //此方法返回 null 会引发异常
        return cookies;
    }

    private String encodeCookie(List<Cookie> cookies) {
        StringBuilder sb = new StringBuilder();
        for (Cookie cookie : cookies) {
            //将Cookie转换成字符串
            sb.append(cookie.toString());
            //以#为分隔符
            sb.append("#");
        }
        if(sb.length() > 0){
            sb.deleteCharAt(sb.lastIndexOf("#"));
        }
        return sb.toString();
    }

    public static String loadCookie(String host) {
        SharedPreferences sp = BaseApplication.getAppContext()
                .getSharedPreferences("cookie_oref", Context.MODE_PRIVATE);
        if (!TextUtils.isEmpty(host) && sp.contains(host)) {
            return sp.getString(host, "");
        }
        return null;
    }

    private void saveCookie(String host, String cookie) {
        SharedPreferences.Editor editor = BaseApplication.getAppContext()
                .getSharedPreferences("cookie_oref", Context.MODE_PRIVATE)
                .edit();
        if (!TextUtils.isEmpty(host)) {
            editor.putString(host, cookie);
        }
        editor.apply();
    }
}

webview cookie同步:

private void syncCookie(String url) {
        HttpUrl okurl = HttpUrl.parse(ApiConstant.PROJECT_URL + url);
        String cookies = MyCookieJar.loadCookie(okurl.host());
        if(!TextUtils.isEmpty(cookies)){
            try {
                createInstance(this);
                CookieManager cookieManager = CookieManager.getInstance();
                cookieManager.setAcceptCookie(true);
                String[] cookieArray = cookies.split("#");
                for (int i = 0; i < cookieArray.length; i++) {
                    cookieManager.setCookie(ApiConstant.PROJECT_URL+url, cookieArray[i]);//为url设置cookie
                }
                if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP){
                    cookieManager.flush();
                }else{
                    CookieSyncManager.getInstance().sync();
                }

            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

总结这次解决问题的时间都浪费在没有把cookie和session关联起来,其实把session id放在cookie传到客户端即可。到目前还有一点不明白的就是,为什么一定要发第二遍登录请求,webview cookie才会同步过去,有知道的童鞋请不吝赐教!hiahiahia~

举报

相关推荐

0 条评论