WebView遇到的坑及优化

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

WebView webview = (WebView) findViewById(R.id.web_view);

assert webview != null;

WebSettings settings = webview.getSettings();

settings.setUseWideViewPort(true);

settings.setLoadWithOverviewMode(true);

settings.setJavaScriptEnabled(true);

webview.setWebChromeClient(new WebChromeClient() {

// android 3.0以下:用的这个方法

public void openFileChooser(ValueCallback valueCallback) {

uploadMessage = valueCallback;

openImageChooserActivity();

}

// android 3.0以上,android4.0以下:用的这个方法

public void openFileChooser(ValueCallback valueCallback, String acceptType) {

uploadMessage = valueCallback;

openImageChooserActivity();

}

//android 4.0 - android 4.3 安卓4.4.4也用的这个方法

public void openFileChooser(ValueCallback valueCallback, String acceptType,

String capture) {

uploadMessage = valueCallback;

openImageChooserActivity();

}

//android4.4 无方法。。。

// Android 5.0及以上用的这个方法

@Override

public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]>

filePathCallback, WebChromeClient.FileChooserParams fileChooserParams) {

uploadMessageAboveL = filePathCallback;

openImageChooserActivity();

return true;

}

});

String targetUrl = “file:///android_asset/up.html”;

webview.loadUrl(targetUrl);

}

