您的位置:首页 > 移动开发

使用WebView遇见的问题(如WebView中上传照片或文件,拦截JS)

2016-06-23 13:44 656 查看
webView.setJavaScriptEnabled(true),可能会影响Activity的生命周期,在魅族手机上出现,可能导致执行Activity的OnPause()生命周期。

浏览器内核:Webkit内核;Chrominum内核;Blink内核.

WebView加载H5也有两种模式,一种是加载服务器的H5页面,一种是加载本地的H5页面。

  WebView本身是一个AbsoluteLayout,绘制时,会把Canvas传入本地方法,由JNI调用把浏览器的UI绘制在Canvas上面。当用户聚焦一个输入框时,会生成一个TextView,并把它加入AbsoluteLayout中去。绘制流程变成先绘制浏览器,再绘制TextView,浏览器当中的输入框的样式大小会与TextView在用户每次对页面进行缩放时保持一致。在Android2.0/2.1两个平台上,因为TextView中文本的高度超过了边框调试,导致TextView中的文本只能显示出三分之二来,就出现了这个问题。

解决方案就是扩大TextView的文本框。

Android1.6及以前的版本,还有最新的2.2这个BUG都被官方解决了。

    在4.4版本之前,Android WebView基于WebKit实现。不过,在4.4版本之后,Android WebView就换成基于Chromium的实现了。基于Chromium实现,使得WebView可以更快更流畅地显示网页。在Android4.4之前的版本中,系统使用的是Webkit内核,Webkit内部包含了网络请求、页面渲染、js引擎等等。其后,切换到Google的Chromium内核。

 WebView是Android系统提供能显示网页的系统控件,它是一个特殊的View,同时它也是一个ViewGroup可以有很多其他子View。在Android 4.4以下(不包含4.4)系统WebView底层实现是采用WebKit内核,而在Android 4.4及其以上Google 采用了chromium内核作为系统WebView的底层内核支持。基于Chromium 的Webview和基于Webkit webview的差异,基于Chromium Webview提供更广的HTML5,CSS3,JavaScript支持,

  在目前最新Android 系统版本5.0上基于chromium 37,Webview提供绝大多数的Html5特性支持。Webkit JavaScript引起采用WebCore Javascript 在Android 4.4上换成了V8能直接提升JavaScript性能。另外Chromium 支持远程调试(Chrome DevTools)。

 WebView类直接继承于Android的布局类绝对布局AbsoluteLayout,这是由于绝对布局没有屏幕边框的缘故,这样加载Web网页时才能左右滑动,因为通常Web网页的宽度都是要远远大于手机屏幕的宽度的。

目前开源的浏览器内核sdk不多,主要有以下几个:ChromeView、Crosswalk、TbsX5(腾讯浏览服务)。

1.基于Chromium内核的开源ChromeView目前基本上没有维护,另一个问题是所编译出来的动态库太大,ARM 29M,x86 38M,这无疑对app体积来说是个大难题。因此放弃采用基于Chromium的ChromeView。

2.Crosswalk同样是基于Chromium内核,同样存在上述app体积问题,因此也放弃。

3.TbsX5基于谷歌Blink内核,并提供两种集成方案:1)只共享微信手Q空间的x5内核(for share),2)独立下载x5内核(with download)。

> Android WebView常见问题及解决方案汇总: http://blog.csdn.net/t12x3456/article/details/13769731/
那些年在WebView上踩过的坑- http://blog.csdn.net/u012124438/article/details/53401663
WebView适配问题- http://blog.csdn.net/a345017062/article/category/1359585
完美解决WebView与上层父元素的TouchMove事件冲突- http://blog.csdn.NET/daeees/article/details/39693231
Android 软键盘盖住输入框的问题-- http://blog.csdn.net/chengyingzhilian/article/details/7975277
> WebView中上传照片或文件

Android开发深入理解WebChromeClient之onShowFileChooser或openFileChooser使用说明- http://teachcourse.cn/2224.html#
Android-AdvancedWebView- https://github.com/delight-im/Android-AdvancedWebView/blob/ecff154ef390a0dbdb5337bd5dea2055205c104f/Source/src/im/delight/android/webview/AdvancedWebView.java#L1011
Android WebView支持Input type=file文件上传- http://blog.csdn.net/muzhengjun/article/details/51954580
Android笔记:Webview 支持 input type=file选择上传图片- http://glblong.blog.51cto.com/3058613/1726034/
> TTS Error: leaked ServiceConnection android.speech.tts.TextToSpeech ????(leaked ServiceConnection android.speech.tts.TextToSpeech$Connection@4274a9f8 that was originally bound here)

  I got this Leaked Connection when using a WebView in my Fragment. In the onCreateView method I did setJavaScriptEnabled(true), which caused this error, when pressing back on the Activity. To get rid of it, I moved the set to onResume(), and also set it to
false in onPause(), then problem disappeared.

> WebView.destroy() called while still attached 解决方法

解决方法如下:

    public void onDestroy() {

        if (webView != null) {

            ViewGroup parent = (ViewGroup) webView.getParent();

            if (parent != null) {

                parent.removeView(webView);

            }

            webView.removeAllViews();

            webView.destroy();

        }

        super.onDestroy();

    }

}

@Override
protected void onDestroy() {
super.onDestroy();

if (webView != null) {
webView.clearHistory();
webView.clearCache(true);
//       webView.loadUrl("about:blank"); // clearView() should be changed to loadUrl("about:blank"), since clearView() is deprecated now
webView.freeMemory();
webView.pauseTimers();

ViewGroup parent = (ViewGroup) webView.getParent();
if (parent != null) {
parent.removeView(webView);
}
webView.removeAllViews();
webView.destroy();
webView = null; // Note that mWebView.destroy() and mWebView = null do the exact same thing
}
//    webView.removeAllViews();
//    webView.destroy();
}

---------------------------

> WebView拦截JS

Android中使用WebView与JS交互全解析- http://blog.csdn.net/u012124438/article/details/53371102
// mShowWebpageWv.setWebChromeClient(new WebChromeClient() {

// @Override

// public boolean onCreateWindow(WebView view, boolean isDialog,

// boolean isUserGesture, Message resultMsg) {

// return super.onCreateWindow(view, isDialog, isUserGesture,

// resultMsg);

// }

// webView中就可以捕获javascript的alert()、confirm()事件了。

// @Override

// public boolean onJsAlert(WebView view, String url, String message,

// JsResult result) {

// Log.v(TAG, "JsAlert,message=" + message);

// Log.v(TAG, "JsAlert,result=" + result);

// Log.v(TAG, "JsAlert,url=" + url);

// return super.onJsAlert(view, url, message, result);

// }

// @Override

// public boolean onJsConfirm(WebView view, String url,

// String message, JsResult result) {

// return super.onJsConfirm(view, url, message, result);

// }

/ * 可以拦截到一些方法 在这里,我们会重载WebChromeClient的onJsPrompt方法,当此方法返回true的时候,

// * 就说明WebChromeClient已经处理了这个prompt事件,不需要再继续分发下去

// * 实现Javascript跟Android原生环境之间的同步访问

// */

// @Override

// public boolean onJsPrompt(WebView view, String url, String message,

// String defaultValue, JsPromptResult result) {

// return super.onJsPrompt(view, url, message, defaultValue,result);

// }

// @Override

// public boolean onConsoleMessage(ConsoleMessage consoleMessage) {

// Log.d("MattersTodoDetailsActivity", consoleMessage.message()

// + " -- From line " + consoleMessage.lineNumber()

// + " of " + consoleMessage.sourceId());

// return super.onConsoleMessage(consoleMessage);

// }

// });

> Webview加载不了https请求中的http图片

  公司之前用http被劫持了,webview打开的网页里面有小广告,于是老大就把请求链接改成了https,但是我们的图片服务器还是http的。这一改,对于5.0以下的没有影响,但是由于5.0是默认不支持mixed content的,即不支持同时加载https和http混合模式。

  解决Webview加载不了https请求中的http图片

//允许混合内容 解决部分手机 加载不出https请求里面的http下的图片  

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {  

    settings.setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW);  

}

H5 img标签图片无法显示的解决方案- http://blog.csdn.net/qq_16559905/article/details/54317034
使用Referer Meta标签控制referer,在H5 的 header加入meta

<meta name="referrer" content="never">

1、如果页面中包含了如下 meta 标签,所有从当前页面中发起的请求将不会携带 referer:

<meta name="referrer" content="never">

2、如果页面中包含了如下 meta 标签,则从当前页面中发起的 http请求将只携带 origin 部分(注:根据原文中的语境,我理解这里的 origin 是包含了 schema 和 hostname 的部分 url,不包含 path 等后面的其他 url 部分),而不是完整的 URL :

<meta name="referrer" content="origin">

注意:在使用本文中所述的 meta 标签的时候,浏览器原有的 referer 策略将被打破,比如从 http 协议的页面跳转到 https 的页面的时候,如果设置了适当的值,也会携带 referer。

> Https和http混合在一个网页中

Android 7.0系统webview 显示https页面空白处理- http://blog.csdn.net/li_huorong/article/details/60469607
android webview 访问https页面 SslError 处理- http://blog.csdn.net/aptentity/article/details/71566437
Android端支持HTTP和HTTPS- http://blog.csdn.net/boweijie/article/details/40301911
Android WebView 无法加载Https(或加载错误)- http://m.blog.csdn.net/zhangwenshuan/article/details/55513869
android 用webview加载网页(https和http)- http://blog.csdn.net/qq_30740239/article/details/54141106
Android5.0 WebView中Http和Https混合问题- http://www.zhimengzhe.com/Androidkaifa/78017.html
------------------------------------------------------

android webview常见问题以及性能优化- http://www.jianshu.com/p/9293505c7f71
总结几种加速WebView加载的方法

1、提高渲染的优先级,webView.getSettings().setRenderPriority(RenderPriority.HIGH);

2、使用webView.getSettings().setBlockNetworkImage,把图片加载放在最后来加载渲染。参照示例1.

3、使用硬件加速,该功能在Android 3.0 (API level 11)才加入。

