Android WebView问题汇总以及解决方法

Android WebView常见问题解决方案汇总:

1、Android webview背景设置为透明无效

webview是一个使用方便、功能强大的控件,但由于webview的背景颜色默认是白色,在一些场合下会显得很突兀(比如背景是黑色)。

此时就想到了要把webview的背景设置为透明,这样就可以与其背景融为一体。

在2.X的平台下,一般设置webview背景为透明的方法如下:

wvContent.setBackgroundColor(0);

但当程序在4.0上使用时,发现居然这种设置方法无法,即使通过上面设置背景为0,照样显示出原来默认的白色背景。

通过网上查找,发现原来是由于硬件加速导致的,此时就想到了使用代码关闭当前webview的硬件加速,方法如下:

wvContent.setLayerType(View.LAYER_TYPE_SOFTWARE,null);

这时发现又有新问题,如果要通过该代码进行设置,SDK最低版本也要11(android 3.0)无法正常编译

这时需要在布局文件中设置 android:layerType="software"

通过测试,在4.0和2.2都能正常运行,webview透明背景设置成功

2、WebView页面中播放了音频,退出Activity后音频仍然在播放

需要在Activity的onDestory()中调用webView.destroy();

但是直接调用可能会引起如下错误:

06-10 15:01:11.402: E/ViewRootImpl(7502): sendUserActionEvent() mView == null
06-10 15:01:26.818: E/webview(7502): java.lang.Throwable: Error: WebView.destroy() called while still attached!
06-10 15:01:26.818: E/webview(7502): at android.webkit.WebViewClassic.destroy(WebViewClassic.java:4142)
06-10 15:01:26.818: E/webview(7502): at android.webkit.WebView.destroy(WebView.java:707)
06-10 15:01:26.818: E/webview(7502): at com.didi.taxi.ui.webview.OperatingWebViewActivity.onDestroy(OperatingWebViewActivity.java:236)
06-10 15:01:26.818: E/webview(7502): at android.app.Activity.performDestroy(Activity.java:5543)
06-10 15:01:26.818: E/webview(7502): at android.app.Instrumentation.callActivityOnDestroy(Instrumentation.java:1134)
06-10 15:01:26.818: E/webview(7502): at android.app.ActivityThread.performDestroyActivity(ActivityThread.java:3619)
06-10 15:01:26.818: E/webview(7502): at android.app.ActivityThread.handleDestroyActivity(ActivityThread.java:3654)
06-10 15:01:26.818: E/webview(7502): at android.app.ActivityThread.access$1300(ActivityThread.java:159)
06-10 15:01:26.818: E/webview(7502): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1369)
06-10 15:01:26.818: E/webview(7502): at android.os.Handler.dispatchMessage(Handler.java:99)
06-10 15:01:26.818: E/webview(7502): at android.os.Looper.loop(Looper.java:137)
06-10 15:01:26.818: E/webview(7502): at android.app.ActivityThread.main(ActivityThread.java:5419)
06-10 15:01:26.818: E/webview(7502): at java.lang.reflect.Method.invokeNative(Native Method)
06-10 15:01:26.818: E/webview(7502): at java.lang.reflect.Method.invoke(Method.java:525)
06-10 15:01:26.818: E/webview(7502): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1187)03-10 15:01:26.818: E/webview(7502): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1003)
06-10 15:01:26.818: E/webview(7502): at dalvik.system.NativeStart.main(Native Method)

如上所示,webview调用destory时,webview仍绑定在Activity上.这是由于自定义webview构建时传入了该Activity的context对象,因此需要先从父容器中移除webview,然后再销毁webview:rootLayout.removeView(webView);

3、WebView保留缩放功能但隐藏缩放控件:

mWebView.getSettings().setSupportZoom(true);
mWebView.getSettings().setBuiltInZoomControls(true);
if (DeviceUtils.hasHoneycomb())
mWebView.getSettings().setDisplayZoomControls(false);  

注意:setDisplayZoomControls是在Android 3.0中新增的API.

4、为WebView自定义错误显示界面:

覆写WebViewClient中的onReceivedError()方法:

/**
 * 显示自定义错误提示页面,用一个View覆盖在WebView
 */
protected void showErrorPage() {
    LinearLayout webParentView = (LinearLayout)mWebView.getParent();
    initErrorPage();
    while (webParentView.getChildCount() > 1) {
        webParentView.removeViewAt(0);
    }
    LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(LayoutParams.FILL_PARENT,LayoutParams.FILL_PARENT);
    webParentView.addView(mErrorView, 0, lp);
    mIsErrorPage = true;
}
protected void hideErrorPage() {
    LinearLayout webParentView = (LinearLayout)mWebView.getParent();  

    mIsErrorPage = false;
    while (webParentView.getChildCount() > 1) {
        webParentView.removeViewAt(0);
    }
}
protected void initErrorPage() {
    if (mErrorView == null) {
        mErrorView = View.inflate(this, R.layout.online_error, null);
        Button button = (Button)mErrorView.findViewById(R.id.online_error_btn_retry);
        button.setOnClickListener(new OnClickListener() {
            public void onClick(View v) {
                mWebView.reload();
            }
        });
        mErrorView.setOnClickListener(null);
    }
}
@Override
public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
mErrorView.setVisibility(View.VISIBLE);
super.onReceivedError(view, errorCode, description, failingUrl);
} 

5、WebView cookies清理:

CookieSyncManager.createInstance(this);
CookieSyncManager.getInstance().startSync();
CookieManager.getInstance().removeSessionCookie();   

但是CookieManager已经过时,不建议使用。

文档中提示The WebView now automatically syncs cookies as necessary.

6、清理cache 和历史记录:

webView.clearCache(true);
webView.clearHistory();
m_webview.loadDataWithBaseURL(null, result,"text/html", "utf-8",null);

7、判断WebView是否已经滚动到页面底端:

getScrollY()方法返回的是当前可见区域的顶端距整个页面顶端的距离,也就是当前内容滚动的距离.

getHeight()或者getBottom()方法都返回当前WebView 这个容器的高度

getContentHeight 返回的是整个html 的高度,但并不等同于当前整个页面的高度,因为WebView 有缩放功能, 所以当前整个页面的高度实际上应该是原始html 的高度再乘上缩放比例. 因此,更正后的结果,准确的判断方法应该是:

if(WebView.getContentHeight*WebView.getScale() == (webview.getHeight()+WebView.getScrollY()))

