| |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
-> 移动开发 -> WebView遇到的坑及优化,flutter小程序引擎 -> 正文阅读 |
|
[移动开发]WebView遇到的坑及优化,flutter小程序引擎 |
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 Int
ent(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有这几种类型:
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); } 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来检测到崩溃并做出相应处理。 (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)。 (4) 怎么知道WebView是否已经滚动到页面底端? 解决方案: 方案1,使用原生WebView的api可以获取到: if (mWebView.getContentHeight() * mWebView.getScale() == (mWebView.getHeight() + mWebView.getScrollY())) { //说明已经到底了 } 方案2,继承WebView,重写onScrollChanged方法: 我们在做上拉加载下一页这样的功能时,也需要知道当前页面滚动条所处的状态,如果快到底部,则要发起网络请求数据更新网页。同样继承WebView类,在子类覆盖onScrollChanged方法。 以下代码中mCurrContentHeight用于记录上次触发时的网页高度,用来防止在网页总高度未发生变化而目标区域发生连续滚动时会多次触发TODO,mThreshold是一个阈值,当页面底部距离滚动条底部的高度差<=这个值时会触发TODO里面的代码。 具体如下: @Override protected void onScrollChanged(int newX, int newY, int oldX, int oldY) { super.onScrollChanged(newX, newY, oldX, oldY); if (newY != oldY) { float contentHeight = getContentHeight() * getScale(); // 当前内容高度下从未触发过, 浏览器存在滚动条且滑动到将抵底部位置 if (mCurrContentHeight != contentHeight && newY > 0 && contentHeight <= newY + getHeight() + mThreshold) { // TODO Something… mCurrContentHeight = contentHeight; } } } 相关API介绍:
|
|
移动开发 最新文章 |
Vue3装载axios和element-ui |
android adb cmd |
【xcode】Xcode常用快捷键与技巧 |
Android开发中的线程池使用 |
Java 和 Android 的 Base64 |
Android 测试文字编码格式 |
微信小程序支付 |
安卓权限记录 |
知乎之自动养号 |
【Android Jetpack】DataStore |
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 | -2024/11/24 8:00:54- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |