WebView的使用之Android与JS通过WebView互调方法
一、概述:
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文件夹里:
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的有参构造方法')");}
点击按钮,弹出的弹框效果如下:
这里要注意了!注意了!!注意了!!!重要的事情说三遍:
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文件夹下:
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代码的效果如下:
这里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; } }}
更多相关文章
- C#/IOS/Android通用加密解密方法
- 更改Android(安卓)AVD模拟器创建路径位置的方法
- Android中数据存储----SQLite数据库
- Android键盘系统
- Android应用程序启动过程源代码分析
- Android(安卓)AsyncTask理解及简单用法
- Android(安卓)App开发基础篇—数据存储(SP和文件)
- Android(安卓)学习笔记——利用JNI技术在Android中调用、调试C++
- Android(安卓)APK文件在电脑上面运行方法