Android-X5WebView(Cookie管理、进度监听、适配8.1系统等策略)

简介: 本文已独家授权 郭霖 ( guolin_blog ) 公众号发布!撸完了上一篇Android-X5WebView简介 之后,有些大兄弟可能觉得不过瘾呐,说你那样的都是很基础的啊(的确很基础),项目里面用起来不爽啊(的确很不爽),不能让我直接CV啊(的确不能直接复制粘贴)等等,那这篇文章的目标就是怎么样快速封装X5WebView,如何有效的同步以及管理Cookie,如何使用IntentService优化预加载,如何监听进度条以及8.1系统的踩坑适配,等一些在项目中的常用功能。

本文已独家授权 郭霖 ( guolin_blog ) 公众号发布!

撸完了上一篇Android-X5WebView简介 之后,有些大兄弟可能觉得不过瘾呐,说你那样的都是很基础的啊(的确很基础),项目里面用起来不爽啊(的确很不爽),不能让我直接CV啊(的确不能直接复制粘贴)等等,那这篇文章的目标就是怎么样快速封装X5WebView,如何有效的同步以及管理Cookie,如何使用IntentService优化预加载,如何监听进度条以及8.1系统的踩坑适配,等一些在项目中的常用功能。

本文最近更新内容:

X5Webview适配Android 8.1系统

Https与Http混合加载

功能需求:

需求一:客户端账号密码登录成功以后,调用H5(也就是使用X5webView,以下简称X5)。H5界面也需要去记录你的状态。比如你客户端本地登录成功以后,H5界面也需要显示登录成功的状态。那么,客户端和H5如何去同步状态?

需求二:因为X5加载的时候,会有一段时间会显示空白或者卡顿,如何去监听并利用这个进度并优化?

需求三:如何简单封装X5WebView基本功能,方便日后快速使用?

需求分析:

需求一:

(针对需求一,真的是参考了很多哥们的技术博客,然后由于笔者上周也就是3月9号接到的开发需求,其中遇到了很多坑,所以我希望这篇博客可以把这个需求写的详细,尽可能的造福以后遇到同样需求的朋友让他们节约时间少走弯路)

对于Cookie,我们并不陌生,如果不是很了解的建议首先参考Cookie、Session、Token那点事儿  先大致掌握一下。这里多提一嘴,Cookie 简单理解,它主要是用来进程保活的,其具有时效性(持久化和非持久化),它是通过服务器的请求,在响应头里面拿到,然后在第二次http请求上以请求头的方式将参数带过去,优点是减少后台查库压力等等,更加具体的细节和说明可以参考上面的链接文章,那么,在Android中,也就是WebView中,我们如何去管理Cookie?

首先:CookieSyncManager与CookieManager

Android中关于Cookie的说明:

早期的cookie是由CookieSyncManager进行管理的,之后CookieSyncManager被抛弃了,换成了CookieManager来进行管理。两个版本的分割线就是Android SDK -- 21。

Android中Cookie的存储位置:

目前Android系统WebView是将cookie存储data/data/package_name/app_webview这个目录下的一个叫Cookies的数据中。

CookieSyncManager在内存和存储器之间同步浏览器的cookie。另外,CookieSyncManager的同步策略是在一个独立的线程里定时进行同步。

注意:每次同步的时间间隔是5分钟。

CookieSyncManager类下的常用API介绍

cookie同步策略:

CookieSyncManager.createInstance(context); 

CookieSyncManager.getInstance().startSync();

cookie停止同步:

CookieSyncManager.getInstance().stopSync()

cookie立即同步:调用了该方法会立即进行cookie的同步,代码如下:

CookieSyncManager.getInstance().sync()

删除cookie操作:

CookieSyncManager.createInstance(this);

CookieManager.getInstance().removeAllCookie();

CookieManager.getInstance().removeSessionCookie();

CookieSyncManager.getInstance().sync();

CookieSyncManager.getInstance().startSync();

CookieManager管理cookie:从sdk21之后,webview已经内置了cookie的同步操作了。虽然不再需要关注cookie的同步,但是依然需要掌握删除cookie的操作。

删除cookie操作:底层实现是异步清除数据库的记录

CookieManager.getInstance().removeAllCookies(null);

CookieManager.getInstance().flush();

立即同步:注意到这个flush()方法就是立即同步cookie的操作,本质上与CookieSyncManager中的sync()方法是一样的。于是乎,关于同步cookie我们可以有如下简单的写法:

img_ab5fae840f72ab131ee5a087e8565866.png
cookie同步

然后,笔者就遇到了第一个坑,按照如下写法以后,cookie居然神奇的不同步(下面是伪代码,下面是伪代码)

img_3c231744eb494040d0babb39ccb1f764.png
cookie不同步

之前笔者通过字符串拼接,也就是append字符串 ,拼接字符串以后,我想直接通过cookieManager.setCookie(url, cookie); 在x5WebView.loadUrl(url);调用之前去设置cookie,

然后,cookie就是同步不了。没得办法,打印日志之后发现,手动设置的cookie值,神奇的只有一个分号 !

谷歌百度后,有哥们说是因为cookie Value的值在读取时,只会读取到第一个分号时,当发现第一个分号即认为读取结束。所以分号后面的cookie的值将不会读取,实际测试确实是这样。那么,我们该如何解决拼接cookie读取失败的问题?

解决办法如下图,我们可以一个个手动设置cookie,即可拼接完整的Cookie。(这种办法虽然笨拙,但的确可以有效解决分号切割问题)

img_36a4559c24962757743e38328a240a47.png
setCookie解决办法

当然,我在公司项目里用的是Okhttp,(为什么这里用Okhttp,因为!这样就可以用Okhttp、Retrofit、OkGo等网络框架,直接集成 我在项目中给大家提供的拦截器、自定义CookieJar使用了)。通过自定义拦截器,实现CookieJar去完成同步客户端和H5的cookie状态。这里先上下最终效果图:(笔者的代码可能不是唯一实现功能需求的,但凑合还能用。实现方式有很多种,写的不好也请大家见谅)

img_aae21a51038c6e453ebf349ac0168d23.png
Okhttp简单设置

关于AddCookiesInterceptor以及SaveCookiesInterceptor这两个拦截器,主要就是存Cookie和使用Cookie,具体说明可以参考 两个拦截器的说明 ,然后我们点进自定义cookieJar中的 SaCookieManger

img_d08fdbf5f5f5e565c40d78c445f37a75.png
SaCookieManger

这个类定义了一个context构造参数,在保存cookie的saveFromResponse方法中,调用了SaasCookieManager.loadCookie(cookies,url.host());方法,我们点进SaasCookieManager


img_f22fb0a18c348bf991e1240821614986.png
SaasCookieManager

通过遍历添加到集合里面,然后一个个的setCookie( url ,cookie )、接着判断SDK版本号进行同步刷新即可,具体可以参考项目源代码。

当然大家也可以在这里面根据开发需求去增加自己的实际功能。

通过上面的步骤,我们就可以简单的实现 客户端与H5端同步cookie。

笔者的项目里面,是客户端登录成功以后,进入H5页面,H5页面上直接显示已登录状态。

拓展:有部分手机使用后可能还是无法同步,那么我们可以尝试,设置跨域读取cookie,开启webview对第三方cookie的支持。


img_29f808b4691886e9d31e76e6a3ca36a2.png
跨域查询

当页面加载完毕的时候,我们可以通过下面的截图代码,去获取H5上面的cookie,我们也可以打印日志、进行同步

img_540d94524cb4cc77fd477d6e1a51807d.png
页面加载完毕

需求二:

监听进度,是这样,WebView里面的WebChromeClient这个类,里面有个onProgressChanged方法,重写这个方法就可以获取加载进度。获取到X5Webview的进度之后,还需要通过WebView的setWebChromeClient方法,将我们自定义的WebChromeClient对象传进去,即可完成进度监听。


img_c72ee1accadf93f12f0777329cb9cacc.png
监听进度

拓展:WebViewClient 内置的shouldOverrideUrlLoading(WebView view, String url)这个函数的主要意思是指:检查URL主机是否与特定域匹配。 如果它匹配,则该方法返回false以便不覆盖URL加载(它允许WebView像往常一样加载URL); 如果URL主机不匹配,则Intent创建一个以启动默认活动以处理URL(解析为用户的默认Web浏览器)。

需求三:封装X5Webview基本功能

常用设置:

比如设置对JS的支持等等一些比较常用的,我们可以直接这样设置


img_8bb821ad92ccc74916ac042b49140d33.png
常用设置


滚动条(内侧、外侧的设置),隐藏或显示的基本使用:

img_9bbf8148ae16af089ec00a83cf886b9c.png
滚动条属性设置

处理预加载:

有的小伙伴说,X5预加载不是很友好。在加载X5内核的时候,X5内核需要进行一些初始化,这些初始化如果不明确指出运行的线程,它就会在你启动页面的时候,默认在主线程中执行,因此就会出现卡顿(这个现象时有时无,但是我们在代码层面尽可能的去规避使用风险),所以,我们可以写个 IntentService 去帮我们管理预加载问题:


img_2b2a5ed9a15b265fa67b94793ac2e254.png
IntentService

多提一嘴:IntentService是Service的子类,比普通的Service增加了额外的功能。

IntentService会创建独立的worker线程来处理所有的Intent请求;

会创建独立的worker线程来处理onHandleIntent()方法实现的代码,无需处理多线程的问题;

所有请求处理完成后,IntentService会自动停止,开发者无需手动调用stopSelf()方法停止Service;

写完之后我们在去自定义Application里面注册服务:(别忘了去清单文件配置Services)


img_28da10294d397bfaa3fbae6c4f27ae9b.png
Application使用service

返回键的处理:

这个就根据大家开发需求具体使用了,有的要求返回键按下两次才允许退出等等

生命周期的处理、释放资源的处理:这个就不说了,大家查阅资料集成功能即可

拦截广告的处理:

有些哥们说,使用这个经常会出现广告,解决这个办法有两个办法

1:使用Https

2:设计拦截url规则,对允许的url进行放行加载,不允许的url,WebView禁止加载

Android8.0系统适配:

2017年8月份,谷歌正式发布了Android8.0系统,时隔3个多月谷歌正式发布了Android 8.1的正式版。但是目前,Android用户持有的系统版本百分之85的系统是介于Android4.4-Android7.0这个系统版本之间,好了,这样真机调试就会有一定的局限性。现在出现了这样一种情况,使用X5去加载Url,8.1系统以下的都正常,8.1系统以上的的就会有问题。这不,腾讯的X5社区也有别的开发者反馈了这个问题,但是没人回答:

img_218a82ff7b9c4aa0294923be05965601.png
8.1系统的问题
img_edffc7ec7379518f17f1a8a5e3c27278.png
8.1系统的问题

具体他是什么问题我不清楚(最后分析可能是遇到了同样的问题),这里先细说我遇到的问题。还是文章内部的代码,到了8.1系统以后,我这边通过X5WebView加载H5游戏就有问题。我们知道 初始化的时候,首先需要调用 QbSdk.PreInitCallback 这个回调函数,也就是onViewInitFinished ( boolean ininTag )这个回调函数,这个函数主要是完成x5內核初始化,其中,这里的ininTag为true则表示x5内核加载成功,false即表示x5内核加载失败,如果为false,X5内核会自动切换到系统内核。

 现在的一个情况是,加载到X5内核以后,这个initTag有一定几率会失败。你可能会说既然初始化失败那就使用系统的WebView呀,嗯,没错,但是现在切换原生的WebView以后,就加载不出来了(蜜汁尴尬)这个原因后面也会说,基于此这里引用一段谷歌针对8.0系统的官方文档:


多个 Android 应用和服务可以同时运行。 例如,用户可以在一个窗口中玩游戏,同时在另一个窗口中浏览网页,并使用第三个应用播放音乐。同时运行的应用越多,对系统造成的负担越大。 如果还有应用或服务在后台运行,这会对系统造成更大负担,进而可能导致用户体验下降;例如,音乐应用可能会突然关闭。应用在两个方面受到限制:

后台服务限制:处于空闲状态时,应用可以使用的后台服务存在限制。 这些限制不适用于前台服务,因为前台服务更容易引起用户注意。

广播限制:除了有限的例外情况,应用无法使用清单注册隐式广播。 它们仍然可以在运行时注册这些广播,并且可以使用清单注册专门针对它们的显式广播。

注:默认情况下,这些限制仅适用于针对 O 的应用。

在后台中运行的服务会消耗设备资源,这可能降低用户体验。 为了缓解这一问题,系统对这些服务施加了一些限制。

系统可以区分 前台 和 后台 应用。 (用于服务限制目的的后台定义与内存管理使用的定义不同;一个应用按照内存管理的定义可能处于后台,但按照能够启动服务的定义又处于前台。)如果满足以下任意条件,应用将被视为处于前台:

具有可见 Activity(不管该 Activity 已启动还是已暂停)。

具有前台服务。

另一个前台应用已关联到该应用(不管是通过绑定到其中一个服务,还是通过使用其中一个内容提供程序)。 例如,如果另一个应用绑定到该应用的服务,那么该应用处于前台:

A:IME

B:壁纸服务

C:通知侦听器

D:语音或文本服务

E:如果以上条件均不满足,应用将被视为处于后台。

F:绑定服务不受影响,这些规则不会对绑定服务产生任何影响。 如果您的应用定义了绑定服务,则不管应用是否处于前台,其他组件都可以绑定到该服务。

为了降低发生这些问题的几率,Android 8.0 对应用在用户不与其直接交互时可以执行的操作施加了限制。

在 Android 8.0 之前,创建前台服务的方式通常是先创建一个后台服务,然后将该服务推到前台。

Android 8.0 有一项复杂功能;系统不允许后台应用创建后台服务。 因此,Android 8.0 引入了一种全新的方法,即Context.startForegroundService(),以在前台启动新服务。


以上文档截取自8.0系统谷歌官方文档,那么这一段话主要的意思就是新系统限制了服务,因此,我们写的IntentService就不要这样写了(谷歌有新的推荐方式我这里怎么快就怎么来吧),直接将IntentService里面初始化X5内核的代码拷贝出来,放在自定义Application里面的onCreate()即可。

还有一点,可能是手机或者种种问题,我这边初始化成功的概率大概是百分之90(测试了十次,有一次内核没有初始化成功),为了规避这种初始化失败又切换到系统内核加载不出来的风险,我找了个笨方法,那就是如果初始化失败就让他继续初始化直到X5初始化成功(这里使用的是EventBus去通知结果),初始化成功以后才使用X5Webview去加载url。

下面是代码截图:

img_6e1d00cbe72cf18573287edcd02013b8.png
自己的8.1解决方案

当然,这只是笔者自己的解决方案(笨办法),如果腾讯技术团队有最新的说明或者开发者有更好的解决方案,请直接在评论区指出,欢迎斧正,谢谢。

最新增加:Https与Http混合加载

我想,这个问题的出现,是之前X5内核在8.1系统上初始化失败,笔者做的一个实验尝试。因为X5内核在8.1系统上初始化失败(解决办法可以参考上面的),所以笔者又将WebView换成了原生的。好的,老铁没毛病,用了原生的WebView以后,问题又出现了,H5游戏加载不出来,这就尴尬到新的地步了?

带着黑人小哥三个问号的我,没办法呐,花时间跟踪调试,最后发现:这个H5内置的脚本资源,居然是Https和Http两种JS脚本混合的!!!

但是!!!X5内部默认实现了混合加载!!!所以现在切换到原生WebView以后,加载不出来了。因此针对这种特殊情况,需要加上新的API。

我们知道Https简单讲就是HTTP的安全版,为什么它是安全的版本?因为Https提供了身份验证与加密通讯方法(确切的说是SSL)但是,Https需要证书,但是Android这边针对WebView加载Https的一般做法是忽略SSL证书错误,继续加载页面。所以需要重写WebViewClient的onReceivedSslError(WebView view, SslErrorHandler handler, SslError error)方法,实现代码如下:

    public WebViewClient client = new WebViewClient() {

        @Override

        public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {

            //  忽略SSL证书错误,继续加载页面

            handler.proceed();

        }

}

证书的问题我们忽略以后,接下来还需要重写WebSettings内置的API,一行代码搞定:

WebSettings  webSetting = getSettings();

//允许混合加载

webSetting.setAllowUniversalAccessFromFileURLs(true);

这样就可以实现原生WebView混合加载的问题。

附录:项目地址

如果觉得这篇文章对你有帮助,希望点下一个小小的star,谢谢。

Ps:著作权归作者所有,转载请注明作者, 商业转载请联系作者获得授权,非商业转载请注明出处(开头或结尾请添加转载出处,添加原文url地址),文章请勿滥用、开源项目仅供学习交流、也希望大家尊重笔者的劳动成果,谢谢。

