需求
App登录了,访问网站时就不需要在网站再次登录账号了,是不是感觉很神奇呢?
哈哈,康师傅也是这么觉得的!
那么今天我们就来实现一下这个神奇的功能吧!
需求分析
既然我们App的持久化登录状态是通过保存 token ,访问 api 时携带 token 来实现的。
那么,我们是否也可以让网站在访问 api 接口的时候携带上 token 呢?
有的小伙伴可能想到了一个办法——拦截 WebView 的请求,然后给每个请求都添加上 token 。
确实,这是一个可行的办法,但是有点太麻烦了(我试过,不好弄)。
那么还有其它方法吗?当然有啦!
我们都知道,前端的登录状态保存一般是保存在 cookies 里的,所以我们打开阳光沙滩网站看看。打开网站 —> 按下 F12 —> Application —> Storage —> Cookies 。
看到 sob_token
这个字段了吗,这就是阳光沙滩的网站保存的 token 啦,其中比较关键的是 name
、value
、domain
、path
这几个字段。(这几个字段我们先复制下来,等下会用到)
网站的 token 既然是从 cookies 里获取的,那我们在 WebView 访问网站之前给它设置对应的 cookie 不就好了?
那么,我们要怎么才能给 WebView 设置 cookie 呢?
查官方文档嘛!
通过查询相关文档,我们发现了 CookieManager
这个类可以帮我们实现这个需求。
CookieManager
类的简介
public abstract class CookieManager extends Object
Manages the cookies used by an application's
WebView
instances.CookieManager represents cookies as strings in the same format as the HTTP
Cookie
andSet-Cookie
header fields (defined in RFC6265bis).
译:
管理应用程序的 WebView 实例使用的 cookie。
CookieManager 以与 HTTP Cookie 和 set-Cookie 头字段(在 RFC6265bis 中定义)相同的格式将 Cookie 表示为字符串。
从上面的描述就可以看出来,我们的 WebView 在访问网页的时候会使用 CookieManager 来获取 cookie ,那么我们只需要在加载网页之前把 Cookie 设置到 CookieManager 中即可。
我们再捋一下逻辑:网站请求 api —> 获取 Cookie —> WebView —> CookieManager。
编码实现
核心代码在下面,想要全部代码请查看我的 gitee 仓库(仓库地址:https://gitee.com/anjiemo/sob-login-demo)
/**
* author : A Lonely Cat
* github : https://github.com/anjiemo/SunnyBeach
* time : 2022/01/10
* desc : WebView 界面
*/
public class BrowserActivity extends AppCompatActivity {
private static final String URL = "url";
private WebView mWebView;
public static void start(Context context, String url) {
Intent intent = new Intent(context, BrowserActivity.class);
intent.putExtra(URL, url);
if (!(context instanceof Activity)) {
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
}
context.startActivity(intent);
}
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.browser_activity);
initView();
initData();
}
private void initData() {
Intent intent = getIntent();
String url = intent.getStringExtra(URL);
mWebView.loadUrl(url);
}
@SuppressLint("SetJavaScriptEnabled")
private void initView() {
mWebView = findViewById(R.id.web_view);
mWebView.setWebViewClient(new AppBrowserViewClient());
WebSettings settings = mWebView.getSettings();
// 设置启用 Javascript
settings.setJavaScriptEnabled(true);
// 设置 Dom 存储已启用
settings.setDomStorageEnabled(true);
}
private static class AppBrowserViewClient extends WebViewClient {
@Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
super.onPageStarted(view, url, favicon);
injectCookie(url);
}
/**
* 注入 Cookie
* @param url 需要注入 cookie 的 url
*/
private void injectCookie(String url) {
// 获取 CookieManager 的单例实例
CookieManager manager = CookieManager.getInstance();
String apiTopDomain = StringUtil.getTopDomain(Constants.SUNNY_BEACH_API_BASE_URL);
String siteTopDomain = StringUtil.getTopDomain(Constants.SUNNY_BEACH_SITE_BASE_URL);
String apiCookie = getCookie(apiTopDomain);
String siteCookie = getCookie(siteTopDomain);
manager.setCookie(url, apiCookie);
manager.setCookie(url, siteCookie);
}
/**
* 根据 domain 获取 sob_token
* @param domain 顶级域名
* @return cookie
*/
public String getCookie(String domain) {
SobCacheManager manager = SobCacheManager.newInstance();
return new Cookie.Builder()
.name(SobCacheManager.SOB_TOKEN_NAME)
.value(manager.getSobToken())
.domain(domain)
.path("/")
.build()
.toString();
}
}
}