浅谈Android WebView

一、基本情况介绍

     


     Android WebView在Android平台上是一个特殊的View, 基于webkit引擎、展现web页面的控件。

     WebView内部实现是采用渲染引擎来展示view的内容,提供网页前进后退,网页放大,缩小,搜索。


二、常用接口介绍

WebView有几个比较重要的辅助类。

WebSetting:用来配置WebView的一些基本参数

WebViewClient:主要帮助WebView处理各种通知、请求事件的

WebChromeClient:主要辅助WebView处理Javascript的对话框、网站图标、网站title、加载进度等


1.通过WebSetting,设置一些基本参数


//声明WebSettings子类
WebSettings webSettings = webView.getSettings();

//如果访问的页面中要与Javascript交互,则webview必须设置支持Javascript
webSettings.setJavaScriptEnabled(true);  

// 定位(location)
settings.setGeolocationEnabled(true);

// 默认文本编码,默认值 "UTF-8" 
settings.setDefaultTextEncodingName("UTF-8"); 
settings.setDefaultFontSize(16); // 默认文字尺寸,默认值16,取值范围1-72 
settings.setDefaultFixedFontSize(16); // 默认等宽字体尺寸,默认值16 
settings.setMinimumFontSize(8); // 最小文字尺寸,默认值 8 
settings.setMinimumLogicalFontSize(8); // 最小文字逻辑尺寸,默认值 8 
settings.setTextZoom(100); // 文字缩放百分比,默认值 100 

// 字体 
settings.setStandardFontFamily("sans-serif"); // 标准字体,默认值 "sans-serif" 
settings.setSerifFontFamily("serif"); // 衬线字体,默认值 "serif" 
settings.setSansSerifFontFamily("sans-serif"); // 无衬线字体,默认值 "sans-serif" 
settings.setFixedFontFamily("monospace"); // 等宽字体,默认值 "monospace" 
settings.setCursiveFontFamily("cursive"); // 手写体(草书),默认值 "cursive" 
settings.setFantasyFontFamily("fantasy"); // 幻想体,默认值 "fantasy"

//设置自适应屏幕,两者合用
webSettings.setUseWideViewPort(true); //将图片调整到适合webview的大小 
webSettings.setLoadWithOverviewMode(true); // 缩放至屏幕的大小

//缩放操作
webSettings.setSupportZoom(true); //支持缩放,默认为true。是下面那个的前提。
webSettings.setBuiltInZoomControls(true); //设置内置的缩放控件。若为false,则该WebView不可缩放
webSettings.setDisplayZoomControls(false); //隐藏原生的缩放控件

//其他细节操作
webSettings.setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK); //关闭webview中缓存 
webSettings.setAllowFileAccess(true); //设置可以访问文件 
webSettings.setJavaScriptCanOpenWindowsAutomatically(true); //支持通过JS打开新窗口 
webSettings.setLoadsImagesAutomatically(true); //支持自动加载图片

2.WebViewClient回调接口

//在网页开始加载时回调 。
 public void onPageStarted(WebView view, String url, Bitmap favicon) {
 }

 //在网页结束加载时回调。
 public void onPageFinished(WebView view, String url) {
 }

 //当加载的网页需要重定向,或者超链接在加载前都会回调此函数,可以在这里拦截一些url的加载。
 //return true 就会拦截掉;return false 就是交由webview处理,url会继续加载。
 public boolean shouldOverrideUrlLoading(WebView view, String url) { 
    return false; 
 } 

 //WebView即将加载指定的url资源时回调。 
 public void onLoadResource(WebView view, String url) { 
 } 

 //访问指定的url发生错误时回调,我们可以在这里做错误处理,比如无网络的错误页面。 
 public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) { 
 } 

 //通知可以更新访问记录,意味着当前的访问url已经生效并在内核当中生成了访问记录。 
 public void doUpdateVisitedHistory(WebView view, String url, boolean isReload) { 
 } 

 //当网页加载资源过程中发现SSL错误时回调。 
 public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
 }

3.WebChromeClient回调接口

