一、概述:
Android与JS通过WebView实现交互,实际上是:

  • Android调用JS的代码;
  • JS调用Android的代码;

二者互调的纽带就是WebView。
Android调用JS代码的方法有以下几种:

  • 通过WebView的loadUrl();
  • 通过WebView的evaluateJavascript();

JS调用Android代码的方法要多点,有以下3种:
- 通过WebView的 addJavascriptInterface() 进行对象映射;
- 通过WebViewClient的 shouldOverrideUrlLoading () 方法回调拦截url;
- 通过WebChromeClient的 onJsAlert()、onJsConfirm()、onJsPrompt()方法回调拦截JS对话框alert()、confirm()、prompt()消息.
-
二、Android通过WebView调用 JS 方法

1、通过WebView的loadUrl()使用详情:
Android中激发点击事件,即调用WebView JS(文本名为webjs)中的方法;

——为了示例方便及响应速度,这里采用Andorid调用本地JS代码进行解释。实际开发中,Andorid极可能调用本地Html文件中的JS代码,也可能调用网络加载的Html页面中的JS代码。

步骤:
A、将需要调用的JS代码的HTML文件放到src/main/assets文件夹里:
WebView的使用之Android与JS通过WebView互调方法_第1张图片
webjs.html文件中代码如下:

<html><head>    <meta charset="UTF-8">    <title>Titletitle>    <h4>JS与Android(Java)的交互h4>    <input type="button" value="js调Android" onclick="ok()">    <script type="text/javascript">    function ok() {        android.webMessage("JS与Android(Java)的交互");    }    function javaCallJavascriptNoParam() {         alert("Android中的Java通过WebView调用了javaScript的无参构造");         document.getElementById("javacalljs").innerHTML = "Android中的Java通过WebView调用了javaScript的无参构造;    }    function javaCallJavascript(param) {         alert(param);         document.getElementById("javacalljs").innerHTML = param;    }    script>head><body><div id="javacalljs">div>    <br/><br/>body>html>

B、在Activity中设置WebView的常用属性:

1)、让网页显示在WebView中而不是用浏览器打开

mWeb.setWebViewClient(new WebViewClient());

2)、设置启动概述模式浏览界面、使用宽屏的视图窗口。

WebSettings setting = mWeb.getSettings();setting.setUseWideViewPort(true);setting.setLoadWithOverviewMode(true);

3)、允许调用Js的权限:

setting.setJavaScriptEnabled(true);setting.setJavaScriptCanOpenWindowsAutomatically(true);

B、在Activity中加载App内置的html文件:

String URL = "file:///android_asset/webjs.html";mWeb.loadUrl(URL);

C、在Activity的Java代码中调用html文件中的javascript代码:

@OnClick(R.id.tvLoadWeb)public void onViewClicked() {    mWeb.loadUrl("javascript:javaCallJavascript('Android中的Java通过WebView调用了javaScript的有参构造方法')");}

点击按钮,弹出的弹框效果如下:
WebView的使用之Android与JS通过WebView互调方法_第2张图片
这里要注意了!注意了!!注意了!!!重要的事情说三遍:

1、javascript中没有Java里面的多态和重载的概念,也就是说不能出现相同名字的方法,哪怕是后面的参数不一样(最鲜明的就是有参和无参)也不行。就如上面html文件里面的方法function javaCallJavascriptNoParam() {}和function javaCallJavascript(param) {},如果我们都用同一个方法名,有时候调用就会报错:Undefined;

2、在WebView调用javascript方法的loadUrl方法里面:

mWeb.loadUrl("javascript:javaCallJavascript('Android中的Java通过WebView调用了javaScript的有参构造方法')");  

中,要以”javascript”开头,有部分博客上面写的是以html的文件名开头,如本例中html的文件名为:“webjs”,他们就写成:

mWeb.loadUrl("webjs:javaCallJavascript(Android中的Java通过WebView调用了javaScript的有参构造方法')");

博主表示这样写也调用成功,但是我在学习的时候没有一次是调用成功的,不知道是我没学到家还是怎么的,总之调用起来各种不顺利。但可以确定的一点是:用前一种方法是肯定可以成功调用的。
3、有参无参其实都一样,就传不传参数而已,这个不多说。

三、JS通过WebView调用Java的方法
调用步骤:

1、创建html文件并放在src/main/assets文件夹下:
WebView的使用之Android与JS通过WebView互调方法_第3张图片
webjs.html文件代码如下:

