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开发过程中踩过的坑,相应解决方案纯粹是经验参考,因为使用环境以及能力的局限,如果文章出现错误,欢迎老司机留言指出。

目录
相关文章
|
1月前
|
开发框架 前端开发 Android开发
安卓与iOS开发中的跨平台策略
在移动应用开发的战场上,安卓和iOS两大阵营各据一方。随着技术的演进,跨平台开发框架成为开发者的新宠,旨在实现一次编码、多平台部署的梦想。本文将探讨跨平台开发的优势与挑战,并分享实用的开发技巧,帮助开发者在安卓和iOS的世界中游刃有余。
|
1月前
|
缓存 前端开发 Android开发
安卓开发中的自定义视图:从零到英雄
【10月更文挑战第42天】 在安卓的世界里,自定义视图是一块画布,让开发者能够绘制出独一无二的界面体验。本文将带你走进自定义视图的大门,通过深入浅出的方式,让你从零基础到能够独立设计并实现复杂的自定义组件。我们将探索自定义视图的核心概念、实现步骤,以及如何优化你的视图以提高性能和兼容性。准备好了吗?让我们开始这段创造性的旅程吧!
27 1
|
1月前
|
搜索推荐 Android开发 开发者
探索安卓开发中的自定义视图:打造个性化UI组件
【10月更文挑战第39天】在安卓开发的世界中,自定义视图是实现独特界面设计的关键。本文将引导你理解自定义视图的概念、创建流程,以及如何通过它们增强应用的用户体验。我们将从基础出发,逐步深入,最终让你能够自信地设计和实现专属的UI组件。
|
20天前
|
搜索推荐 前端开发 API
探索安卓开发中的自定义视图:打造个性化用户界面
在安卓应用开发的广阔天地中,自定义视图是一块神奇的画布,让开发者能够突破标准控件的限制,绘制出独一无二的用户界面。本文将带你走进自定义视图的世界,从基础概念到实战技巧,逐步揭示如何在安卓平台上创建和运用自定义视图来提升用户体验。无论你是初学者还是有一定经验的开发者,这篇文章都将为你打开新的视野,让你的应用在众多同质化产品中脱颖而出。
40 19
|
1月前
|
IDE Java 开发工具
移动应用与系统:探索Android开发之旅
在这篇文章中,我们将深入探讨Android开发的各个方面,从基础知识到高级技术。我们将通过代码示例和案例分析,帮助读者更好地理解和掌握Android开发。无论你是初学者还是有经验的开发者,这篇文章都将为你提供有价值的信息和技巧。让我们一起开启Android开发的旅程吧!
|
20天前
|
JSON Java API
探索安卓开发:打造你的首个天气应用
在这篇技术指南中,我们将一起潜入安卓开发的海洋,学习如何从零开始构建一个简单的天气应用。通过这个实践项目,你将掌握安卓开发的核心概念、界面设计、网络编程以及数据解析等技能。无论你是初学者还是有一定基础的开发者,这篇文章都将为你提供一个清晰的路线图和实用的代码示例,帮助你在安卓开发的道路上迈出坚实的一步。让我们一起开始这段旅程,打造属于你自己的第一个安卓应用吧!
45 14
|
23天前
|
Java Linux 数据库
探索安卓开发:打造你的第一款应用
在数字时代的浪潮中,每个人都有机会成为创意的实现者。本文将带你走进安卓开发的奇妙世界,通过浅显易懂的语言和实际代码示例,引导你从零开始构建自己的第一款安卓应用。无论你是编程新手还是希望拓展技术的开发者,这篇文章都将为你打开一扇门,让你的创意和技术一起飞扬。
|
21天前
|
XML 存储 Java
探索安卓开发之旅:从新手到专家
在数字时代,掌握安卓应用开发技能是进入IT行业的关键。本文将引导读者从零基础开始,逐步深入安卓开发的世界,通过实际案例和代码示例,展示如何构建自己的第一个安卓应用。我们将探讨基本概念、开发工具设置、用户界面设计、数据处理以及发布应用的全过程。无论你是编程新手还是有一定基础的开发者,这篇文章都将为你提供宝贵的知识和技能,帮助你在安卓开发的道路上迈出坚实的步伐。
31 5
|
20天前
|
开发框架 Android开发 iOS开发
安卓与iOS开发中的跨平台策略:一次编码,多平台部署
在移动应用开发的广阔天地中,安卓和iOS两大阵营各占一方。随着技术的发展,跨平台开发框架应运而生,它们承诺着“一次编码,到处运行”的便捷。本文将深入探讨跨平台开发的现状、挑战以及未来趋势,同时通过代码示例揭示跨平台工具的实际运用。
|
21天前
|
XML 搜索推荐 前端开发
安卓开发中的自定义视图:打造个性化UI组件
在安卓应用开发中,自定义视图是一种强大的工具,它允许开发者创造独一无二的用户界面元素,从而提升应用的外观和用户体验。本文将通过一个简单的自定义视图示例,引导你了解如何在安卓项目中实现自定义组件,并探讨其背后的技术原理。我们将从基础的View类讲起,逐步深入到绘图、事件处理以及性能优化等方面。无论你是初学者还是有经验的开发者,这篇文章都将为你提供有价值的见解和技巧。