WebView与JS的那些事:入门篇

来源:互联网 发布:五笔教材 知乎 编辑:程序博客网 时间:2024/06/08 18:48

webview应该是开发人员最常接触的控件了,加载一个页面的时候,webview.loadUrl(url)就完事了,我遇到这么玩webview的一般都是在界面显示一些应用说明或是版本信息的时候比较常见,但是,这样根本发挥不了webview的潜能,接下来,我会出几篇比较好玩的文章,带大家爽一爽,今天这一篇或许对有些基础的人并不感冒,但可以看看后面的文章,会给你们带来惊喜的。


初探我会跟着官网的API来分析,让大家了解了解这些是拿来干什么的。

Basic usage(基本用法)

对于打开一个url我们可能会有两种方法,一个是通过外部浏览器去打开,另一种则是通过自己的应用的webview去打开,官网也给出了两种用法。

通过外部浏览器打开

 Uri uri = Uri.parse("http://www.example.com"); Intent intent = new Intent(Intent.ACTION_VIEW, uri); startActivity(intent);

通过内部webview打开

 WebView webview = new WebView(this); setContentView(webview); webview.loadUrl("http://slashdot.org/"); String summary = "<html><body>You scored <b>192</b> points.</body></html>"; webview.loadData(summary, "text/html", "utf-8");

customization points(定制)

对于上面的webview的基本用法我们已经知道了,接下来,我们看一些定制webview需要了解哪些东西。

(一)WebChromeClient

官网解释:This class is called when something that might impact a browser UI happens,for instance, progress updates and JavaScript alerts are sent here
大概意思是,这个类能做一些对界面的渲染效果,比如加载webview的进度更新或是js的对话框

(二)WebViewClient

官网解释:It will be called when things happen that impact the rendering of the content, eg, errors or form submissions. You can also intercept URL loading here
大概意思就是,当webview加载的时候,这个类有很多的方法会被回调,比如webview的开始加载,加载错误,加载完成等回调处理,关键看后面这一句,你也可以拦截url的加载,这句话很关键,后面会用上,这个拦截需要依赖这个类的一个方法—shouldOverrideUrlLoading()

(三)WebSettings

官网解释:Modifying the WebSettings, such as enabling JavaScript with setJavaScriptEnabled()
这个类主要是对于webview进行一些设置,比如是否允许加载js等,这个也是我们比较常用的。

(四)addJavascriptInterface(Object, String)

官网解释:Injecting Java objects into the WebView using the addJavascriptInterface(Object, String) method. This method allows you to inject Java objects into a page’s JavaScript context, so that they can be accessed by JavaScript in the page.
这个类是重中之重,他发挥了webview的特性,他就好比是网页与原生沟通的一个桥梁,网页中的js能调用android内的控件,android能通过js去处理网页,就像官网的解释那样,这个方法允许你注入java对象实现js的上下文

使用

上面介绍的差不多了,接下来,我们要学会如何去使用他,我们先从上面的介绍一步一步的开始

WebChromeClient的使用

我们见过很多浏览器的效果,在加载网页的时候,头部有个进度条一直跟着显示加载进度,该实现方式就是通过如下的代码实现的,我们可以在webview的头部添加一个progressbar控件的横向样式,设置max最大值为100,因为WebChromeClient的onProgressChanged方法回调的progress加载完成的时候也是100。

webview.setWebChromeClient(new WebChromeClient() {            public void onProgressChanged(WebView view, int progress) {                 progressBar.setProgress(progress);                 Log.i(TAG,"--->"+progress);            } });

如图

这里写图片描述

WebViewClient的使用

该方法就好比是webview的一个生命周期,有网页加载开始回调,加载失败回调,加载成功回调。然而,仅仅就这三个方法,却可以帮我们完成很多很多的事情。

  webView.setWebViewClient(new WebViewClient() {            @Override            public boolean shouldOverrideUrlLoading(WebView view, String url) {                return true;            }            @Override            public void onPageStarted(WebView view, String url, Bitmap favicon) {                super.onPageStarted(view, url, favicon);                Log.i(TAG, "-------->网页加载开始");            }            @Override            public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) { {                Log.i(TAG, "-------->网页加载错误");            }            @Override            public void onPageFinished(WebView view, String url) {                super.onPageFinished(view, url);                  Log.i(TAG, "------>网页加载完成");            }        });

根据方法名字我们就知道其中的意思了,我相信,在这样的一个周期当中,很多开发者都有这样的需求。
网页加载失败或是没有网络的时候,我们为了不想让用户看到“找不到网页”这样的页面,我们习惯自己定制加载失败的页面去告知用户,然后点击重新加载,继续加载。这样符合用户的体验,这时候,这个周期就非常的符合要求了。

注意:我们要知道一点的就是,无论webview加载成功还是加载失败,最后一个触发的都是加载完成的回调,所以,我们在处理加载失败页面的时候,需要在onReceivedError设置一个标志位,告诉onPageFinished刚刚加载的是一个错误的页面。

用法:我们可以在根布局RelativeLayout下创建两个布局,设置加载失败页面为gone,设置webview也为gone,progressbar设置为visible,我们在loadUrl加载页面的时候,我们在onPageStarted去初始化状态,比如,设置当前是否是错误页面flag=false,设置webview为gone,设置错误页面为gone,然后在onReceivedError里面只需要设置当前页面是错误页面flag=true,最后,我们在onPageFinished加载完成的时候去做个判断,如果flag为false表示加载成功,这时候我们设置webview为visible,如果flag为ture表示加载错误,我们就设置错误页面为visible,webview为gone,最后设置progressBar为gone,然后给错误页面设置一个点击事件,点击该按钮就是重新加载,这样,一个体验不错的小功能就出来了。

图:该处我把上面的progressbar也设置了一下,在加载完成的时候设置为gone,在开始加载的时候visible。我也把加载过程的生命周期也Toast出来了,方便查看

这里写图片描述

对了,还有一个方法没有说

public boolean shouldOverrideUrlLoading(WebView view, String url)

官网解释:return true means the host application handles the url, while return false means the current WebView handles the url

这个方法还是很有意思,他可以做到对页面的url拦截,现在方法内什么都不写,如果return返回了true,就交给手机的应用去处理这个url,亲测的时候,当返回true的时候,页面的链接点击是没有效果的,如果返回false,url直接在webview进行加载,
但是,我又遇到一个好玩的。我们在该方法内使用 view.loadUrl(url);继续加载这个链接,这时候,无论是设置true还是false,页面都会在webview进行加载,所以,感觉这个方法有点鸡肋啊,怪不得这个方法现在加上了删除线,不推荐使用了。

  @Override            public boolean shouldOverrideUrlLoading(WebView view, String url)   {                view.loadUrl(url);                return true;            }

WebSettings

该类就是辅助webview的一些设置,比如有

         WebSettings seting = webView.getSettings();        //设置加载网页的js可用,这个设置对后面要讲到的js与android交互的时候会使用到        seting.setJavaScriptEnabled(true);        // 设置允许JS弹窗        seting.setJavaScriptCanOpenWindowsAutomatically(true);        // 防止中文乱码        seting.setDefaultTextEncodingName("UTF-8");        // 设置可以支持缩放       seting.setSupportZoom(true);        // 设置缓存是否可用        seting.setAppCacheEnabled(true);        //设置webview的缓存        seting.setCacheMode(WebSettings.LOAD_NO_CACHE);        // 设置出现缩放工具        seting.setBuiltInZoomControls(false);          // 自适应屏幕seting.setLayoutAlgorithm(WebSettings.LayoutAlgorithm.NORMAL);

addJavascriptInterface

该方法才是webview最好玩的的地方,如下使用

seting.setJavaScriptEnabled(true);
webView.addJavascriptInterface(new JSObject(), “jsAndroid”);

该方法首先得设置能加载js才能使用,addJavascriptInterface有两个方法,一个是对象,这个对象里面设置了好多以@JavascriptInterface为注解的方法,目的是为js提供调用原生的入口,第二个参数就好比是new一个对象的变量,就相当于JSObject js=new JSObject(),第二个参数就好比是那个js对象 。我们来看看官网给我们的例子

class JsObject {    @JavascriptInterface    public String toString() { return "injectedObject"; } } webView.addJavascriptInterface(new JsObject(), "injectedObject"); //添加网页内容 webView.loadData("", "text/html", null); //添加js代码 webView.loadUrl("javascript:alert(injectedObject.toString())");

上面的demo主要目的是通过js拿android的数据。

如图:
这里写图片描述

为了更好的演示js与webview的交互,我还是写个网页出来。

Html页面代码

<!DOCTYPE html><html><head>    <script type="text/javascript">        function javaToJs() {            document.getElementById("main").innerHTML = "<br\>java调用了js的无参函数";        }        function javaToJsValue(arg) {            document.getElementById("main").innerHTML = ("<br\>java调用了js的有参数函数--->" + arg);        }    </script></head><body><h1 id="main">webview与js交互</h1><input type="button" value="调用java代码 无参函数" onclick="window.jsAndroid.setValue()"><input type="button" value="调用java代码 带参函数" onclick="window.jsAndroid.setValue('我是被js带过来的')"></body></html>

java代码

  @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        initWeb();        initSetting();         webView.addJavascriptInterface(new JSObject(), "jsAndroid");        webView.loadUrl("http://192.168.7.248/web.html");     } private void initWeb() {        webView = (WebView) findViewById(R.id.webview);     }   private void initSetting() {        seting = webView.getSettings();        seting.setJavaScriptEnabled(true);        // 设置允许JS弹窗        seting.setJavaScriptCanOpenWindowsAutomatically(true);        //防止中文乱码        seting.setDefaultTextEncodingName("UTF-8");        //设置webview的缓存        seting.setCacheMode(WebSettings.LOAD_NO_CACHE);    } //button无参的点击事件    public void jstoAndroid(View v){        webView.loadUrl("javascript:javaToJs()");    }    //button带参的点击事件    public void jstoAndroidValue(View v){        webView.loadUrl("javascript:javaToJsValue('hello')");    }  class JSObject {        @JavascriptInterface        public void setValue(){            Toast.makeText(MainActivity.this, "js调用了java代码 无参函数", Toast.LENGTH_SHORT).show();        }        @JavascriptInterface        public void setValue(String str){            Toast.makeText(MainActivity.this, "js调用了java代码 有参函数,c传递的数据是---->"+str, Toast.LENGTH_SHORT).show();        }    }

结果显示如图:

这里写图片描述

好了,讲了差不多了,此处就不提供源码了,这篇主要提供思路,下一篇才是精彩。

0 0