mWebView.stopLoading();//再次打开页面时,若界面没有消亡,会导致进度条不显示并且界面崩溃

在activity的ondestory的时候需要做一下操作

if (mWebView != null) {

            mWebView.stopLoading();//再次打开页面时,若界面没有消亡,会导致进度条不显示并且界面崩溃WebView.stopLoading();

            mWebView.onPause();

            mWebView.clearCache(true)

            mWebView.clearHistory();

            mWebView.removeAllViews();

            mWebView.destroyDrawingCache();

            ViewGroup parent = (ViewGroup) mWebView.getParent();

            if (parent != null) {

                parent.removeView(mWebView);

            }

            mWebView.removeAllViews();

            mWebView.destroy();//这句由于有些在其他线程还没有结束,会导致空指针异常导致没办法使用

            mWebView = null;

        }

H5页面有混合http和https的链接,5.0以上系统不支持混合模式,需要通过配置来开启

//5.0及以上webview不支持http和https混合模式 需要通过配置来开启混合模式

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {

   settings.setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW);

}

Android关于WebView控件stoploading方法的正确使用

Android中使用WebView控件实现链接超时响应,一般都会通过重写WebViewClient类的onPageStarted方法,通过添加timer,达到自定义链接最大时长的目的,但是在timer的run方法体中调用webview的stoploading方法达不到预料中的效果,原因是出在java线程安全机制,java会认为在异步线程中调用修改控件的状态是不安全的。正确的方法应该是使用Hander类。

例如:

// 开始加载页面时

public void onPageStarted(WebView view, String url, Bitmap favicon) {

    super.onPageStarted(view, url, favicon);

    final int progressNum = view.getProgress();

    final Handler handler=new Handler();

    timer = new Timer();

    TimerTask tt = new TimerTask() {

        @Override

        public void run() {

            if (progressNum < 100) {

                System.out.println("链接超时");

                handler.post(runnable);

                timer.cancel();

                timer.purge();

            }

        }

    };

    timer.schedule(tt, 30000, 1);//30最大链接时间为30秒

}

Runnable runnable=new Runnable() {

    public void run() {

        webView.stopLoading();//在这里中断连接

    }

};

  1、展示webview的activity可以另开一个进程,这样就能和我们app的主进程分开了,即使webview产生了oom崩溃等问题也不会影响到主程序,如何实现呢,其实很简单,在androidmanifest.xml的activity标签里加上android:process="packagename.web"就可以了。运行起来就会发现多了一个进程,哈哈。

  2、webview的创建也是有技巧的,最好不要在layout.xml中使用webview,可以通过一个viewgroup容器,使用代码动态往容器里addview(webview),这样可以在onDestory()里销毁掉webview及时清理内存,另外需要注意创建webview需要使用applicationContext而不是activity的context,销毁时不再占有activity对象,这个大家应该都知道了,最后离开的时候需要及时销毁webview,onDestory()中应该先从viewgroup中remove掉webview,再调用webview.removeAllViews();webview.destory();

  3.WebViewClient.onPageFinished()。你永远无法确定当WebView调用这个方法的时候,网页内容是否真的加载完毕了。当前正在加载的网页产生跳转的时候这个方法可能会被多次调用,StackOverflow上有比较具体的解释(How to listen for a Webview finishing loading a URL in Android?-https://stackoverflow.com/questions/3149216/how-to-listen-for-a-webview-finishing-loading-a-url),
但其中列举的解决方法并不完美。所以当你的WebView需要加载各种各样的网页并且需要在页面加载完成时采取一些操作的话,可能WebChromeClient.onProgressChanged()比WebViewClient.onPageFinished()都要靠谱一些。

  4.WebView后台耗电问题。当你的程序调用了WebView加载网页,WebView会自己开启一些线程(?),如果你没有正确地将WebView销毁的话,这些残余的线程(?)会一直在后台运行,由此导致你的应用程序耗电量居高不下。对此我采用的处理方式比较偷懒,简单又粗暴(不建议),即在Activity.onDestroy()中直接调用System.exit(0),使得应用程序完全被移出虚拟机,这样就不会有任何问题了。

  5.切换WebView闪屏问题。如果你需要在同一个ViewGroup中来回切换不同的WebView(包含了不同的网页内容)的话,你就会发现闪屏是不可避免的。这应该是Android硬件加速的Bug,如果关闭硬件加速这种情况会好很多,但无法获得很好的浏览体验,你会感觉网页滑动的时候一卡一卡的,不跟手。

  6.数据积累问题。开启缓存什么的有利于网页的浏览体验,但你会发现即使是清除了必要的内容,比如Cache、Cookie、Form Data、History、Password等等东西,你的应用程序所占用的存储空间还是会越来越大,到最后只好手动到系统设置的应用信息界面里清除数据了

  7.滚动条问题。Android System WebView的横向滚动条真是好粗的有木有...

  8.在某些手机上,Webview有视频时,activity销毁后,视频资源没有被销毁,甚至还能听到在后台播放。即便是像刚才那样各种销毁webview也无济于事,解决办法:在onDestory之前修改url为空地址。是不是很坑?
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: