Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JSBridge实现原理探索:以toast为例 #76

Open
youngwind opened this issue Jun 30, 2016 · 1 comment
Open

JSBridge实现原理探索:以toast为例 #76

youngwind opened this issue Jun 30, 2016 · 1 comment
Labels

Comments

@youngwind
Copy link
Owner

youngwind commented Jun 30, 2016

问题

我们知道,如果想要满足飞快增长的业务需要,必然得在APP中嵌入Web内容。一般来说,是java调用webview类新建一个webview,然后通过loadUrl加载Web页面。如果这个页面是纯展示性的还好说,对于复杂的页面,常常需要调用APP原生的功能,这个时候应该怎么办呢?

我们把问题抽象一下:“如何实现javascript和java的相互调用?”
把问题一分为二,先来看**“如何实现javascript调用java?”**

要实现的效果

我们要实现的效果如下图所示,点击某个按钮,打开一个新页面,然后加载web页面。点击web页面当中的按钮,调用安卓原生的方法toast,弹出提示。
demo

如果你想在手机上查看真实效果的话,可以扫描下面的二维码安装测试包。
1467255657

思路分析

我们来想想如何实现上面的功能。难点有这么几个:

  1. 如何创建一个webview?如何在webview中加载网页?
  2. web如何调用android?

对于第一点,不是本文的重点,你可以参考这个链接来自行解决。

对于第二点,我们继续分析。
web和android,就像是一个中国人和一个美国人。想要不同语言之间的人进行有效沟通的话,必须要满足以下两个基本要素。

  1. 你在听我说话 => 你在监听我的动作 =>javascript的某个行为会被java捕获到
  2. 我们手上有一本中英双译字典 => 我们之间有协议规范 => 对于传输的信息,javascript和java要用规定好的方式来编码和解码

先来看动作监听。javascript的哪些操作会被java捕获到?整个web页面都是运行在java提供的webview实例当中。javascript执行以下四种行为会被webview监听到,箭头后面是对应触发的Java方法。

  1. window.alert => onJSAlert
  2. window.confirm => onJSConfirm
  3. window.prompt => onJsPrompt
  4. window.location => shouldOverrideUrlLoading

好,动作监听我们解决了。接下来是要制定通信协议。说到通信协议,我们首先想到的是http协议,没错,我们可以仿照http协议制定我们自己的协议。
比如http协议是这样子的: http://www.baidu.com?param
我们制定的协议是这样子: ywjs://toast?message
其中ywjs是scheme,代表我们用的是某种自定义的协议。toast是方法名,也就是我希望调用的是系统的toast方法。toast方法所需要的参数,也就是弹出的提示字符串。

代码实现

好,思路我们已经分析好了。万事俱备,只欠敲代码了。(如果完全看不懂,请先补充一下基本的安卓开发知识和webview的使用方法)

// java代码 JSBridgeAlert.java
package com.example.youngwind.helloworld.JSBridgeAlert;

import android.content.pm.ApplicationInfo;
import android.net.Uri;
import android.os.Build;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.webkit.JsResult;
import android.webkit.WebChromeClient;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.Toast;

import com.example.youngwind.helloworld.R;

public class JSBridgeAlert extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_jsbridge_alert);
        // 添加了chrome:inspect bebug功能
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
            if (0 != (getApplicationInfo().flags &= ApplicationInfo.FLAG_DEBUGGABLE)) {
                WebView.setWebContentsDebuggingEnabled(true);
            }
        }

        final WebView myWebView = (WebView) findViewById(R.id.webView);

        // webview启用javascript
        WebSettings webSettings = myWebView.getSettings();
        webSettings.setJavaScriptEnabled(true);


        myWebView.loadUrl("file:///android_asset/alert.html");

        myWebView.setWebChromeClient(new WebChromeClient() {
            @Override
            public boolean onJsAlert(WebView view, String url, String message, JsResult result) {

                // message === "ywjs://toast?利用jsAlert建立JSBridge"

                if(message.startsWith("ywjs://")){
                    String methodName = "";
                    String param = "";
                    Uri uri = Uri.parse(message);

                    // toast
                    methodName = uri.getHost();

                    // msg参数
                    param = uri.getQuery();

                    if (methodName.equals("toast")) {
                        Toast.makeText(view.getContext(), param, Toast.LENGTH_LONG).show();
                    }
                    // 这一句非常关键,相当于点击了alert的确认
                    // 没有这一句的话,alert只能被触发一次,且其他地方的alert也不能被触发
                    result.confirm();
                }



                return true;
            }
        });
    }
}

// html代码 Alert.html
<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>利用jsAlert建立JSBridge</title>
    <style>
        #test {
            width:100%;
            height:50px;
        }
    </style>
</head>
<body>
<button id="test">点我toast</button>
<script src="file:///android_asset/jquery.js" type="text/javascript"></script>
<script type="text/javascript">

    $(document).on('click','#test',function(){
        alert("ywjs://toast?利用jsAlert建立JSBridge");
        })


</script>
</body>
</html>

其他实现方式

刚刚只展示了onJsAlert的实现代码,就像刚刚提到的,还有confirm、prompt和location方法也可以用来实现。
另外,webview本身提供了这样的接口,可以不采用上面的重新思路来进行,那就是addJavascriptInterface。
具体的实现方法可以参考文末的链接,可以查看我编写的demo代码

遗留问题

还有这么一些问题没有有待解决。

  1. java如何调用js方法?
  2. Javascript调用了java方法,java方法执行完成之后如何调用javascript的回调方法?
  3. ios系统下如何做JSBridge?

参考资料

@xxssww0258
Copy link

addJavascriptInterface制定的协议有什么区别?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants