Android使用WebView开发常见的坑

简介:  原文链接:http://mp.weixin.qq.com/s?__biz=MzAwODE1NTI2MQ==&tempkey=uP3a%2BOgIN7vPbLfJp3BTCl2KabYi1%2FfBUQEkkQD7ixoNgGn4JfrR81AwdwsBof%2FhsiCe4%2B9o0KJQ6...

 原文链接:http://mp.weixin.qq.com/s?__biz=MzAwODE1NTI2MQ==&tempkey=uP3a%2BOgIN7vPbLfJp3BTCl2KabYi1%2FfBUQEkkQD7ixoNgGn4JfrR81AwdwsBof%2FhsiCe4%2B9o0KJQ6lv%2B32pSyH46EQAIwJ5i%2BxxED%2BjrIpwHyFCFbDUibPnNlrZDxQAc4JV34qtCRBPLX6fF3qjtjQ%3D%3D&chksm=1b7278102c05f1068706fba93854af9f4ab7b93e610b5ffee5917dcf378489958605f784c2cf#rd

Android WebView开发常见的坑

 

现在的App基本上都会使用Native+H5的方式来开发的,例如网易新闻详情页面,微信公号详情页面都会使用WebView开发。这样可以很容易实现图文排版的需求,而且混合开发的好处也是显而易见的。

AC在开发项目的时候也经常使用WebView这个控件,这个控件使用很方便,但却也有诸多问题。以下是AC在开发过程中踩过的坑,希望对使用这个控件的小伙伴们有用。

1、WebView无法显示html中的alert和confirm对话框

WebView要显示html中的alert和confirm对话框,需要实现WebViewChromClient接口。WebView只是一个承载体,各种内容的渲染需要使用WebviewChromClient去实现,所以set一个默认的基类WebChromeClient就行

mWebView.setWebChromeClient(new WebChromeClient());

用于弹起alert等,如果要定制alert,confirm对话框就必需重写onAlert和onConfirm方法

2、WebView中实现的JS方法无法调用

在实现WebView与JS交互的过程中,如果遇到点击后JS方法无响应,应该注意以下问题:

(1)WebView.addJavascriptInterface(new AndroidClick(), "app");这个方法的别名android是否与JS中的对象名称一致如

<div style="text-align:center;"><a onclick="window.app.onclick('www.115.com')" >内容已自动优化阅读,点击查看原文</a></div>

(2)如果是H5通过alert方法来提示对话框的信息的时候,WebView需要实现注册这个回调函数

 

mWebView.setWebChromeClient(new CustomWebChromeClient());

并实现以下alert回调方法,并可以实现自定义的对话框样式。

 

@Override
public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
//return super.onJsAlert(view, url, message, result);
   showConfirmDialog(view.getContext(), message, result, false);
   return true;
}

类似的还有onJsConfirm方法等。

(3)如果发布的APP有进行混淆,那么AndroidClick这个JS 与 JAVA交互的类需要proguard.cfg文件忽略这个类的混淆,否则混淆后JS将执行不了。

-keepclassmembers class net.angrycode.js2java.AndroidClick{ *; }

(4)JS调用Native方法时,如果前端执行一些比较耗时的操作,前端代码就有可能会跑在线程里,这时候如果JS方法调用Native方法做一些逻辑操作,调用就会有问题,虽然不会Crash但是会报错。参考解决方法是(mJSInterface是通过addJavaInterface注入到WebView中的对象)

 

/**
* 提交创建申请单数据
*/
mJSInterface.setOnPutApplyListener(json -> {
   mWebView.post(() -> {
       //确保是在主线程中访问Native相关控件
   });
});

3、快速打开和关闭WebView页面发生了控件空指针异常问题

这个问题可能有很多原因,但WebView加载过程中如果关闭了页面控件被回收而加载线程还在继续跑,那么数据返回时页面就有可能发生空指针异常。这个时候可以在WebViewClient以及WebViewChrome接口中的onPageStart以及onPageFinish,onProgressChange这几个回调方法中判断当前页面是否存在,若不存在则直接返回。

 

@Override
public void onPageFinished(WebView view, String url) {
if (getActivity() == null || getActivity().isFinishing()) {
return;
   }
super.onPageFinished(view, url);
   //...
}

4、WebView与JS交互引起的安全问题

4.2以下系统这里推荐一个开源项目https://github.com/pedant/safe-java-js-webview-bridge

当然WebView的安全不止这个,可以自行百度或者Google脑部相关姿势。AC也会在之后的文章中专门整理这个问题。

同时此问题在官方4.2(API Level 17)以上手机已经得到修复,使用@JavascriptInterface 注解声明addJavascriptInterface注入的方法。即只有使用@JavascriptInterface的方法才会被注入到WebView中。

5、WebView长按弹出ActionMode菜单样式问题



三星手机WebView弹出的菜单样式有可能会出现此问题,解决方法可以继承WebView重写startActionMode()方法,然后修改menu的菜单样式。

 

