Android Webview的一些坑
前言
Webview在开发中,总会遇到各种兼容,崩溃,支持各种功能的问题。这里整理下我们是如何处理这些问题的。这里不会说怎么开发一个基本的功能,像这样的文章应该有很多。这里会罗列一些我自己认为很有用的功能的实现,或者一些常见的问题。
带#号的url拼接参数
由于uri的格式问题,scheme://[path]?[param]#[fragment]
参数肯定是只能拼接到?号后方和#号前方的。
两种方法处理。
1、转化为uri,使用uri的api来拼接参数
2、自己处理字符串,通过“#”分为两部分,在第一部分上拼接参数
重载和回退问题
M页内部跳转的时候,有时候不希望返回上一个页面。因此在url上拼接特定的参数,如果检测到了这样的参数,直接跳过这条历史记录,返回上上个页面。
在一次域名升级过程中,FE通过replace方法替换了加载的域名,这时候页面会进行重载,在Android系统中,这个重载会在历史栈中留下记录,因此返回之后会回到原地址,然后又跳到新地址。造成问题。由于在旧的地址中参数不太切合实际(入口无法统计,替换难度工作量巨大。不可能全换掉。),因此在跳转后的url中拼接参数标记这是被替换的,上一个地址应该被忽略。因此有了这样的操作。
下面是对goBack的处理逻辑。
private void goBack(WebView webView) {
if (webView == null) {
return;
}
WebBackForwardList temp = webView.copyBackForwardList();
if (temp == null) {
webView.goBack();
return;
}
int cIndex = temp.getCurrentIndex();
WebHistoryItem item = temp.getItemAtIndex(cIndex);
int i;//需要退到的页面
i = cIndex - 1;
//isReplaced的url需要回退
while (item != null && StringUtils.isNotEmpty(item.getUrl())
&& item.getUrl().contains("isReplaced=1")) {
item = temp.getItemAtIndex(i);
i = i - 1;
}
//跳过url中包含isGoBack=1的链接,表示这个url不会进入回退列表
for (; i >= 0; i--) {
String url = temp.getItemAtIndex(i) == null ? null : temp.getItemAtIndex(i).getUrl();
if (!StringUtils.isNullOrEmpty(url) && (url.contains("isGoBack=1") || url.startsWith("data:text/html"))) {
if (i == 0 && getActivity() != null) {
//如果需要back的页面是not go back ,并且当前页面是最后一页 ,那么关闭activity
getActivity().finish();
return;
}
continue;
}
break;
}
if (i < 0 && getContext() != null) {
getActivity().finish();
return;
}
//往前back
webView.goBackOrForward(-cIndex + i);
}
返回拦截弹窗
在M页有时候会需要需要用户输入,通常情况下,用户误点击了返回之后就直接退出了这个页面。因此提供了一个可以让M页设置返回弹窗的功能。
具体做法就是通过提供JS入口,让FE可以设置返回弹窗。然后页面关闭之前判断是否有弹窗逻辑来进行拦截。
实现无TitleBar,穿透顶栏
有时候UI上会有一些要求,让M的标题栏特殊些或者穿透顶栏,或者没有标题栏之类的。
我们的处理是根据url中拼接的参数来决定这个页面的标题栏的样式或者隐藏,来决定是否穿透顶栏。
M页侧获取到的宽度为0
由于我们实现了离线包的功能,所以获取资源的速度很快。
后来发现部分页面加载的时候仅剩下了图片,没有文字。
客户端排查问题,发现页面加载完成的时候,实际上webview的宽度还是为0。
解决方案,webview布局到页面上的时候才去加载url。
mWebView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
if (mWebView != null) {
loadUrl(mUrl);
mWebView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
}
}
});
微信支付返回商家信息不一致的问题
一次我们收到其他业务线说在android上无法用微信的M页支付问题,经查明是因为Referer不一致导致,后来发现大部分android手机的Webview默认都不会带referer,因此造成了问题。这里在shouldOverrideUrlLoading的时候,加载新的url的时候添加进去Referer,这样就没有问题了。
Map<String, String> additionalHttpHeaders = new HashMap<String, String>();
additionalHttpHeaders.put("Referer", view.getUrl());
mWebView.loadUrl(url, additionalHttpHeaders);
魅族手机打开文件选择的问题
有些魅族机型在打开系统的选文件功能的时候会崩溃,说没有读取uri的权限,因此在启动M页的时候需要添加这样的权限。
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
其他
还有其他的一些功能很实用,一般都是M页通用的能力。比如全屏播放视频,选图,选文件,拍照,拍视频。这里说的是系统再带的功能。只需按照规范来实现功能就可以了。
结尾
还有一些对ssl的处理了,js的调用,js的调用前域名鉴权。这里不再说了。
网友评论