{ //已经处于底端 }

8、URL拦截:

Android WebView是拦截不到页面内的fragment跳转的。但是url跳转的话,又会引起页面刷新,H5页面的体验又下降了。只能给WebView注入JS方法了。

9、处理WebView中的非超链接请求(如Ajax请求):

有时候需要加上请求头,但是非超链接的请求,没有办法再shouldOverrinding中拦截并用webView.loadUrl(String url,HashMap headers)方法添加请求头

目前用了一个临时的办法解决:

首先需要在url中加特殊标记/协议, 如在onWebViewResource方法中拦截对应的请求,然后将要添加的请求头,以get形式拼接到url末尾

在shouldInterceptRequest()方法中,可以拦截到所有的网页中资源请求,比如加载JS,图片以及Ajax请求等等

@SuppressLint("NewApi")
@Override
public WebResourceResponse shouldInterceptRequest(WebView view,String url) {
    // 非超链接(如Ajax)请求无法直接添加请求头,现拼接到url末尾,这里拼接一个imei作为示例
    String ajaxUrl = url;
    // 如标识:req=ajax
    if (url.contains("req=ajax")) {
       ajaxUrl += "&imei=" + imei;
    }
    return super.shouldInterceptRequest(view, ajaxUrl);  

}  

10、在页面中先显示图片:

@Override
public void onLoadResource(WebView view, String url) {
  mEventListener.onWebViewEvent(CustomWebView.this, OnWebViewEventListener.EVENT_ON_LOAD_RESOURCE, url);
    if (url.indexOf(".jpg") > 0) {
     hideProgress(); //请求图片时即显示页面
     mEventListener.onWebViewEvent(CustomWebView.this, OnWebViewEventListener.EVENT_ON_HIDE_PROGRESS, view.getUrl());
     }
    super.onLoadResource(view, url);
}  

11、屏蔽掉长按事件 因为webview长按时将会调用系统的复制控件:

mWebView.setOnLongClickListener(new OnLongClickListener() {
          @Override
          public boolean onLongClick(View v) {
              return true;
          }
      }); 

12、在WebView加入 flash支持:

String temp = "<html><body bgcolor=\"" + "black"
                + "\"> <br/><embed src=\"" + url + "\" width=\"" + "100%"
                + "\" height=\"" + "90%" + "\" scale=\"" + "noscale"
                + "\" type=\"" + "application/x-shockwave-flash"
                + "\"> </embed></body></html>";
String mimeType = "text/html";
String encoding = "utf-8";
web.loadDataWithBaseURL("null", temp, mimeType, encoding, "");  

13、WebView 在Android4.4的手机上onPageFinished()回调会多调用一次

需要尽量避免在onPageFinished()中做业务操作,否则会导致重复调用,还有可能会引起逻辑上的错误.

14、需要通过获取Web页中的title用来设置自己界面中的title及相关问题:

需要给WebView设置 WebChromeClient,并在onReceiveTitle()回调中获取

WebChromeClient webChromeClient = new WebChromeClient() {
            @Override
            public void onReceivedTitle(WebView view, String title) {
                super.onReceivedTitle(view, title);
                txtTitle.setText(title);
            }
        };    

但是发现在小米3的手机上,当通过webview.goBack()回退的时候,并没有触发onReceiveTitle(),这样会导致标题仍然是之前子页面的标题,没有切换回来.

这里可以分两种情况去处理:

(1) 可以确定webview中子页面只有二级页面,没有更深的层次,这里只需要判断当前页面是否为初始的主页面,可以goBack的话,只要将标题设置回来即可.

(2)webview中可能有多级页面或者以后可能增加多级页面,这种情况处理起来要复杂一些:

因为正常顺序加载的情况onReceiveTitle是一定会触发的,所以就需要自己来维护webview  loading的一个url栈及url与title的映射关系那么就需要一个ArrayList来保持加载过的url,一个HashMap保存url及对应的title.

正常顺序加载时,将url和对应的title保存起来,webview回退时,移除当前url并取出将要回退到的web 页的url,找到对应的title进行设置即可.这里还要说一点,当加载出错的时候,比如无网络,这时onReceiveTitle中获取的标题为 找不到该网页,因此建议当触发onReceiveError时,不要使用获取到的title.

15、WebView因addJavaScriptInterface()引起的安全问题.

这个问题主要是因为会有恶意的js代码注入,尤其是在已经获取root权限的手机上,一些恶意程序可能会利用该漏洞安装或者卸载应用.

关于详细的情况可以参考: https://github.com/pedant/safe-java-js-webview-bridge, 该项目利用onJsPrompt() 替代了addJavaScriptInterface(),同时增加了异步回调,

很好地解决了webview  js注入的安全问题.

欢迎扫描二维码,互相学习

时间: 2024-10-05 23:54:18

Android WebView问题汇总以及解决方法的相关文章

Android应用插件式开发解决方法

Android应用插件式开发解决方法 一.现实需求描述 一般的,一个Android应用在开发到了一定阶段以后,功能模块将会越来越多,APK安装包也越来越大,用户在使用过程中也没有办法选择性的加载自己需要的功能模块.此时可能就需要考虑如何分拆整个应用了. 二.解决方案提出 一般有两种方式,一种是将应用按照功能分拆成多个应用,用户需要哪个就下载哪个,都需要就都下载.应用之间,可以在代码层面做一定的关联,以共享部分信息.另一种方式,类似于其他平台插件的方式,用户可以在主应用中可以选择性的下载需要的插件

android studio 更新 Gradle错误解决方法(Gradle sync failed)

android studio 更新 Gradle错误解决方法 Android Studio每次更新版本都会更新Gradle这个插件,但由于长城的问题每次更新都是失败,又是停止在Refreshing Gradle Project ,有时新建项目的时候报 Gradle Project Compile Error 等等相关的问题 解决这些问题办法是 首先打开android studio项目 找到项目目录gradle\wrapper\gradle-wrapper.properties这个文件 内容如下

Android SDK下载速度慢的解决方法(简单使用代理)

相信做android开发的同学们,一定会遇到的问题就是google那边经常崩,但是学习的开始,我们又必须要用Android SDK,(几个G的大小),一般我们装完ADT之后(如果你用的是Eclipse,android studio的就不需要了.),这时候我们需要打开SDK Manager来下载Android SDK的一些工具,还有android不同版本的内容.但是你会发现速度慢得惊人.原因就是Google. 本来不想因为这个东西写一篇博文的,但是因为怕刚开始学android的人会在上面浪费很多时

Android应用插件式开发解决方法[转]

一.现实需求描述 一般的,一个Android应用在开发到了一定阶段以后,功能模块将会越来越多,APK安装包也越来越大,用户在使用过程中也没有办法选择性的加载自己需要的功能模块.此时可能就需要考虑如何分拆整个应用了. 二.解决方案提出 一般有两种方式,一种是将应用按照功能分拆成多个应用,用户需要哪个就下载哪个,都需要就都下载.应用之间,可以在代码层面做一定的关联,以共享部分信息.另一种方式,类似于其他平台插件的方式,用户可以在主应用中可以选择性的下载需要的插件,不需要该功能,则不需要下载. 第一种

android sdk manager 无法更新解决方法

因为在开始->运行->cmd 中敲入 ping dl-ssl.google.com -t 始终ping不通 ,关闭cmd后 首先需要下载一个代理服务器下载地址 http://pan.baidu.com/share/link?shareid=341717&uk=2601338879 打开此软件,在内容选项中 看到生成的代理地址,记住ip地址127.0.0.1 和端口号8580 之后打开android sdk manager.exe  打开tools里的options 在弹出的对话框中,把

Android WebView常见问题汇总

如有转载,请声明出处: 时之沙: http://blog.csdn.net/t12x3456 Android WebView常见问题解决方案汇总: 就目前而言,如何应对版本的频繁更新呢,又如何灵活多变地展示我们的界面呢,这又涉及到了web app与native app之间孰优孰劣的争论. 于是乎,一种混合型的app诞生了,灵活多变的部分,如淘宝商城首页的活动页面,一集凡客诚品中我们都可以见到web 页面与native页面的混合,既利用了web app的灵活易更新,也借助了native app本身

Android Studio ADB启动失败解决方法

在用Android studio启动自己的Android代码的时候,出现adb not responding. 解决方法: 1.输入netstat -aon|findstr "5037",可以看到进程号为5196的进程(这个进程号因机器和时间而异)在占用5037端口(adb需要使用此端口). 2.打开任务管理器,选择“进程”选项卡,点击选项栏“查看-选择列...”,勾选“PID(进程标识符)”,点确定.会看到每个进程都会显示它们的PID了.找到进程号为5196的进程,结束这个进程,ki

React Native在Android平台运行gif的解决方法

概述 目前RN在Android平台上不支持gif格式的图片,而在ios平台是支持的,期待以后的版本中系统也是可以默认支持Android的.首先说下在ios平台怎么加载gif呢? <Image source= {require('./img/loading.gif')} style = {styles.loading}/> 完整实例: xport default class Loading extends React.Component { render(){ if (!this.props.i

ubuntu下eclipse运行android emulator提示权限不够解决方法

在ubuntu下安装的eclipse及android sdk,运行模拟器时提示权限不够的解决方法是,在终端中找到当前sdk目录然后使用管理员权限执行以下命令: $  sudo  chmod  777  android-sdk-linux/  -R