相关文章
|
13天前
|
安全 数据安全/隐私保护 Android开发
探索Android与iOS的隐私保护策略
在数字时代,智能手机已成为我们生活中不可或缺的一部分,而随之而来的则是对个人隐私和数据安全的日益关注。本文将深入探讨Android与iOS两大操作系统在隐私保护方面的策略和实践,分析它们如何应对日益严峻的隐私挑战,以及用户应如何保护自己的数据安全。通过对比分析,我们将揭示两大系统在隐私保护方面的优势和不足,为用户提供有价值的见解和建议。
|
4月前
|
缓存 监控 Android开发
探索iOS与安卓开发中的性能优化策略
在移动应用开发的竞技场上,iOS和安卓这两大操作系统不断推动着技术的边界。性能优化,作为提升用户体验的关键因素,已成为开发者们关注的焦点。本文将深入探讨两大平台上的性能优化实践,揭示如何通过工具、技术和策略来提升应用的响应速度和流畅度,同时考虑到电池寿命和内存管理等关键指标。
|
14天前
|
前端开发 Android开发 开发者
探索Android与iOS的跨平台开发策略
在当今多元化的移动设备市场中,开发者面临着为不同操作系统设计应用的挑战。本文深入探讨了Android和iOS两大主流平台的跨平台开发策略。我们将分析使用Flutter、React Native等框架进行跨平台开发的优劣,并讨论如何克服各平台间的差异性,以实现高效、一致的用户体验。此外,文章还将提供一些实用的技巧和最佳实践,帮助开发者优化跨平台应用的性能和兼容性。
33 4
|
15天前
|
前端开发 Android开发 iOS开发
探索Android与iOS的跨平台开发策略
在移动应用开发的多元化时代,跨平台开发已成为开发者追求效率和广泛覆盖的重要手段。本文深入探讨了Android与iOS两大主流平台下的跨平台开发策略,分析了各自的优势与挑战,并通过实际案例展示了如何有效实施跨平台解决方案,以期为开发者提供有价值的参考和启示。
|
2月前
|
调度 Android开发 开发者
构建高效Android应用:探究Kotlin多线程优化策略
【10月更文挑战第11天】本文探讨了如何在Kotlin中实现高效的多线程方案,特别是在Android应用开发中。通过介绍Kotlin协程的基础知识、异步数据加载的实际案例,以及合理使用不同调度器的方法,帮助开发者提升应用性能和用户体验。
51 4
|
2月前
|
监控 测试技术 Android开发
掌握安卓性能优化的关键策略
【10月更文挑战第7天】 在移动应用开发领域,性能优化是一项至关重要的任务。本文将探讨安卓应用性能优化的重要性、关键策略以及实际操作建议,帮助开发者提升应用的用户体验和竞争力。通过深入浅出的方式,我们将从背景介绍到具体实践,全面解析安卓性能优化的各个维度。
|
23天前
|
安全 Android开发 iOS开发
深入探索iOS与Android系统的差异性及优化策略
在当今数字化时代,移动操作系统的竞争尤为激烈,其中iOS和Android作为市场上的两大巨头,各自拥有庞大的用户基础和独特的技术特点。本文旨在通过对比分析iOS与Android的核心差异,探讨各自的优势与局限,并提出针对性的优化策略,以期为用户提供更优质的使用体验和为开发者提供有价值的参考。
|
2月前
|
安全 Android开发 数据安全/隐私保护
安卓应用开发中的常见挑战及解决策略
【10月更文挑战第7天】在安卓应用开发的旅程中,开发者常面临各种挑战,从设备兼容性到性能优化,再到用户界面设计。本文将深入探讨这些常见问题,并提供实用的解决策略,帮助开发者提升应用质量和用户体验。我们将通过代码示例和实践建议,展示如何克服这些挑战,打造更流畅、更吸引人的安卓应用。
54 0
|
3月前
|
调度 Android开发 UED
Android经典实战之Android 14前台服务适配
本文介绍了在Android 14中适配前台服务的关键步骤与最佳实践,包括指定服务类型、请求权限、优化用户体验及使用WorkManager等。通过遵循这些指南,确保应用在新系统上顺畅运行并提升用户体验。
215 6
|
4月前
|
存储 JavaScript 前端开发
Cookie 反制策略详解:Cookie加解密原理、Cookie和Session机制、Cookie hook、acw_sc__v2、jsl Cookie调试、重定向Cookie
Cookie 反制策略详解:Cookie加解密原理、Cookie和Session机制、Cookie hook、acw_sc__v2、jsl Cookie调试、重定向Cookie
211 1