webView是android中用于展示简单的网页或者加载一些html格式的很好的选择,它提供了很多的操作上的封装但同时又不失去灵活性,因为他提供了webViewClient和webChromeClient这两个可自定义的类来进行对页面动作的不同产生不同的表现的行为。在hybrid app开发模式中,webView可用于和web网页交互的能力也是一个很突出的亮点,很多时候都会需要用到这样的技术。所以接下来会通过讲解webView,webViewCient,webChromeClient之间互相的关系和作用,然后综合所讲内容来展示一个webView与web的javascript进行交互的场景。首先了解可定义webView页面表现行为的类。读者可先看webView的部分在回来看前面的部分,会比较好理解。
如果webView的缩放模式发生改变的时候,所请求的资源也需要发送变化,那么就需要监听webView的缩放比例了。可以通过webVewClient的onScaleChanged方法来进行拦截。
public void onScaleChanged(WebView view, float oldScale, float newScale)
其中oldScale表示原来的缩放比例,newScale表示新的缩放比例。这里要注意的是,对于高分辨率的手机,缩放比例默认是1.5X,普通的是1x,低分辨率的是0.75x。
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() 此方法用于获取可见的标题栏高度,注意是可见。
public SslCertificate getCertificate() 如果访问的连接含有SSL安全证书,则返回,否则返回NULL。
public void setHttpAuthUsernamePassword(String host, String realm, String username, String password) 用于给指定的主机或者域名存储Http身份凭证,这样在访问的时候就可以今夕身份验证。
public void loadUrl(String url)
注意如果使用此方法加载了页面之后,点击页面的内容需要跳转到其他页面的话,系统默认是调用浏览器处理,如果你希望webView去加载,就应该重写webViewClient的shouldOvrriedLoadUrl方法。
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的内容就会滚动带页面顶部或者底部。
public String getOriginalUrl() public String getUrl()
前者用于获取原始的链接地址,后者用于获取当前页面的访问地址。
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-----------