当前位置: 移动技术网 > 移动技术>移动开发>Android > Android中WebView的基本配置与填坑记录大全

Android中WebView的基本配置与填坑记录大全

2019年07月24日  | 移动技术网移动技术  | 我要评论
前言 在应用程序开发过程中,经常会采用webview来展现某些界面,这样就可以不受发布版本控制,实时更新,遇到问题可以快速修复。 但是在android开发中,由于and

前言

在应用程序开发过程中,经常会采用webview来展现某些界面,这样就可以不受发布版本控制,实时更新,遇到问题可以快速修复。

但是在android开发中,由于android版本分化严重,每一个版本针对webview都有部分更改,因此在开发过程中会遇到各种各样的坑,下面这篇就来给大家介绍关于android中webview的基本配置与填坑记录,话不多说了,来一起看看详细的介绍吧。

基本配置

// 硬件加速
getactivity().getwindow().setflags(
 windowmanager.layoutparams.flag_hardware_accelerated,
 windowmanager.layoutparams.flag_hardware_accelerated);
// webview 配置
websettings websettings = mwebview.getsettings();
// 生命周期
mwebview.onpause(); // 通过 onpause 动作通知内核暂停所有的动作,如 dom 的解析、plugin 的执行、javascript 执行等
mwebview.onresume(); // 恢复 webview,能正常执行网页的响应
((viewgroup) mwebview.getparent()).removeview(mwebview);
mwebview.destroy(); // 当 activity 要 destroy 时,应先将 webview 移除,再 destroy 掉
// 前进后退
if (mwebview.cangoback()) {
 mwebview.goback();
}
if (mwebview.cangoforward()) {
 mwebview.goforward();
}
// 缓存相关
mwebview.clearcache(true); // 清除缓存
mwebview.clearhistory(); // 清除历史
mwebview.clearformdata(); // 清除表单数据
websettings.setcachemode(websettings.load_no_cache);// 设置缓存模式
// 缓存模式
load_default: 默认,根据 cache-control 决定是否从网络上取数据
load_normal: api level 17 中已经废弃, 从api level 11开始作用同 load_default 模式
load_cache_else_network: 只要本地有,无论是否过期,或者 no-cache,都使用缓存中的数据
load_no_cache: 不使用缓存,只从网络获取数据
load_cache_only: 不使用网络,只读取本地缓存数据
// js 相关
websettings.setjavascriptenabled(true); // 支持 js。如果碰到后台无法释放 js 导致耗电,应在 onstop 和 onresume 里分别设成 false 和 true 
mwebview.addjavascriptinterface(new webappinterface(this), "android"); // js 接口
websettings.setpluginsenabled(true); // 支持插件
// 设置自适应屏幕,两者合用
websettings.setusewideviewport(true); // 将图片调整到适合 webview 的大小 
websettings.setloadwithoverviewmode(true); // 缩放至屏幕的大小
// 缩放操作
websettings.setsupportzoom(true); // 支持缩放,默认为 true
websettings.setbuiltinzoomcontrols(true); // 设置内置的缩放控件,若为 false,则该 webview 不可缩放
websettings.setdisplayzoomcontrols(false); // 隐藏原生的缩放控件

填坑记录

1、webviewclient 类常用方法

mwebview.setwebviewclient(new mywebviewclient());

shouldoverrideurlloading()

在网页上的所有加载都经过这个方法,这个函数我们可以做很多操作。

onpagestarted()

开始载入页面调用的,我们可以设定一个 loading 的页面,告诉用户程序在等待网络响应。

onpagefinished()

在页面加载结束时调用。我们可以关闭 loading 条,切换程序动作。

onloadresource()

在加载页面资源时会调用,每一个资源(比如图片)的加载都会调用一次。

onreceivederror()

加载页面出现错误时调用。

2、webchromeclient 类常用方法

mwebview.setwebchromeclient(new mywebchromeclient());

