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,只加了一行代码。

    跑起来↓
    WebView的前世今生(一)------简单的使用方法
    哎,说好一句话解决呢?

    这里问题出现的原因是:网页的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 还可以通过

    1. WebViewClient的shouldOverrideUrlLoading()
    2. 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

相关文章: