通过webView与javascript交互来研究webView的特点




1、前言



webView是android中用于展示简单的网页或者加载一些html格式的很好的选择,它提供了很多的操作上的封装但同时又不失去灵活性,因为他提供了webViewClient和webChromeClient这两个可自定义的类来进行对页面动作的不同产生不同的表现的行为。在hybrid app开发模式中,webView可用于和web网页交互的能力也是一个很突出的亮点,很多时候都会需要用到这样的技术。所以接下来会通过讲解webView,webViewCient,webChromeClient之间互相的关系和作用,然后综合所讲内容来展示一个webView与web的javascript进行交互的场景。首先了解可定义webView页面表现行为的类。读者可先看webView的部分在回来看前面的部分,会比较好理解。



2、WebViewClient



此类可以作用与当webView的页面内容发生改变的时候或者需要提交表单数据的时候又或者发生错误的时候,进行对url或者内容的拦截处理,来进一步定义我们的操作内容。在WebViewClient中,有以下几个要点是比较重要的。


2.1 在新的请求前拦截URL


默认情况下,如果webView没有设置webViewClient的话,有新的请求加载的时候是由当前的activityManager进行处理请求的,但如果我们想在webView加载url的时候先拦截下来,自己处理的话,就需要给webView设置拦截器,即设置一个webViewClient并重写shouldOveeriedUrlLoading方法。该方法原型如下:


 public boolean shouldOverrideUrlLoading(WebView view, String url)

此方法可以让程序对url(post方式的请求除外)请求进行控制,当此方法返回true的时候表示程序会对url进行处理,返回false的时候表示webView会自己对url进行处理。而如果webView没有进行此方法重写的话,则当前的url会有系统负责处理。


2.2 判断当前页面是否开始加载或者加载完毕


webViewClient可以通过onPageStarted和onPageFinished来判断当前webView中某个页面是否开始加载或者是否加载完毕。方法原型如下:

 public void onPageStarted(WebView view, String url, Bitmap favicon) 
public void onPageFinished(WebView view, String url)
启动view表示调用了此方法的webView,url是当前正在加载的链接。favicon是与当前页面有关的一个标志,用于判断当前的页面是否加载过。



2.3 获取请求资源的数据


webViewCLient允许你拦截资源请求并获取返回的内容,方法原型如下:

 public WebResourceResponse shouldInterceptRequest

如果此方法返回的是Null,则webView会像往常一样去加载url的内容,否则的话就会用获取的数据来初始化内容。需要注意的是此方法不在主线程运行。


2.4获取请求失败的原因

webView中定义了很多常量用于描述url加载失败的原因,通过重写onReceiverError方法就可以获取失败的代码和失败信息。方法原型如下:

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

其中errorCode加载失败的代码,description是失败的描述,failingUrl是失败的链接。每个errorCode都有对应的消息。下面贴出它们的意义:







2.5 webView的缩放模式发生改变


如果webView的缩放模式发生改变的时候,所请求的资源也需要发送变化,那么就需要监听webView的缩放比例了。可以通过webVewClient的onScaleChanged方法来进行拦截。


 public void onScaleChanged(WebView view, float oldScale, float newScale)


其中oldScale表示原来的缩放比例,newScale表示新的缩放比例。这里要注意的是,对于高分辨率的手机,缩放比例默认是1.5X,普通的是1x,低分辨率的是0.75x。





3、 WebChromeClient



这个类可用于设计跟webView的ui相关的操作,比如请求进度的更新,或者js的弹窗或者标题的展现以及图标.....此类中最近常用的到的方法如下:



3.1获取请求进度


webChromeClient可以获取当前请求的url的进度情况,很经常用于展示在标题栏里面展示当前的进度信息。方法原型如下:


 public void onProgressChanged(WebView view, int newProgress) 

其中的newProgress就是当前的请求进度情况,通过设置activityd的setProgress方法就可以进行展示请求进度,当达到100%的时候,进度会自动消失。




3.2获取请求的网站标题和图标



webChromeClient提供了两个方法,可用于获取当前请求的Url的网站标题和图标,这样如果又需要的话,可以自己在标题栏设置相应的标题内容和图标信息,方法原型如下:


 public void onReceivedTitle(WebView view, String title) 
<pre name="code" class="cpp"> public void onReceivedIcon(WebView view, Bitmap icon)
 

3.3进行js弹窗提示

webChromeClient可以在客户端弹出js对话框的时候进行回调,以确认是由客户端对对话框进行处理还是交给webView进行处理。方法原型如下:
  public boolean onJsAlert(WebView view, String url, String message,
            JsResult result)

 public boolean onJsConfirm(WebView view, String url, String message,
            JsResult result)
 
 
 public boolean onJsPrompt(WebView view, String url, String message,
            String defaultValue, JsPromptResult result)

 public boolean onJsBeforeUnload(WebView view, String url, String message,
            JsResult result)


message是用于展示的提示消息,jSresult是客户端返回给javascript的结果。第一个方法弹出js的警告对话框,第二个是确认对话框,第三个是提示对话框,第四个是导航对话框。



3.4获取请求资源的权限



当前页面需要请求客户端资源的时候,会需要一些权限,因此webChromeClient提供了请求权限的处理方法,方法原型如下:


 public void onPermissionRequest(PermissionRequest request)

此方法只有两种处理方式,一种是PermissionRequest.grant方法用于同意,另外是deny方法用于拒绝。如果没有重写这个方法,默认是拒绝的。




3.5webView加载视频时指定显示图标


当webView含有视屏播放的时候,如果还没显示视频,会展示一个图标的。如果没有指定,将返回默认的图标,可以通过以下方法返回指定图标。

 public Bitmap getDefaultVideoPoster()



4、WebView


WebView是Android提供的一个用于展示网页内容的控件,如果你想实现一个简单的浏览器或者展示一些在线内容的话,就需要用到它。在webView中,展现网页内容用到的是webkit渲染引擎,并且实现了很多基本的功能,比如会记录你的浏览历史,这样你可以进行回退或者前进查找网页。还有查找文字、缩放网页比例等。既然我们用到webView去加载网页内容,所以就需要网络权限,记得,要加上网络权限。


默认情况下,webView是没有实现任何浏览器插件功能的,如果你仅仅是展现网页内容,那么webView是个很好的选择,但如果网页内容需要和用户交互的话,你必须让webView响应javaScript的动作。如果你没有实现webView的这些交互功能,建议使用Uri意图调用系统的浏览器处理网页内容请求比较合适。调用方法如下:


Uri uri=Uri.parse("htttp://baidu.com");

startActivity(new Intent(Intent.ACTION_VIEW,Uri));


要使用webView,可以在XML布局添加WbeView标签,并在onCreate方法中获取进行基本的交互设置。也可以自己new一个,然后调用setContentView方法将整个acitivty都被webView覆盖,如下:

WebView webView=new WebView();

setContentView(webView);


使用webView加载网页可以使用loadUrl方法,如下:

webView.loadUrl("Http://baidu.com“);


或者你可以加载html格式的资源,可以是静态资源文件也可以是字符串内容。比如:


String html="<html><body>content</body></html>;

webView.loadData(html,"text/html",null);


前面的部分讲到了webViewClient和webChromeClient,这两个方法可以定义很多webView基于不同的事件的不同相应,因此,一般情况下,如果不是仅仅展示html内容的话,都需要重写这两个对象来定义相应的实现。通常webChromeClient用于在webView的ui发生变化的时候的被调用,比如根据请求的网页获取当前的进度,在标题栏进行展示。webViewClient则用于处理webView中内容发生变化的时候,比如发送了错误或者进行了表单提交等。一般来说,如果想要webView进行URL请求处理,都需要重写shouldOverriedUrlLoading方法,这样,就可以拦截Url请求让webView自己处理,否则的话,会让应用抛出给系统调用,即唤起系统浏览器进行处理。


如果想要和页面进行交互,那么就必须允许webView与javaScript交互,由于webView默认是禁止的,所以需要我们自己设置。一般首先使用过调用webView.getSettings.setJavaScriptEnable方法进行设置。如果你还需要和网页进行数据交互,还需自行写一个java对象注入当前的页面中,这样javascript可以调用这个注入的对象来和应用交互。

下面给出一个官方的例子:


getWindow().requestFeature(Window.FEATURE_PROGRESS);
 *
 * webview.getSettings().setJavaScriptEnabled(true);
 *
 * final Activity activity = this;
 * 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%
 *     activity.setProgress(progress * 1000);
 *   }
 * });
 * 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("http://developer.android.com/")

至于如何和网页进行交互,是本文的重点,会在后面通过一个例子来讲解。


前面讲到过webView是可以进行方法缩小的,但是默认是不允许此动作的,所以要进行设置,如下:


webView.getSettings.setBuiltInZoomEnable(true);


这样设置之后,就会出现方法缩小的按钮,或者你可以用手势对页面进行放大缩小。


因为webView是用来浏览网页数据的,因此会涉及很多安全性问题,所以对于网页的cookie和缓存,每个应用都有自己的缓存文件,并且这些文件是不可以共享的。


由于机器的配置发生改变会导致activit进行重新加载资源,而这些也会导致webView重新加载页面,所以如果你不想发送,webView重新加载页面的现象,就需要在AndroidMenifest.xml中配置condigurationChange的相关属性。