<html><head>    <meta charset="UTF-8">    <title>Titletitle>    <h4>JS与Android(Java)的交互h4>    <input type="button" value="js调Android" onclick="ok()">    <script type="text/javascript">        function javaCallJsNoArgs() {            document.getElementById("content1").innerHTML += "js调用java,Java再回调js的无参方法        }        function javaCallJsExistArgs(args) {            document.getElementById("content2").innerHTML += "js调用java,Java再回调js的无参方法,参数是:" + args + ";        }    script>head><body><div id="javacalljs">div><br/><br/>        JS与Android(Java)的交互<br/><br/><br/>    <input type="button" value="JS调Java无参方法方法然后再回调"           onclick="js_call_java.javaCallJsMethod1()"/><br/>        <div id="content1">div>    <br/><br/>    <input type="button" value="JS调Java有参方法方法然后再回调"           onclick="js_call_java.javaCallJsMethod2()"/><br/>        <div id="content2">div>body>html>

2、在Activity的xml文件中布局WebView控件,并设置对应的Java和Js互调的属性:

WebSettings setting = mWvJsCallJava.getSettings();setting.setJavaScriptEnabled(true);/下面单个属性的作用前面已经介绍过了,不再重复。setting.setJavaScriptCanOpenWindowsAutomatically(true);setting.setUseWideViewPort(true);setting.setLoadWithOverviewMode(true);//设置编码格式setting.setDefaultTextEncodingName("utf-8");WebViewUtils.webViewSetting(setting, true, false, getApplicationContext());WebViewUtils.setViewClient(mWvJsCallJava);WebViewUtils.setChromeClien(mWvJsCallJava, getApplicationContext());//添加一个对象,让js对象可以访问该对象的方法mWvJsCallJava.addJavascriptInterface(new Javascript(), "js_call_java");

上面的Javascript.class文件代码如下:

final class Javascript{        public Javascript(){        }        @JavascriptInterface        public void javaCallJsMethod1() {            runOnUiThread(new Runnable() {                @Override                public void run() {                    mWvJsCallJava.loadUrl("javascript:javaCallJsNoArgs()");                }            });        }        @JavascriptInterface        public void javaCallJsMethod2() {            runOnUiThread(new Runnable() {                @Override                public void run() {                    mWvJsCallJava.loadUrl("javascript:javaCallJsExistArgs('我是皓月')");                }            });        }    }

addJavascriptInterface()方法里面参数”js_call_java”的作用:
我的理解是:
他是WebView与JS交互时的一个标识符,点击WebView中的按钮,按钮就会通过”js_call_java”标识符调用Java代码中标识符后面的方法。比如:

type="button" value="JS调Java有参方法方法然后再回调"           οnclick="js_call_java.javaCallJsMethod2()"/>

点击这个button后,系统就会通过WebView根据标识符”js_call_java”去调用他后面对应的方法。这里,标识符”js_call_java”后面的方法是:javaCallJsMethod2(),那么他就会调用Javascript对象里面的javaCallJsMethod2()方法。
上面WebViewUtils.class文件的代码在文末贴出。

3、加载html文件

String URL = "file:///android_asset/webjs.html";mWvJsCallJava.loadUrl(URL);

这样就完成了JS对Java代码的调用。我们还可以在Java代码里面继续调用js方法,就像上面那样:

mWvJsCallJava.loadUrl("javascript:javaCallJsExistArgs('我是皓月')");

JS调用Java代码的效果如下:
WebView的使用之Android与JS通过WebView互调方法_第4张图片

这里Java代码调用了js代码里面的javaCallJsExistArgs()有参方法。另一个也是如此。
至此,JS与Java的交互告一段落。

WebViewUtils.class文件的代码如下:

public class WebViewUtils {    public static void webViewSetting(WebSettings setting, boolean setTure, boolean setFalse, Context context) {        /////////////////////////////////////////////////////////////////////////////////////////        /**是否允许数据库存储,需要读写权限,默认false**/        /**查看setDatabasePath API 如何正确设置数据库存储。         * 该设置拥有全局特性,同一进程所有WebView实例共用同一配置。注意:保证在同一进程的任一WebView         * 加载页面之前修改该属性,因为在这之后设置WebView可能会忽略该配置 **/        setting.setDatabaseEnabled(setTure);        /////////////////////////////////////////////////////////////////////////////////////////        /**是否设置缓存,必需设置有效的缓存路径才能生效,默认值 false**/        setting.setAppCacheEnabled(true);        setting.setAppCachePath(context.getCacheDir().getAbsolutePath());        /////////////////////////////////////////////////////////////////////////////////////////        /**是否允许定位,默认true。         * 注意:为了保证定位可以使用,要保证以下几点:         * 1、Application需要有android.Manifest.permission#ACCESS_COARSE_LOCATION定位权限         * 2、Application需要实现WebChromeClient#onGeolocationPermissionsShowPrompt的监听回调,         *    接收Js定位请求访问地理位置的通知 **/        setting.setGeolocationEnabled(setTure);        /////////////////////////////////////////////////////////////////////////////////////////        /**是否保存表单数据,默认false**/        setting.setSaveFormData(setTure);        /////////////////////////////////////////////////////////////////////////////////////////        /**是否启动概述模式浏览界面,当页面宽度超过WebView显示宽度时,缩小页面适应WebView。默认false         * 需要和setUseWideViewPort()配合使用才生效**/        setting.setLoadWithOverviewMode(setTure);        /**是否支持ViewPort的meta tag属性,如果页面有ViewPort meta tag 指定的宽度,         * 则使用meta tag指定的值,否则默认使用宽屏的视图窗口(横竖屏时的宽度)**/        setting.setUseWideViewPort(setTure);        /////////////////////////////////////////////////////////////////////////////////////////        /**通知WebView是否需要设置一个节点获取焦点,当WebView#requestFocus(int,android.graphics.Rect)         * 被调用的时候,默认true **/        setting.setNeedInitialFocus(setTure);        /////////////////////////////////////////////////////////////////////////////////////////        /**布局算法**/        setting.setLayoutAlgorithm(WebSettings.LayoutAlgorithm.NORMAL);        /////////////////////////////////////////////////////////////////////////////////////////        /**设置是否(支持)允许执行JS方法**/        setting.setJavaScriptEnabled(setTure);        /////////////////////////////////////////////////////////////////////////////////////////        /**是否支持多窗口,如果设置为true ,WebChromeClient的onCreateWindow方法必须被主程序实现,默认false**/        setting.setSupportMultipleWindows(setTure);        /////////////////////////////////////////////////////////////////////////////////////////        /**是否允许JS自动打开窗口。默认false **/        setting.setJavaScriptCanOpenWindowsAutomatically(setFalse);        /////////////////////////////////////////////////////////////////////////////////////////        /**是否允许获取WebView的内容URL,可以让WebView访问ContentPrivider存储的内容.默认true**/        setting.setAllowContentAccess(setTure);        /**是否允许访问WebView内部文件,默认true, 不知道什么意思**/        setting.setAllowFileAccess(setTure);        /////////////////////////////////////////////////////////////////////////////////////////        /**是否允许通过file url加载的Javascript读取本地文件,默认值 false**/        setting.setAllowFileAccessFromFileURLs(setTure);        /////////////////////////////////////////////////////////////////////////////////////////        /**是否允许通过file url加载的Javascript读取全部资源(包括文件,http,https),默认值 false**/        setting.setAllowUniversalAccessFromFileURLs(setTure);        /////////////////////////////////////////////////////////////////////////////////////////        ////////////////////////////////资源加载        /**是否自动加载图片,包括从网络获取的图片、app内置的图片以及从Sdcard获取的图片**/        setting.setLoadsImagesAutomatically(setTure);        /**是否自动加载网络图片**/        setting.setBlockNetworkImage(setTure);        /**是否加载网络资源**/        setting.setBlockNetworkLoads(setTure);        /////////////////////////////////////////////////////////////////////////////////////////        ////////////////////////////////缩放(zoom)        /**是否支持缩放,配合setBuiltInZoomControls使用,默认true **/        setting.setSupportZoom(setTure);        /**是否使用WebView内置的缩放组件,由浮动在窗口上的缩放控制和手势缩放控制组成,默认false**/        setting.setBuiltInZoomControls(setFalse);        /**是是否显示内置缩放控件(有点像进度条,左边是“-”,右边是“+”)**/        setting.setDisplayZoomControls(setFalse);        /////////////////////////////////////////////////////////////////////////////////////////        ////////////////////////////////默认文本编码,默认值 "UTF-8"        /**设置页面的编码格式,默认UTF-8 **/        setting.setDefaultTextEncodingName("utf-8");        /////////////////////////////////////////////////////////////////////////////////////////        /**设置默认字体大小,默认16,取值区间[1-72],超过范围,使用其上限值。         * 另外WebView各种字体的大小的设置有一系列的方法:setXxxxFontSize(int size)**/        setting.setDefaultFontSize(16);        /**默认等宽字体尺寸,默认值16**/        setting.setDefaultFixedFontSize(16);        /**最小文字尺寸,默认值 8**/        setting.setMinimumFontSize(8);        /**最小文字逻辑尺寸,默认值 8**/        setting.setMinimumLogicalFontSize(8);        /**文字缩放百分比,默认值 100**/        setting.setTextZoom(100);        /////////////////////////////////////////////////////////////////////////////////////////        ////////////////////////////////设置字体        /**是否支持多窗口如果设置为true,WebChromeClient的onCreateWindow方法必须被主程序实现,默认false         * 另外WebView各种字体的设置有一系列的方法:setXxxxFontFamily(String font)**/        setting.setStandardFontFamily("sans-serif");        /**衬线字体,默认值 "serif"**/        setting.setSerifFontFamily("serif");        /**无衬线字体,默认值 "sans-serif"**/        setting.setSansSerifFontFamily("sans-serif");        /**等宽字体,默认值 "monospace"**/        setting.setFixedFontFamily("monospace");        /**手写体(草书),默认值 "cursive"**/        setting.setCursiveFontFamily("cursive");        /**幻想体,默认值 "fantasy"**/        setting.setFantasyFontFamily("fantasy");        /////////////////////////////////////////////////////////////////////////////////////////        /**存储(storage),启用HTML5 DOM storage API,默认值 false*/        setting.setDomStorageEnabled(true);        /////////////////////////////////////////////////////////////////////////////////////////        /**是否需要用户手势来播放Media,默认true**/        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {            setting.setMediaPlaybackRequiresUserGesture(setTure);        }        /////////////////////////////////////////////////////////////////////////////////////////        /**设置加载不安全资源的WebView加载行为。KITKAT版本以及以下默认为MIXED_CONTENT_ALWAYS_ALLOW         * 方式,LOLLIPOP默认MIXED_CONTENT_NEVER_ALLOW。强烈建议:使用MIXED_CONTENT_NEVER_ALLOW **/        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {            setting.setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW);        }        /////////////////////////////////////////////////////////////////////////////////////////        /**是否在离开屏幕时光栅化(会增加内存消耗),默认值 false**/        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {            setting.setOffscreenPreRaster(false);        }        /////////////////////////////////////////////////////////////////////////////////////////        /**根据cache-control决定是否从网络上取数据         * LOAD_DEFAULT 默认加载方式         * LOAD_CACHE_ELSE_NETWORK 按网络情况使用缓存         * LOAD_NO_CACHE 不使用缓存         * LOAD_CACHE_ONLY 只使用缓存 **/        if (isNetworkAvailable(context)) {            //有网络,从网络获取。            setting.setCacheMode(WebSettings.LOAD_DEFAULT);        } else {            // 没网,离线加载缓存(即使已经过期)            setting.setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK);        }    }    public static void setViewClient(WebView mWeb) {        /*****作用:让HTML网页显示在显示在WebView中而不是用浏览器打开**/        mWeb.setWebViewClient(new WebViewClient() {            @Override            public void onPageStarted(WebView view, String url, Bitmap favicon) {                //开始载入页面调用的,我们可以设定一个loading的页面,告诉用户程序在等待网络响应。                super.onPageStarted(view, url, favicon);            }            @Override            public void onPageFinished(WebView view, String url) {                //在页面加载结束时调用。我们可以关闭loading 条,切换程序动作。                super.onPageFinished(view, url);            }            @Override            public boolean shouldOverrideUrlLoading(WebView view, String url) {                //使得打开网页时不调用系统浏览器, 而是在本WebView中显示                view.loadUrl(url);                return super.shouldOverrideUrlLoading(view, url);            }            @Override            public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {                return super.shouldOverrideUrlLoading(view, request);            }            @Override            public void onLoadResource(WebView view, String url) {                //在加载页面资源时会调用,每一个资源(比如图片)的加载都会调用一次。                super.onLoadResource(view, url);            }            @Override            public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {                //加载页面的服务器出现错误时(如404)调用。                switch (errorCode) {                    //HttpStatus.SC_NOT_FOUND                    case 404:                        break;                    default:                        break;                }                super.onReceivedError(view, errorCode, description, failingUrl);            }            @Override            public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {                //专用于https请求                super.onReceivedSslError(view, handler, error);            }        });    }    public static void setChromeClien(WebView mWeb, final Context context) {        mWeb.setWebChromeClient(new WebChromeClient() {            @Override            public void onProgressChanged(WebView view, int newProgress) {                //网页的加载进度:newProgress即是加载进度百分比:0<=newProgress<=100;                super.onProgressChanged(view, newProgress);            }            @Override            public void onReceivedTitle(WebView view, String title) {                //要加载的网页的标题,比如http://www.baidu.com的标题:百度;http://www.ifeng.com的标题:凤凰网。                super.onReceivedTitle(view, title);            }            @Override            public boolean onJsAlert(WebView view, String url, String message, JsResult result) {                //允许弹出javascript的警告框,message就是警告框的内容。                return super.onJsAlert(view, url, message, result);            }            @Override            public boolean onJsConfirm(WebView view, String url, String message, final JsResult result) {                //允许弹出javascript的确认框,message就是确认信息。                new AlertDialog.Builder(context)                        .setTitle("信息确认")                        .setMessage(message)                        .setPositiveButton("确定", new DialogInterface.OnClickListener() {                            @Override                            public void onClick(DialogInterface dialog, int which) {                                result.confirm();                            }                        })                        .setNegativeButton("取消", new DialogInterface.OnClickListener() {                            @Override                            public void onClick(DialogInterface dialog, int which) {                                result.cancel();                            }                        })                        .setCancelable(false)                        .show();                // 返回布尔值:判断点击时确认还是取消                // true表示点击了确认;false表示点击了取消;                return super.onJsConfirm(view, url, message, result);            }            @Override            public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result) {                //允许弹出javascript输入框                EditText et = new EditText(context);                AlertDialog.Builder dialog = new AlertDialog.Builder(context);                dialog.setTitle("输入信息").setView(et)                        .setPositiveButton("Sure", new DialogInterface.OnClickListener() {                            @Override                            public void onClick(DialogInterface dialog, int which) {                                //返回输入框中的值,                            }                        })                        .setNegativeButton("Cancel", new DialogInterface.OnClickListener() {                            @Override                            public void onClick(DialogInterface dialog, int which) {                                //返回null。                            }                        }).setCancelable(false).show();                return super.onJsPrompt(view, url, message, defaultValue, result);            }        });    }    public static void clearCache(WebView mWeb) {        //清除网页访问留下的缓存,这个方法是针对整个应用程序.        mWeb.clearCache(true);        //清除当前webview访问的历史所有记录        mWeb.clearHistory();        //这个api仅仅清除自动完成填充的表单数据,并不会清除WebView存储到本地的数据        mWeb.clearFormData();    }    public static boolean isNetworkAvailable(Context context) {        // 获取手机所有连接管理对象(包括对wi-fi,net等连接的管理)        try {            ConnectivityManager connectivity = (ConnectivityManager) context                    .getSystemService(Context.CONNECTIVITY_SERVICE);            if (connectivity != null) {                // 获取网络连接管理的对象                NetworkInfo info = connectivity.getActiveNetworkInfo();                if (info != null && info.isConnected()) {                    // 判断当前网络是否已经连接                    if (info.getState() == NetworkInfo.State.CONNECTED) {                        return true;                    }                }            }        } catch (Exception e) {            e.printStackTrace();        }        return false;    }    public static Bitmap getLocalBitmap(String URL) {        try {            FileInputStream input = new FileInputStream(URL);            Log.i("TAG", "onViewClicked: input is Empty?:" + (input == null));            return BitmapFactory.decodeStream(input);        } catch (Exception e) {            Log.i("TAG", "onViewClicked: 抛异常:" + e);            return null;        }    }}

更多相关文章

  1. Android 学习笔记——利用JNI技术在Android中调用、调试C++代码
  2. Android APK文件在电脑上面运行方法
  3. 获取Android SDK 源代码并在Eclipse中关联查看的方法--转
  4. Android获取所有安装APP信息的详细代码
  5. android电话拨号器源代码
  6. android中遍历arrayList的四种方法

随机推荐

  1. (原)android的JNI中使用C++的类
  2. [置顶] 作为人才我们为什么要和几个猎头
  3. Android(安卓)开发即时聊天工具 YQ :(一) So
  4. Android对数据库表的一个约定:每张表都应
  5. Android(安卓)弹无虚发之第三弹:ActionBar
  6. 非开发人员如何使用命令行安装和卸载Andr
  7. Android----xml文件中的控件的id设置
  8. Android(安卓)开发中重力感应的实例
  9. android库工程jar打包和混淆
  10. 【小王的安卓之路】Android原生网络请求