//当前WebView的加载url的进度变化时回调。
 public void onProgressChanged(WebView view, int newProgress) {
 }

 //获取到当前url页面的title时回调。
 public void onReceivedTitle(WebView view, String title) {
 }

 //获取到当前url页面的icon标识时回调
 public void onReceivedIcon(WebView view, Bitmap icon) {
 }

 //需要显示JavaScript警告的dialog时回调。
 public boolean onJsAlert(WebView view, String url, String message,
        JsResult result) {
    return false;
 }

 //需要展示一个确认的对话框时回调。
 public boolean onJsConfirm(WebView view, String url, String message,
    JsResult result) {
    return false;
 }

 //需要展示一个含输入框的对话框时回调。
 public boolean onJsPrompt(WebView view, String url, String message,
           String defaultValue, JsPromptResult result) {
      return false;
 }

 //需要显示文件的选择器时回调(android 5.0及后)
 public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> filePathCallback,
           FileChooserParams fileChooserParams) {
   return false;
 }

 //需要显示文件的选择器时回调(android 5.0前)
 public void openFileChooser(ValueCallback<Uri> uploadFile, String acceptType, String capture) {
    uploadFile.onReceiveValue(null);
 }

4.WebView的常用接口

//加载网页
public void loadUrl(String url); // 加载URL指定的网页
public void loadUrl(String url, Map<String, String> additionalHttpHeaders); // 携带http headers加载URL指定的网页 
public void reload(); // 重新加载当前网页 

//获取页面信息相关
public String getUrl();       // 获取当前页面的URL 
public String getOriginalUrl(); // 获取当前页面的原始URL 
public String getTitle();     // 获取当前页面的标题
public Bitmap getFavicon();  // 获取当前页面的favicon 
public int getProgress();    // 获取当前页面的加载进度 

//前进后退 
public boolean canGoBack();  // 是否可后退
public boolean canGoForward(); // 是否可前进  
public void goBack();      // 后退一页
public void goForward();   // 前进一页  
public void clearHistory();// 清除当前webview访问的历史记录
public WebBackForwardList copyBackForwardList(); // 复制一份BackForwardList 

//Javascript
public void addJavascriptInterface(Object object, String name); // 注入Javascript对象   
public void removeJavascriptInterface(String name);   // 移除已注入的Javascript对象,下次加载或刷新页面时生效
// 对传入的JS表达式求值,通过resultCallback返回结果 
// 此函数添加于API19,必须在UI线程中调用,回调也将在UI线程 
public void evaluateJavascript(String script, ValueCallback<String> resultCallback)


5.简单使用

webview.getSettings().setJavaScriptEnabled(true);

 webview.setWebChromeClient(new WebChromeClient() {
   public void onProgressChanged(WebView view, int progress) {
     // Activities and WebViews measure progress with different scales.
     // The progress meter will automatically disappear when we reach 100%
   }
 });
 webview.setWebViewClient(new WebViewClient() {
   public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
     Toast.makeText(activity, "Oh no! " + description, Toast.LENGTH_SHORT).show();
   }
 });

 webview.loadUrl("https://developer.android.com/");


三、Hybrid的使用

     Hybrid混合开发前两年非常流行,因其无需升级客户端版本就可实现快速更新功能、跨平台等特性,使得在一些电商平台,比如说很多电商平台,淘宝、京东、聚划算,还有一些应用的活动页面等。

      WebView比较灵活,不需要升级客户端,只需要修改网页代码即可。因此项目中经常变化的页面可以用WebView这种方式去加载网页。

      Hybrid开发模式有着开发快、更新快、跨平台等诸多有点,但是由于需要依赖于WebView来加载,就会存在一些性能和体验的问题,相较于原生的View,这一块都要比原生的差很多。后来推出的React Native、Weex等基于web开发,但是渲染为Native的方式,目前更加受到追捧。

  

    美团页面:

       

       

   饿了么:                                                                  

          

京东: 

       

     

1.基本使用方法

   (1)设置WebView属性
       
  webSettings.setJavaScriptEnabled(true); 

     必须设置为true,使webview支持JS。

   (2)定义好桥接模块的接口

      Android与JS可以通过WebView互相调用其方法。

   

2.JS去调用Android的代码:

   首先需要声明方法,然后加上@JavascriptInterface

public class AndroidJsBridgeJavaScriptInterface{ 

   // 定义JS调用的方法,并加入@JavascriptInterface注解
   @JavascriptInterface
   public void testMethod(String msg) {
      Toast.makeText(AppContextUtil.getAppContext(),"JS调用了Android的testMethod方法", Toast.LENGTH_SHORT).show();
   } 

}

向webview中注入桥接对象

//AndroidJsBridgeJavaScriptInterface类对象映射到js的AndroidJsInterface对象
webView.addJavascriptInterface(new AndroidJsBridgeJavaScriptInterface(), "AndroidJsInterface");

使用chrome://inspect/#devices(墙)可以直接查看到注入的对象



在Js中调用Android模块注入的方法

首先编写JS:TestJsAndroid.html

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>TestJs</title>

    <style>
   .button {
     background-color: #4CAF50;
     border: none;
     color: white;
     padding: 15px 32px;
     text-align: center;
     text-decoration: none;
     display: inline-block;
     font-size: 16px;
     margin: 4px 2px;
     cursor: pointer;
   }
   </style>

    <script>
     function callAndroid(){
       //由于对象映射,所以调用AndroidJsInterface对象等于调用Android映射的对象
       AndroidJsInterface.testMethod("js调用了android中的testMethod方法");
     }
   </script>
</head>

<body>
 点击按钮则调用callAndroid函数
 <br />
 <button type="button" class="button" onclick="callAndroid()">callAndroid</button>
</body>

</html>

加载Js

webView.loadUrl("file:///android_asset/TestJsAndroid.html");//目前js放在assets目录下,也可以部署到服务器,直接加载url


除了上面的方式,还可以通过自定义协议,在WebViewClient 的shouldOverrideUrlLoading ()方法回调拦截url或者通过 WebChromeClient 的onJsAlert()、onJsConfirm()、onJsPrompt()方法回调拦截,然后调用相应的方法。


3.Android去调用JS的代码

首先编写JS:TestAndroidJs.html

<!DOCTYPE html> 
<html> 
  <head> 
  <meta charset="utf-8"> 
  <title>TestAndroidJs</title> 
   
  <script> 
     //Android需要调用的方法 
     function callJSMethod(){ 
       alert("Android中调用了JS的方法"); 
     } 
  </script> 

  </head> 
</html>

Android中调用

webView.loadUrl("javascript:callJSMethod()");


注意:

调用JS方法可以有两种方式

一:直接使用loadUrl方法;

二:使用evaluateJavascript方法

webView.evaluateJavascript("javascript:callJS()", new ValueCallback<String>() { 
   @Override public void onReceiveValue(String value) { 
     //此处为 js 返回的结果 
   } 
  }); 
}

两者的区别是:

 evaluateJavascript是Android 4.4后开始支持,异步执行,效率更高,带有返回值

 loadUrl不需要考虑版本问题,但是同步执行,性能较差


                                


四.Hybrid的一个扩展应用场景

    在第三方资讯详情页中,使用自己的评论模块和相关推荐、广告等,提高资讯使用的体验,增加广告的收入。

                                  


    基本的流程和上面Hybrid的方式差不多,不同的有两点:

    (1)需要注意js注入的时机,需要在资讯文章加载完成后注入

             即:WebViewClient的onPageFinished方法中注入

    (2)Js是需要在资讯文章的基础上拼接

 

javascript:{
 $("body").append("<div style='position:fixed; bottom:15px'><b>这个是添加的内容</b></div>");

 function myJsFunction(data) {
  alert("myJsFunction:" + data);
  }

}

五.释放

   WebView使用后,释放不当,会导致内存泄漏

      

ViewGroup view = (ViewGroup) mWebView.getParent();//先从父容器中移除
view.removeView(mWebView);
mWebView.setWebViewClient(null); //把设置的接口置为空
mWebView.setWebChromeClient(null);
mWebView.destroy();  //调用其destroy方法,然后置空
mWebView = null;





    




猜你喜欢

转载自blog.csdn.net/qqwuy_muzi/article/details/80557505