由于android设备的屏幕差别很大,根据不同的分辨率有不同的像素密度,所以进行屏幕适配是必须的。对于webView来说,也是如此。android简单的把所有的设备分为三个等级,分别为高分辨率,普通分辨率和低分辨率手机,webView默认的展示内容的尺寸是普通分辨率。如果是高分辨率,webView将会放大1.5倍,如果是低分辨率则会缩小到0.75倍。这样就保证了在不同的手机上可以展示相同的内容。同时,根据分辨率的不同还可以设置目标css样式来达到不同的效果。


如何判断当前设备的分辨率呢,可以通过在js中调用window.devicePixelRatio这个属性来判断,如果返回的是1.5表示是高分辨率,1表示是普通的,0.75表示是低分辨率。


如果要支持html5播放视频,请记得打开硬件加速器,打开方法是在AndroidMenifest.xml标签中设置。当加载视屏或者网页的时候希望全屏现实的话,则需要重写webChromeClient中的onShowCustomView和onHideCustomView方法,记住这两个方法缺一不可,否则无法实现全屏。如果在适配加载过程中,需要显示自定义视图,可以重写getVideoLoadingProgressView方法。


最后请记住,使用webView的时候不要用wrap_content属性,必须使用确切的数值或者match_[arent来指定宽高,否则的话会到值wbView发生奇奇怪怪的显示现象。在webView中提供的很多方法都是委托webViewProvider实现的,在这里不讲webViewProvider是因为,它的方法基本和webView中的意思连同名字都是一样的,所以没有讲的必要,但是我们要知道这一点,即webView本身只是一个展示网页内容的控件,虽然他可以定制,但是却需要很多支持。下面将webView中比较重要的方法:



①、获取标题栏高度


public int getVisibleTitleHeight()

此方法用于获取可见的标题栏高度,注意是可见。



②、获取SSL安全证书


  public SslCertificate getCertificate()

如果访问的连接含有SSL安全证书,则返回,否则返回NULL。



③、为指定的主机存储Http凭证


  public void setHttpAuthUsernamePassword(String host, String realm,
            String username, String password)

用于给指定的主机或者域名存储Http身份凭证,这样在访问的时候就可以今夕身份验证。



④、加载网络请求


 public void loadUrl(String url)


注意如果使用此方法加载了页面之后,点击页面的内容需要跳转到其他页面的话,系统默认是调用浏览器处理,如果你希望webView去加载,就应该重写webViewClient的shouldOvrriedLoadUrl方法。


⑤、用post方式访问网络请求


 public void postUrl(String url, byte[] postData)


此方法会用于进行post方式访问连接,如果当前的url不是网络请求的话,就会调用loadUrl去加载数据,否则的话会携带postData数据去请求连接。



⑥、加载本地数据


public void loadData(String data, String mimeType, String encoding) 

这里需要解释的是encoding,它用于指示data的加密方式,如果是base64加密的话,encoding必须是”Base64",否则的话,就传值NULL,这样系统会自己去处理data数据的解码。


⑦、返回上一个网页


public void goBack() 

如果没有上一个网页,则会一直停留在当前页面。可通过canGoBack方法判断是否可以返回上一个页面。


⑧、滚到到页面顶部或者底部


 public boolean pageUp(boolean top) 
 public boolean pageDown(boolean bottom)


传值true,当前webView的内容就会滚动带页面顶部或者底部。



⑨、获取Url


 public String getOriginalUrl() 
 public String getUrl()


前者用于获取原始的链接地址,后者用于获取当前页面的访问地址。


⑩、进行js交互


 public void addJavascriptInterface(Object object, String name)


其中object是你定义的类,里面可以包含提供给js调用app的方法,name是js调用java对象的名称,这个名称在js和APP中必须保持一致。下面给出一个官方的例子:



class JsObject {
     *    {@literal @}JavascriptInterface
     *    public String toString() { return "injectedObject"; }
     * }
     * webView.addJavascriptInterface(new JsObject(), "injectedObject");
     * webView.loadData("<!DOCTYPE html><title></title>", "text/html", null);
     * webView.loadUrl("javascript:alert(injectedObject.toString())");


这里不解释了 ,后面我会用一个例子来讲解。要移除一个javaScript对象,可以调用:


public void removeJavascriptInterface(String name)


同时为了可以相应js操作,需要调用:


 public WebSettings getSettings()
以及:

下面的方法是在WebSetting里面的

  public abstract void setJavaScriptEnabled(boolean flag)



下面讲解一个通过webView来与网页的javascript交互的例子综合使用上述所讲内容:


首先需要在APP中定义一个类,此类应该定义一些可被js调用的方法。如下

 class JavaScriptInterface {
        @JavascriptInterface
        public void setParams(String busType, String entName, String startTimeOne, String startTimeTwo, String taskStatus) {
            activity.busType = busType;
            activity.entName = entName;
            activity.startTimeOne = startTimeOne;
            activity.startTimeTwo = startTimeTwo;
            activity.taskStatus = taskStatus;
        }
    }


类的名字是自己取得,没有限制,可被调用的方法必须加上@javascriptInterface注解,这样才能将这个方法注解到webView对象中。此类笔者是作为activity的内部类来使用的,所以setParams并不是什么强制的方法,这个完全是看你自己定义,我这里只是提供一个接口给js,这样js就可以把相应的查询操作产生的参数设置到APP端 了。


接下来看xml布局文件:


<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="cn.com.chinaweal.share.MainActivity">

    <WebView
        android:id="@+id/webView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"></WebView>

    <Button
        android:id="@+id/btClip"
        android:layout_width="match_parent"
        android:layout_height="40dp"
        android:onClick="clip"
        android:background="#efefef"
        android:text="截图分享"
        android:layout_above="@+id/btShare"
 />

    <Button
        android:id="@+id/btShare"
        android:layout_width="match_parent"
        android:layout_height="40dp"
        android:layout_alignParentBottom="true"
        android:onClick="share"
        android:background="#eeffaa"
        android:text="分享" />
</RelativeLayout>

请读者忽略webView之外的内容。这里只讲解怎么进行交互,读者需要自行筛选出有用的信息。


然后看activity代码:


   protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        getWindow().requestFeature(Window.FEATURE_PROGRESS);
        setContentView(R.layout.activity_main);
        handler = new Handler();
        webView = (WebView) findViewById(R.id.webView);
        webView.setWebChromeClient(new WebChromeClient() {
                                       @Override
                                       public void onProgressChanged(WebView view, int newProgress) {
                                           MainActivity.this.setProgress(newProgress * 1000);
                                       }
                                   }
        );
        webView.setWebViewClient(new WebViewClient() {
            @Override
            public boolean shouldOverrideUrlLoading(WebView view, String url) {
                view.loadUrl(url);
                return true;
            }
        });
        webView.getSettings().setJavaScriptEnabled(true);
        webView.getSettings().setUseWideViewPort(true); //设置自适应
        webView.getSettings().setLoadWithOverviewMode(true);
        webView.getSettings().setBuiltInZoomControls(true);//设置可缩放
        webView.getSettings().setPluginState(WebSettings.PluginState.ON);//设置插件状态从而播放视频
        webView.getSettings().setCacheMode(WebSettings.LOAD_NO_CACHE);
        webView.getSettings().setSavePassword(true);
        webView.getSettings().setSaveFormData(true);
        webView.getSettings().setJavaScriptEnabled(true);
        webView.requestFocus();
        webView.addJavascriptInterface(new JavaScriptInterface(), "webViewInterface");//注意这句话,和后面的js代码关联
        webView.loadUrl("http://192.168.191.1:8080/sdfer/");//这是笔者的调试地址,读者自行修改
        
    }




