WebView的前世今生(一)------简单的使用方法
前言
先前看了几篇关于webView的博客,使用交互什么的都讲得很清楚,笔记记了很多,以为自己算是掌握了webView的使用了。
今天写个demo的时候,发现坑还不少。
纸上学来终觉浅,绝知此事要躬行啊。
打算webView写一整个系列吧,今天这篇就先写写一些简单上手使用的,记录一些坑。
使用WebView加载前端页面
主要是使用webView的loadUrl()方法,直接看代码吧↓
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 不在xml中定义WebView ,而是在需要的时候在Activity中创建
final WebView webView = new WebView(getApplicationContext());
// 复写WebViewClient的shouldOverrideUrlLoading()方法,使得打开网页时不调用系统浏览器, 而是在本WebView中显示
webView.setWebViewClient(new WebViewClient() {
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
view.loadUrl(url);
return true;
}
});
// 如果访问的页面中要与Javascript交互,则webView必须设置支持Javascript
webView.getSettings().setJavaScriptEnabled(true);
// 1. 加载一个百度页面
webView.loadUrl("https://www.baidu.com/");
// 2. 加载一个自己的html文件
// 先载入JS代码, 格式规定为:file:///android_asset/文件名.html
// 文件放在 ...\app\src\main\assets\下
// webView.loadUrl("file:///android_asset/js.html");
// 最后别忘了把webView加入布局
setContentView(webView);
}
}
这里唯一要注意的是:添加网络权限
<uses-permission android:name="android.permission.INTERNET"/>
普通传统的android 与 js 交互方法
-
android 调用 js 的方法
这里主要是使用webView.loadUrl()方法,看代码↓
public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); final WebView webView = new WebView(getApplicationContext()); webView.setWebViewClient(new WebViewClient() { @Override public boolean shouldOverrideUrlLoading(WebView view, String url) { view.loadUrl(url); return true; } }); webView.getSettings().setJavaScriptEnabled(true); webView.loadUrl("file:///android_asset/js.html"); // 在js.html写一个名叫callJS的方法,供android调用 webView.loadUrl("javascript:callJS()"); setContentView(webView); } }一切看起来都so easy,只加了一行代码。
跑起来↓
哎,说好一句话解决呢?这里问题出现的原因是:网页的js代码没有加载完成,就调用了js方法。
解决方法是:在网页加载完成之后调用 js 方法。
还是看代码吧↓
public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); final WebView webView = new WebView(getApplicationContext()); webView.setWebViewClient(new WebViewClient() { @Override public boolean shouldOverrideUrlLoading(WebView view, String url) { view.loadUrl(url); return true; } // 在网页加载完成之后调用js方法 @Override public void onPageFinished(WebView view, String url) { super.onPageFinished(view, url); webView.loadUrl("javascript:callJS()"); } }); webView.getSettings().setJavaScriptEnabled(true); webView.loadUrl("file:///android_asset/js.html"); setContentView(webView); } }android调用js的方法还可以通过WebView的evaluateJavaScript(),这个今天暂且不说。
-
js 调用android 的方法
先写一个供js调用的方法吧。
public class Test { // 被js调用的方法必须加入@JavascriptInterface注解 @JavascriptInterface public void hello() { // 具体逻辑 } }我们刚才在js里写了一个callJS方法供android调用,现在就在这个方法里面去调用android的hello方法。
通过WebView的addJavascriptInterface()给js传一个android对象,js拿到这个对象就能调用她的方法啦。
public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); final WebView webView = new WebView(getApplicationContext()); webView.setWebViewClient(new WebViewClient() { @Override public boolean shouldOverrideUrlLoading(WebView view, String url) { view.loadUrl(url); return true; } @Override public void onPageFinished(WebView view, String url) { super.onPageFinished(view, url); webView.loadUrl("javascript:callJS()"); } }); webView.getSettings().setJavaScriptEnabled(true); webView.loadUrl("file:///android_asset/js.html"); // 通过WebView的addJavascriptInterface()给js提供android对象 webView.addJavascriptInterface(new Test(), "test"); setContentView(webView); } }js 那边直接一句test.hello()就可以调到android这边的hello方法啦。
js 还可以通过
- WebViewClient的shouldOverrideUrlLoading()
- WebChromeClient的onJsAlert()、onJsConfirm()、onJsPrompt()方法回调拦截 js 对话框的alert()、confirm()、prompt()消息
这些方式去与android端交互,不过这个今天先不说。
使用JsBridge完成交互
GitHub链接:https://github.com/lzyzsd/JsBridge
首先要按照README,导入相关库
repositories {
// ...
maven { url "https://jitpack.io" }
}
dependencies {
compile 'com.github.lzyzsd:jsbridge:1.0.4'
}
-
js 调用 android 的方法
android 端的代码↓
public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); final BridgeWebView webView = new BridgeWebView(this); webView.getSettings().setJavaScriptEnabled(true); webView.loadUrl("file:///android_asset/js.html"); // 注册一个供js调用的名叫submitFromWeb的方法 webView.registerHandler("submitFromWeb", new BridgeHandler() { @Override public void handler(String data, CallBackFunction function) { // 具体逻辑 Log.i("tag", "callback:" + data); // 可以把一些数据回传给js function.onCallBack("success"); } }); ViewGroup.LayoutParams layoutParams = new RelativeLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT); addContentView(webView,layoutParams); } }js.html里的主要代码↓
<script> if (window.WebViewJavascriptBridge) { WebViewJavascriptBridge.callHandler( 'submitFromWeb' , "js去调android的submitFromWeb,这是传过去的数据" , function(data) { // 处理android端回传回来的数据 } ); } else { document.addEventListener( 'WebViewJavascriptBridgeReady' , function() { WebViewJavascriptBridge.callHandler( 'submitFromWeb' , "js去调android的submitFromWeb,这是传过去的数据" , function(data) { } ); }, false ); } </script>主要就是android端注册一个方法,然后js去调用,没啥好说的。
-
android 调用 js
在android端去调用js的方法public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); final BridgeWebView webView = new BridgeWebView(this); webView.getSettings().setJavaScriptEnabled(true); webView.loadUrl("file:///android_asset/js.html"); // android 去调用Js的方法 webView.callHandler("functionInJs", null, new CallBackFunction() { @Override public void onCallBack(String data) { Log.d("tag", "callback:" + data); } }); ViewGroup.LayoutParams layoutParams = new RelativeLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT); addContentView(webView,layoutParams); } }js注册一个供android调用的方法
<script> if (window.WebViewJavascriptBridge) { // 在js注册一个方法供android调用 WebViewJavascriptBridge.registerHandler("functionInJs", function(data, responseCallback) { var responseData = '指定接收收到来自Java的数据,回传数据给你'; responseCallback(responseData); }); } else { document.addEventListener( 'WebViewJavascriptBridgeReady' , function() { WebViewJavascriptBridge.registerHandler("functionInJs", function(data, responseCallback) { var responseData = '指定接收收到来自Java的数据,回传数据给你'; responseCallback(responseData); }); }, false ); } </script>如法炮制地让 js 注册一个方法然后android端去调用,事情并没有按想象中的一样发生,并且似乎啥也没发生过。
README里有一句:You can also define a default handler use init method, so that Java can send message to js without assigned handlerName。
大概是说可以在js定义一个默认的处理方法来处理android端没有指定方法名的情况。
本来以为我指定了方法名应该不写这个默认方法也OK吧,然而事实上把这个方法给写上就能出现预期中的结果了。
最后的js代码长这样↓
<script> if (window.WebViewJavascriptBridge) { // 要先初始化一个默认的处理方法 WebViewJavascriptBridge.init(function(message, responseCallback) { var responseData = '默认接收收到来自Java的数据,回传数据给你'; responseCallback(responseData); }); WebViewJavascriptBridge.registerHandler("functionInJs", function(data, responseCallback) { var responseData = '指定接收收到来自Java的数据,回传数据给你'; responseCallback(responseData); }); } else { document.addEventListener( 'WebViewJavascriptBridgeReady' , function() { WebViewJavascriptBridge.init(function(message, responseCallback) { var responseData = '默认接收收到来自Java的数据,回传数据给你'; responseCallback(responseData); }); WebViewJavascriptBridge.registerHandler("functionInJs", function(data, responseCallback) { var responseData = '指定接收收到来自Java的数据,回传数据给你'; responseCallback(responseData); }); }, false ); } </script>感动得暴风哭泣。
写在最后
折腾了这么久终于都,大概算是知道了一些基本的使用方法吧。
下一篇可能是系统整理一下知识点啥的。
本文中的例子下载链接:https://download.csdn.net/download/weixin_38676774/10943652
参考
https://github.com/lzyzsd/JsBridge
https://droidyue.com/blog/2014/09/20/interaction-between-java-and-javascript-in-android/
https://www.jianshu.com/p/3c94ae673e2a
https://blog.csdn.net/carson_ho/article/details/64904691