@Override
public ActionMode startActionMode(ActionMode.Callback callback) {
return super.startActionMode(new CustomCallback(getContext(), callback));
}

public static class CustomCallback implements ActionMode.Callback {
private ActionMode.Callback callback;
   private Context context;

   public CustomCallback(Context context, ActionMode.Callback callback) {
this.callback = callback;
       this.context = context;
   }

@Override
   public boolean onCreateActionMode(ActionMode mode, Menu menu) {
return callback.onCreateActionMode(mode, menu);
   }

@Override
   public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
int size = menu.size();
       for (int i = 0; i < size; i++) {
MenuItem menuItem = menu.getItem(i);
           final Drawable moreMenuDrawable = menuItem.getIcon();

           if (moreMenuDrawable != null) {

menuItem.setIcon(DrawableUtil.getThemeDrawable(context, moreMenuDrawable));

           }
}
return true;
   }

@Override
   public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
return callback.onActionItemClicked(mode, item);
   }

@Override
   public void onDestroyActionMode(ActionMode mode) {
callback.onDestroyActionMode(mode);
       context = null;
   }
}

当然如果不需要长按事件,可以注册WebView的长按事件

mWebView.setOnLongClickListener(v -> {
return true;
});

6、硬件加速问题

一般情况下,使用WebView开发都会使用硬件加速来提高WebView的渲染速度。可以在AndroidManifest.xml文件中设置

android:hardwareAccelerated="true"

也可以在页面中使用

view.setLayerType(View.LAYER_TYPE_HARDWARE, null);

但是简单的使用以上两种方法,开启硬件加速以及不开启硬件加速在一些手机上都会出现这样或者那样的问题,例如,如果一直开启了硬件加速,某些手机有可能会出现屏幕花屏的问题;还有WebView在不同厂商的手机中依然可能会出现Crash问题。而Crash的问题一般是报了WebView底层的错误。可以参考以下处理方式:

在onPageStart中开启硬件加速,在onPageFinish中关闭硬件加速。

        @Override
       public void onPageStarted(WebView view, String url, Bitmap favicon) {
if (getActivity() == null || getActivity().isFinishing()) {
return;
           }
view.setLayerType(View.LAYER_TYPE_HARDWARE, null);
           super.onPageStarted(view, url, favicon);
       }
@Override
       public void onPageFinished(WebView view, String url) {
if (getActivity() == null || getActivity().isFinishing()) {
return;
           }
view.setLayerType(View.LAYER_TYPE_NONE, null);
           super.onPageFinished(view, url);
       }

7、使用独立进程跑WebView

有一定使用WebView经验的老司机可能都把项目中的WebView模块抽取出来,并跑在独立的进程中去。例如在manifest文件中使用属性process指定独立的进程。

<!-- Web 页面 -->
<activity
   android:name=".UI.CommonUI.Activity.WebBrowserActivity"
   android:configChanges="orientation|screenSize|keyboardHidden"
   android:hardwareAccelerated="true"
   android:label=""
   android:process=":web"
   android:screenOrientation="portrait" />

这样做的是因为WebView在以前的版本的底层实现中会发生内存泄漏,导致页面关闭但是依然没有释放内存,而在独立进程中的WebView模块就可以很好解决此问题,在关闭WebView的时候就关闭进程,这样就可以释放相关的内存了。

但是使用多进程架构,进程间数据共享就是一个问题了。例如进程A设置了cookie,同样我也要在进程B共享这个cookie。目前AC认为可行的解决方案是使用ContentProvider来共享数据。此问题AC没有写相应的Demo,希望有老司机可以带路。

8、WebView生命周期回调

WebView也有生命周期回调方法,这些方法需要在Activity或Fragment相应的生命方法中回调。主要是onResume(),onPasuse()和onDestory()(或者onDestoryView())这几个方法的回调实现。

@Override
public void onResume() {
if (mWebView != null) {
mWebView.resumeTimers();
       mWebView.onResume();
   }
super.onResume();
}

@Override
public void onPause() {
if (mWebView != null) {
mWebView.pauseTimers();
       mWebView.onPause();
   }
super.onPause();
}
@Override
public void onDestroyView() {
if (mWebView != null) {
mWebView.stopLoading();
       ((ViewGroup) mWebView.getParent()).removeView(mWebView);
       mWebView.removeAllViews();
       mWebView.setWebChromeClient(null);
       mWebView.setWebViewClient(null);
       unregisterForContextMenu(mWebView);
       mWebView.destroy();
   }
super.onDestroyView();
}

这几个方法的回调实现有利无弊,可以很好地避免翻车。例如WebView中播放声音在页面关闭之后还声音的问题,WebView页面跳转其他页面后返回显示空白不刷新的问题等等。

以上便是AngryCode在使用WebView开发过程中踩过的坑,相应解决方案纯粹是经验参考,因为使用环境以及能力的局限,如果文章出现错误,欢迎老司机留言指出。