private void openImageChooserActivity() {

Intent i = new Intent(Intent.ACTION_GET_CONTENT);

i.addCategory(Intent.CATEGORY_OPENABLE);

i.setType(“image/*”);

startActivityForResult(Intent.createChooser(i, “Image Chooser”),

FILE_CHOOSER_RESULT_CODE);

}

@Override

protected void onActivityResult(int requestCode, int resultCode, Intent data) {

super.onActivityResult(requestCode, resultCode, data);

if (requestCode == FILE_CHOOSER_RESULT_CODE) {

if (null == uploadMessage && null == uploadMessageAboveL) return;

Uri result = data == null || resultCode != RESULT_OK ? null : data.getData();

if (uploadMessageAboveL != null) {

onActivityResultAboveL(requestCode, resultCode, data);

} else if (uploadMessage != null) {

uploadMessage.onReceiveValue(result);

uploadMessage = null;

}

}

}

@TargetApi(Build.VERSION_CODES.LOLLIPOP)

private void onActivityResultAboveL(int requestCode, int resultCode, Intent intent) {

if (requestCode != FILE_CHOOSER_RESULT_CODE || uploadMessageAboveL == null)

return;

Uri[] results = null;

if (resultCode == Activity.RESULT_OK) {

if (intent != null) {

String dataString = intent.getDataString();

ClipData clipData = intent.getClipData();

if (clipData != null) {

results = new Uri[clipData.getItemCount()];

for (int i = 0; i < clipData.getItemCount(); i++) {

ClipData.Item item = clipData.getItemAt(i);

results[i] = item.getUri();

}

}

if (dataString != null)

results = new Uri[]{Uri.parse(dataString)};

}

}

uploadMessageAboveL.onReceiveValue(results);

uploadMessageAboveL = null;

}

重点坑:针对Android4.4,系统把openFileChooser方法去掉了,怎么解决?

详情请见博客

http://blog.csdn.net/xiexie758/article/details/52446937这里就不多说了。

(6) WebView调用手机系统相册来上传图片,处理好第六点说的方法,我们打好release包测试的时候却又发现还是没法选择图片了,怎么解决?

原因分析:

无奈去翻WebChromeClient的源码,发现openFileChooser()是系统API,我们的release包是开启了混淆的,所以在打包的时候混淆了openFileChooser(),这就导致无法回调openFileChooser()了。

解决方案

也很简单,直接不混淆openFileChooser()就好了。

-keepclassmembers class * extends android.webkit.WebChromeClient{

public void openFileChooser(…);

}

(7)怎么在 WebView 中长按保存图片?

1.给 WebView添加监听

mWebview.setOnLongClickListener(new View.OnLongClickListener() {

@Override

public boolean onLongClick(View v) {

}

});

2.获取点击的图片地址

先获取类型,根据相应的类型来处理对应的数据。

//首先判断点击的类型

WebView.HitTestResult result = ((WebView) v).getHitTestResult();

int type = result.getType();

//获取具体信息,图片这里就是图片地址

String imgurl = result.getExtra();

type有这几种类型:

  • WebView.HitTestResult.UNKNOWN_TYPE 未知类型

  • WebView.HitTestResult.PHONE_TYPE 电话类型

  • WebView.HitTestResult.EMAIL_TYPE 电子邮件类型

  • WebView.HitTestResult.GEO_TYPE 地图类型

  • WebView.HitTestResult.SRC_ANCHOR_TYPE 超链接类型

  • WebView.HitTestResult.SRC_IMAGE_ANCHOR_TYPE 带有链接的图片类型

  • WebView.HitTestResult.IMAGE_TYPE 单纯的图片类型

  • WebView.HitTestResult.EDIT_TEXT_TYPE 选中的文字类型

3.操作图片

你可以弹出保存图片,或者点击之后跳转到显示图片的页面。

最后整理一下代码:

mWebView.setOnLongClickListener(new View.OnLongClickListener() {

@Override

public boolean onLongClick(View v) {

WebView.HitTestResult result = ((WebView)v).getHitTestResult();

if (null == result)

return false;

int type = result.getType();

if (type == WebView.HitTestResult.UNKNOWN_TYPE)

return false;

// 这里可以拦截很多类型,我们只处理图片类型就可以了

switch (type) {

case WebView.HitTestResult.PHONE_TYPE: // 处理拨号

break;

case WebView.HitTestResult.EMAIL_TYPE: // 处理Email

break;

case WebView.HitTestResult.GEO_TYPE: // 地图类型

break;

case WebView.HitTestResult.SRC_ANCHOR_TYPE: // 超链接

break;

case WebView.HitTestResult.SRC_IMAGE_ANCHOR_TYPE:

break;

case WebView.HitTestResult.IMAGE_TYPE: // 处理长按图片的菜单项

// 获取图片的路径

String saveImgUrl = result.getExtra();

// 跳转到图片详情页,显示图片

Intent i = new Intent(MainActivity.this, ImageActivity.class);

i.putExtra(“imgUrl”, saveImgUrl);

startActivity(i);

break;

default:

break;

}

}

});

(8) WebView 开启硬件加速导致的问题?

WebView有很多问题,比如:不能打开pdf,播放视屏也只能打开硬件加速才能支持,在某些机型上会崩溃。

下面看一下硬件加速, 硬件加速分为四个级别:

Application级别

<application android:hardwareAccelerated=“true”…>

Activity级别

<activity android:hardwareAccelerated=“true”…>

window级别(目前为止,Android还不支持在Window级别关闭硬件加速。)

getWindow().setFlags(

WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED,

WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED);

View级别

view.setLayerType(View.LAYER_TYPE_HARDWARE, null);

WebView开启硬件加速导致屏幕花屏问题的解决:

原因分析:

4.0以上的系统我们开启硬件加速后,WebView渲染页面更加快速,拖动也更加顺滑。但有个副作用就是,当WebView视图被整体遮住一块,然后突然恢复时(比如使用SlideMenu将WebView从侧边滑出来时),这个过渡期会出现白块同时界面闪烁。

解决方案:

在过渡期前将WebView的硬件加速临时关闭,过渡期后再开启,代码如下:

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

webview.setLayerType(View.LAYER_TYPE_SOFTWARE, null);

}

Android 4.0+ 版本中的EditText字符重叠问题:

做的软件,在一些机器上,打字的时候,EditText中的内容会出现重叠,而大部分机器没有,所以感觉不是代码的问题,一直没有头绪。

出现原因:JellyBean的硬件加速bug,在此我们关掉硬件加速即可。

解决方案:在EditText中加入一句:

android:layerType=”software”

图片无法显示:

做的程序里有的时候会需要加载大图,但是硬件加速中 OpenGL对于内存是有限制的。如果遇到了这个限制,LogCat只会报一个Warning: Bitmap too large to be uploaded into a texture (587x7696, max=2048x2048)

这时我们就需要把硬件加速关闭了。

但开始我是这样处理的,我关闭了整个应用的硬件加速:

<application

android:allowBackup=“true”

android:icon=“@drawable/ic_launcher”

android:hardwareAccelerated=“false”

android:label=“@string/app_name”

android:theme=“@style/AppTheme” >

随后我就发现,虽然图片可以显示了,但是ListView和WebView等控件显得特别的卡,这说明硬件加速对于程序的性能提升是很明显的。所以我就改为对于Activity的关闭。

<activity

android:name=“icyfox.webviewimagezoomertest.MainActivity”

android:label=“@string/app_name”

android:hardwareAccelerated=“false”

(9) ViewPager里非首屏WebView点击事件不响应是什么原因?

如果你的多个WebView是放在ViewPager里一个个加载出来的,那么就会遇到这样的问题。ViewPager首屏WebView的创建是在前台,点击时没有问题;而其他非首屏的WebView是在后台创建,滑动到它后点击页面会出现如下错误日志:

20955-20968/xx.xxx.xxx E/webcoreglue﹕ Should not happen: no rect-based-test nodes found

解决方案:

这个问题的办法是继承WebView类,在子类覆盖onTouchEvent方法,填入如下代码:

@Override

public boolean onTouchEvent(MotionEvent ev) {

if (ev.getAction() == MotionEvent.ACTION_DOWN) {

onScrollChanged(getScrollX(), getScrollY(), getScrollX(), getScrollY());

}

return super.onTouchEvent(ev);

}

##2. 安卓8.0关于WebView的新特性


WebView新增了一些非常有用的API,可以使用和chrome浏览器类似的API来实现对恶意网站的检测来保护web浏览的安全性,为此需要在manifest中添加如下meta-data标签:

<meta-data

android:name=“android.webkit.WebView.EnableSafeBrowing”

android:value=“true” />

WebView还增加了关于多进程的API,可以使用多进程来增强安全性和健壮性,如果render进程崩溃了,你还可以使用Termination Handler API来检测到崩溃并做出相应处理。

##3. 关于WebView的一点小优化


(1)给WebView加一个加载进度条

用Webview加载一个网页时,如果加载时间长,界面会一直空白,体验不太好,所以加个进度条更好看一下,主流APP也都有进度条效果,大概思路我来说一下:

首先自定义一个HorizontalProgressView继承View,然后自定义一个MyWebView继承WebView,然后初始化的时候通过addView方法把前面自定义HorizontalProgressView,然后在MyWebView里面写一个内部类继承WebChromeClient,大致代码如下:

private class MyWebCromeClient extends WebChromeClient {

@Override

public void onProgressChanged(WebView view, int newProgress) {

if (newProgress == 100) {

//加载完毕进度条消失

progressView.setVisibility(View.GONE);

} else {

//更新进度

progressView.setProgress(newProgress);

}

super.onProgressChanged(view, newProgress);

}

}

主要是通过MyWebCromeClient 的onProgressChanged方法里面的进度值调用

progressView.setProgress()方法去更新进度条,当加载100%的时候让进度条消失。

具体实现你们自己去处理吧。

(2)加快HTML网页加载完成的速度,等页面finish再加载图片

默认情况html代码下载到WebView后,webkit开始解析网页各个节点,发现有外部样式文件或者外部脚本文件时,会异步发起网络请求下载文件,但如果在这之前也有解析到image节点,那势必也会发起网络请求下载相应的图片。

在网络情况较差的情况下,过多的网络请求就会造成带宽紧张,影响到css或js文件加载完成的时间,造成页面空白loading过久。解决的方法就是告诉WebView先不要自动加载图片,等页面finish后再发起图片加载。

解决办法:

在WebView初始化时设置如下代码:

public void int () {

if(Build.VERSION.SDK_INT >= 19) {

webView.getSettings().setLoadsImagesAutomatically(true);

} else {

webView.getSettings().setLoadsImagesAutomatically(false);

}

}

同时在WebView的WebViewClient实例中的onPageFinished()方法添加如下代码:

@Override

public void onPageFinished(WebView view, String url) {

if(!webView.getSettings().getLoadsImagesAutomatically()) {

webView.getSettings().setLoadsImagesAutomatically(true);

}

}

(3)自定义WebView页面加载出错界面

当WebView加载页面出错时(一般为404 NOT FOUND),安卓WebView会默认显示一个卖萌的出错界面。但我们怎么能让用户发现原来我使用的是网页应用呢,我们期望的是用户在网页上得到是如原生般应用的体验,那就先要从干掉这个默认出错页面开始。

当WebView加载出错时,我们会在WebViewClient实例中的onReceivedError()方法接收到错误,我们就在这里做些手脚:

@Override

public void onReceivedError (WebView view, int errorCode, String description, String failingUrl) {

super.onReceivedError(view, errorCode, description, failingUrl);

loadDataWithBaseURL(null, “”, “text/html”, “utf-8”, null);

mErrorFrame.setVisibility(View.VISIBLE);

}

从上面可以看出,我们先使用loadDataWithBaseURL清除掉默认错误页内容,再让我们自定义的View得到显示(mErrorFrame为蒙在WebView之上的一个LinearLayout布局,默认为View.GONE)。

最后

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。

因此收集整理了一份《2024年Web前端开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点!不论你是刚入门Android开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门!

如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
", null);

mErrorFrame.setVisibility(View.VISIBLE);

}

从上面可以看出,我们先使用loadDataWithBaseURL清除掉默认错误页内容,再让我们自定义的View得到显示(mErrorFrame为蒙在WebView之上的一个LinearLayout布局,默认为View.GONE)。

最后

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。

因此收集整理了一份《2024年Web前端开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

[外链图片转存中…(img-W9a38BSK-1715025797952)]

[外链图片转存中…(img-qoYlmyoA-1715025797952)]

[外链图片转存中…(img-E1eoAsQf-1715025797952)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点!不论你是刚入门Android开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门!

如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

  • 15
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值