下面看一下js代码,重点关注如何执行webView给js注入的对象


<script type="text/javascript">

        function putParams()
        {
             if(window.webViewInterface!=null)
             {
                 var busType=$("#bustype").val();
                 busType=busType==null?"":busType;
                 var entName=$("#entname").val();
                 entName=entName==null?"":entName;
                 var startTimeOne=$("#startTimeOne").val();
                 startTimeOne=startTimeOne==null?"":startTimeOne;
                 var startTimeTwo=$("#startTimeTwo").val();
                 startTimeTwo=startTimeTwo==null?"":startTimeTwo;
                 var taskStatus=$("#taskstatus").val();
                 taskStatus=taskStatus==null?"":taskStatus;
                 window.webViewInterface.setParams(busType,entName,startTimeOne,startTimeTwo,taskStatus);//重点在这里
             }

        }

</script>


我们看看

 window.webViewInterface.setParams(busType,entName,startTimeOne,startTimeTwo,taskStatus);

webViewInterface就是我们调用addJavascriptInterface给的名称,这个方法是我们自定义的提供给js调用的方法。以上就实现了js端调用客户端的方法的过程。


那么如何在客户端调用js方法呢?


比如,我们在javascript中定义一个方法,如下:


  function invokeFromAPP(msg){
    alert("来自客户端的信息:"+msg);
  }


在客户端的代码中,对webView执行操作,如下:

webView.loadUrl("javascript:invokeFromAPP(msg)");

这样就实现了客户端调用js方法的操作了。



读者如果想了解整个流程,一定记得上机实践,否则是不会明白整个流程的。





---------文章写自:HyHarden---------

--------博客地址:http://blog.csdn.net/qq_25722767-----------









  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值