目录
相关文章
|
5天前
|
搜索推荐 Android开发 开发者
探索安卓开发中的自定义视图:打造个性化UI组件
【10月更文挑战第39天】在安卓开发的世界中,自定义视图是实现独特界面设计的关键。本文将引导你理解自定义视图的概念、创建流程,以及如何通过它们增强应用的用户体验。我们将从基础出发,逐步深入,最终让你能够自信地设计和实现专属的UI组件。
|
7天前
|
Android开发 Swift iOS开发
探索安卓与iOS开发的差异和挑战
【10月更文挑战第37天】在移动应用开发的广阔舞台上,安卓和iOS这两大操作系统扮演着主角。它们各自拥有独特的特性、优势以及面临的开发挑战。本文将深入探讨这两个平台在开发过程中的主要差异,从编程语言到用户界面设计,再到市场分布的不同影响,旨在为开发者提供一个全面的视角,帮助他们更好地理解并应对在不同平台上进行应用开发时可能遇到的难题和机遇。
|
9天前
|
XML 存储 Java
探索安卓开发之旅:从新手到专家
【10月更文挑战第35天】在数字化时代,安卓应用的开发成为了一个热门话题。本文旨在通过浅显易懂的语言,带领初学者了解安卓开发的基础知识,同时为有一定经验的开发者提供进阶技巧。我们将一起探讨如何从零开始构建第一个安卓应用,并逐步深入到性能优化和高级功能的实现。无论你是编程新手还是希望提升技能的开发者,这篇文章都将为你提供有价值的指导和灵感。
|
7天前
|
存储 API 开发工具
探索安卓开发:从基础到进阶
【10月更文挑战第37天】在这篇文章中,我们将一起探索安卓开发的奥秘。无论你是初学者还是有经验的开发者,这篇文章都将为你提供有价值的信息和建议。我们将从安卓开发的基础开始,逐步深入到更复杂的主题,如自定义组件、性能优化等。最后,我们将通过一个代码示例来展示如何实现一个简单的安卓应用。让我们一起开始吧!
|
8天前
|
存储 XML JSON
探索安卓开发:从新手到专家的旅程
【10月更文挑战第36天】在这篇文章中,我们将一起踏上一段激动人心的旅程,从零基础开始,逐步深入安卓开发的奥秘。无论你是编程新手,还是希望扩展技能的老手,这里都有适合你的知识宝藏等待发掘。通过实际的代码示例和深入浅出的解释,我们将解锁安卓开发的关键技能,让你能够构建自己的应用程序,甚至贡献于开源社区。准备好了吗?让我们开始吧!
21 2
|
9天前
|
Android开发
布谷语音软件开发:android端语音软件搭建开发教程
语音软件搭建android端语音软件开发教程!
|
17天前
|
编解码 Java Android开发
通义灵码:在安卓开发中提升工作效率的真实应用案例
本文介绍了通义灵码在安卓开发中的应用。作为一名97年的聋人开发者,我在2024年Google Gemma竞赛中获得了冠军,拿下了很多项目竞赛奖励,通义灵码成为我的得力助手。文章详细展示了如何安装通义灵码插件,并通过多个实例说明其在适配国际语言、多种分辨率、业务逻辑开发和编程语言转换等方面的应用,显著提高了开发效率和准确性。
|
16天前
|
Android开发 开发者 UED
安卓开发中自定义View的实现与性能优化
【10月更文挑战第28天】在安卓开发领域,自定义View是提升应用界面独特性和用户体验的重要手段。本文将深入探讨如何高效地创建和管理自定义View,以及如何通过代码和性能调优来确保流畅的交互体验。我们将一起学习自定义View的生命周期、绘图基础和事件处理,进而探索内存和布局优化技巧,最终实现既美观又高效的安卓界面。
28 5
|
14天前
|
JSON Java Android开发
探索安卓开发之旅:打造你的第一个天气应用
【10月更文挑战第30天】在这个数字时代,掌握移动应用开发技能无疑是进入IT行业的敲门砖。本文将引导你开启安卓开发的奇妙之旅,通过构建一个简易的天气应用来实践你的编程技能。无论你是初学者还是有一定经验的开发者,这篇文章都将成为你宝贵的学习资源。我们将一步步地深入到安卓开发的世界中,从搭建开发环境到实现核心功能,每个环节都充满了发现和创造的乐趣。让我们开始吧,一起在代码的海洋中航行!
|
15天前
|
缓存 数据库 Android开发
安卓开发中的性能优化技巧
【10月更文挑战第29天】在移动应用的海洋中,性能是船只能否破浪前行的关键。本文将深入探讨安卓开发中的性能优化策略,从代码层面到系统层面,揭示如何让应用运行得更快、更流畅。我们将以实际案例和最佳实践为灯塔,引领开发者避开性能瓶颈的暗礁。
34 3