onprogresschanged()

获得网页的加载进度并显示。

onreceivedtitle()

获取 web 页中的标题。

onjsalert()

支持 javascript 的警告框。

onjsconfirm()

支持 javascript 的确认框。

onjsprompt()

支持 javascript 输入框。

3、 https 和 http 混合模式

从 android 5.0 开始,webview 默认不支持同时加载 https 和 http 资源。

解决方法:在webview加载页面之前,设置加载模式为 mixed_content_always_allow

if (build.version.sdk_int >= build.version_codes.lollipop) {
 webview.getsettings().setmixedcontentmode(websettings.mixed_content_always_allow);
}

4、安全问题

addjavascriptinterface

android 4.2 以前,要采用拦截 prompt() 的方式进行漏洞修复;android 4.2 以后,只需要对被调用的函数以 @javascriptinterface 进行注解。

searchboxjavabridge_、accessibility、accessibilitytraversal

if (build.version.sdk_int < build.version_codes.kitkat) {
 mwebview.removejavascriptinterface("searchboxjavabridge_");
 mwebview.removejavascriptinterface("accessibility");
 mwebview.removejavascriptinterface("accessibilitytraversal");
}

密码明文存储漏洞

websettings.setsavepassword(false);

5、替换 webview 的加载错误页面

@override
public void onreceivederror(webview view, int errorcode, string description, string failingurl) {
 super.onreceivederror(view, errorcode, description, failingurl);
 showcusterrorpage();
}
private view merrorview;
protected void showcusterrorpage() {
 // 移除webview
 viewgroup webparentview = (viewgroup) mwebviewinstance.getparent();
 while (webparentview.getchildcount() > 0) {
 webparentview.removeviewat(0);
 }
 // 生成自定义错误页面
 if (merrorview == null) {
 merrorview = view.inflate(mcontext, r.layout.webview_error, null);
 merrorview.setonclicklistener(new view.onclicklistener() {
  public void onclick(view v) {
  showwebviewpage();
  mwebviewinstance.reload();
  }
 });
 }
 // 替换为错误页面
 viewgroup.layoutparams lp = new viewgroup.layoutparams(
  viewpager.layoutparams.fill_parent, viewpager.layoutparams.fill_parent);
 webparentview.addview(merrorview, 0, lp);
}
protected void showwebviewpage() {
 // 移除自定义错误页面
 viewgroup webparentview = (viewgroup) merrorview.getparent();
 while (webparentview.getchildcount() > 0) {
 webparentview.removeviewat(0);
 }
 // 替换为webview
 viewgroup.layoutparams lp = new viewgroup.layoutparams(
  viewpager.layoutparams.fill_parent, viewpager.layoutparams.fill_parent);
 webparentview.addview(mwebviewinstance, 0, lp);
}

6、webview的内存泄露。

关于这个问题,我很难给你一个清晰的描述,你在谷歌里搜 webview lead memory 能搜到很多结果 甚至还有给谷歌提交的issue 哈哈,我也无法给出一个清晰的答案 在什么时候 什么版本那些手机上一定会出现内存泄露,

但是根据我自己的monkey结果来看,有时,webview内存泄露的情况还是很严重的,尤其是当你加载的页面比较庞大的时候。解决方案 我查了很多也用了很多,但是都不太理想,最后看了下微信和qq的做法,试了一下是目前效果最好的,

就是 当你要用webview的时候,记得最好 另外单独开一个进程 去使用webview 并且当这个 进程结束时,请手动调用system.exit(0)。

这是目前对于webview 内存泄露 最好的解决方案。使用此方法 所有因为webview引发的 资源无法释放等问题 全部可以解决。

7、getsettings().setbuiltinzoomcontrols(true) 引发的crush。

这个方法调用以后 如果你触摸屏幕 弹出那个提示框还没消失的时候 你如果activity结束了 就会报错了。3.0以上 4.4以下很多手机会出现这种情况

所以为了规避他,我们通常是在activity的ondestroy方法里手动的将webiew设置成 setvisibility(view.gone)

8、onpagefinished 函数到底有用没有?

多数开发者都是参考的http://stackoverflow.com/questions/3149216/how-to-listen-for-a-webview-finishing-loading-a-url-in-android 这个上面的高票答案。

但其实根据我自己观察,这个函数并没有什么卵用,有的时候是提前结束,有的时候就迟迟无法结束,你信这个函数 还不如信上帝,甚至于onprogresschanged这个函数

都比onpagefinished 要准一些。如果你的产品经理坚持你一定要实现这种功能的话,我建议你 提早结束他,否则卡在那用户迟迟动不了 这种体验不好。

有空的同学可以跟一下源码,onpagefinished 在不同的内核里 调用的时机都不一样。说实话 我也很醉。。。这个问题 有完美解决方案的 请知会我一下。。。

9、后台无法释放js 导致耗电。

这个可能很少有人知道,我也是被投诉过 才了解,在有的手机里,你如果webview加载的html里 有一些js 一直在执行比如动画之类的东西,如果此刻webview 挂在了后台

这些资源是不会被释放 用户也无法感知。。。导致一直占有cpu 耗电特别快,所以大家记住了,如果遇到这种情况 请在onstop和onresume里分别把setjavascriptenabled();

给设置成false和true。

10、如果实在不想用开额外进程的方式解决webview 内存泄露的问题,那么下面的方法很大程度上可以避免这种情况

public void releaseallwebviewcallback() {
  if (android.os.build.version.sdk_int < 16) {
   try {
    field field = webview.class.getdeclaredfield("mwebviewcore");
    field = field.gettype().getdeclaredfield("mbrowserframe");
    field = field.gettype().getdeclaredfield("sconfigcallback");
    field.setaccessible(true);
    field.set(null, null);
   } catch (nosuchfieldexception e) {
    if (buildconfig.debug) {
     e.printstacktrace();
    }
   } catch (illegalaccessexception e) {
    if (buildconfig.debug) {
     e.printstacktrace();
    }
   }
  } else {
   try {
    field sconfigcallback = class.forname("android.webkit.browserframe").getdeclaredfield("sconfigcallback");
    if (sconfigcallback != null) {
     sconfigcallback.setaccessible(true);
     sconfigcallback.set(null, null);
    }
   } catch (nosuchfieldexception e) {
    if (buildconfig.debug) {
     e.printstacktrace();
    }
   } catch (classnotfoundexception e) {
    if (buildconfig.debug) {
     e.printstacktrace();
    }
   } catch (illegalaccessexception e) {
    if (buildconfig.debug) {
     e.printstacktrace();
    }
   }
  }
 }

在webview的 destroy方法里 调用这个方法就行了。

11、另外很多人 不知道webview 实际上有自己一套完整的cookie机制的,利用好这个 可以大大增加对客户端的访问速度。

实际上cookie就是存放在这个表里的。

很多人都想要一个效果:网页更新cookie 设置完cookie以后 不刷新页面即可生效。这个在2.3以下和2.3以上要实现的方法不太一样,所以要做一次兼容

public void updatecookies(string url, string value) {
  if (build.version.sdk_int <= build.version_codes.gingerbread_mr1) { // 2.3及以下
   cookiesyncmanager.createinstance(getcontext().getapplicationcontext());
  }
  cookiemanager cookiemanager = cookiemanager.getinstance();
  cookiemanager.setacceptcookie(true);
  cookiemanager.setcookie(url, value);
  if (build.version.sdk_int <= build.version_codes.gingerbread_mr1) {
   cookiesyncmanager.getinstance().sync();
  }
 }

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对移动技术网的支持。

如您对本文有疑问或者有任何想说的,请 点击进行留言回复,万千网友为您解惑!

相关文章:

验证码:
移动技术网