WebView(H5)调用Android端代码

WebView调用Android代码

做好战斗准备,其实也不复杂

情景再现:
运营的H5页面上有个按钮,叫“立即参加”,当用户点击按钮的时候,App上要弹一个吐司出来。

一、通过WebView的addJavascriptInterface ()方式进行映射

1.准备工作
定义我们将来要响应js代码的类

/**
 * 与h5交互的共同类
 */
public class ForJs {
    //添加注解,不添加注解方法不能够被js调用
  //注意方法名称,提供给js的时候也一定要匹配
    @JavascriptInterface
    public void fromAndroid(){
        //我们具体要执行的逻辑,本例只是弹一个吐司
        ToastUtil.showToast("这个是android里的方法");
    }
 // 同上,只是一个有参,一个无参而已
    @JavascriptInterface
    public void fromAndroid(String msg){
        //我们具体要执行的逻辑,本例只是弹一个吐司
        ToastUtil.showToast("msg");
    }
}

至此,准备工作就已经结束。
2.使用

  • android端代码
        //如果只需要让js调用android代码,这几行就够了
        WebSettings settings = mWebView.getSettings();
        settings.setJavaScriptEnabled(true);
        mWebView.addJavascriptInterface(new ForJs(), "testMall");

参数说明:
1、我们定义的与H5交互的java类
2、java类在H5中映射的对象名称
H5中的js在调用我们的方法的时候,必须知道的是:
映射对象的名称,即示例中的testMall
映射对象提供的方法名称,即示例中的ForJs类中的fromAndroid()
H5中的关键代码
注意这部分代码并不需要我们Android端人员编写,但是却需要我们Android端人员的配合

//js中的点击方法调用,调用的是Android端的无参方法
<div onclick="test()" ></div>
<script>
//js中方法的定义
        function test(){
        testMall.fromAndroid()//注意 testMall 对象,以及fromAndroid()方法名称
        }
</script>

重复一下注意事项:

Androdi端提供给js调用的方法名称要准确无误的告诉前端人员
Js中映射的Java对象名称,要准确无误的告诉Android端人员

一定要看

这种使用方式看起来很简单,但是却有一个致命漏洞:
https://www.jianshu.com/p/3a345d27cd42

二、通过WebViewClinet的shouldOverrideUrlLoading()方法拦截url

  • 拦截该Url
  • 解析Url协议()//新的API可以直接获取到uri
  • 按照约定调用Android端的方法
    1.Android端代码
 mWebView.loadUrl("file:///android_asset/test.html");
        WebSettings settings = mWebView.getSettings();
        settings.setJavaScriptEnabled(true);
        mWebView.setWebViewClient(new WebViewClient(){
            @Override
            public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
                //请求方式
                String method = request.getMethod();
                //请求头
                Map<String, String> requestHeaders = request.getRequestHeaders();
                //uri,给里面有各种我们需要的东西,只需要get即可
                Uri uri = request.getUrl();
                String host = uri.getHost();
                String authority = uri.getAuthority();
                // TODO: 2018/12/15 判断,如果符合约定,即执行Android提供好的方法,最后记得return true
              //模拟微信封杀抖音链接
                if (authority.contains("douyin")){
                    ToastUtil.showToast("不要看抖音,微信不够丰富吗");
                    return true;
                }
                return super.shouldOverrideUrlLoading(view, request);
            }

            @Override
            public boolean shouldOverrideUrlLoading(WebView view, String url) {
                //如果使用这个方法,那么需要自己手动获取uri,其实与上面并无本质区别
                Uri uri = Uri.parse(url);
                return super.shouldOverrideUrlLoading(view, url);
            }
        });

至此,Android端代码完成
2.H5端代码
注意这部分代码并不需要我们Android端人员编写,但是却需要我们Android端人员与H5端人员协商好协议约定

//js中的点击方法调用
<div onclick="test()" ></div>

    <script>
          //js中方法的定义
        function test(){
          document.location="https://www.douyin.com/"
        }
    </script>

与第一种方法比起来,这种写法双方写起来都比较随意。除了Url的协议约定外,别的没有需要注意事项。尤其H5端,其实只是重定向了一个网页而已。
换句话说,在本示例中,如果我们直接在webView中加载
https://www.douyin.com/,也会触发我们的Android中的方法,即拦截逻辑。

更重要的是,第二种方式没有第一种方式那种致命漏洞。即利用shouldOverrideUrlLoading方法不存在漏洞

缺点:难以获得返回值,如果想要获得返回值,那么就利用Android端调用Js的方法webView的loadUrl(restul),将Android端的返回值result当做参数传递给js。

Android端示例代码:

 WebSettings settings = mWebView.getSettings();
        settings.setJavaScriptEnabled(true);
        mWebView.setWebViewClient(new WebViewClient() {
            @Override
            public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
                Uri uri = request.getUrl();
                String authority = uri.getAuthority();
                //模拟代码
                if (authority.contains("douyin")) {
                    String result = "这是Android端执行完成之后的结果";
//获取android端的结果后调用js中的方法,把result当参数传递给js
mWebView.loadUrl("javascript:callJsFromAndroid("+result+")");
                    return true;
                }
                return super.shouldOverrideUrlLoading(view, request);
            }
        });

        //注意,本示例之所以加此行代码,是为了能弹出js框,具体要看实际需求
        mWebView.setWebChromeClient(new WebChromeClient());
        mWebView.loadUrl("file:///android_asset/test.html");

H5端示例代码


<script>
        //result是android端的处理结果
        function callJsFromAndroid(result){
          alert(result)
        }
    </script>

三、通过WebChromeClient的alert()、prompt()、confirm()方法回调js对应的对话框

我在https://www.jianshu.com/p/22265f5c5d78中详细介绍了Android端响应这三种js弹框的方式,如果不熟悉的请先了解一下。一般来将,我们使用的最多的是prompt()方法,因为这个有任意类型的返回值,请看示例代码

Android端代码

  WebSettings settings = mWebView.getSettings();
        settings.setJavaScriptEnabled(true);
        //本行代码添加只是为了让网页在app内打开
        mWebView.setWebViewClient(new WebViewClient());
        
        mWebView.setWebChromeClient(new WebChromeClient(){
            @Override
            public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result) {
                //message即是js弹框中的内容
                //解析message,按照约定处理逻辑
                if (TextUtils.equals(message,"douyin")) {
                    // android端的处理逻辑
                    ToastUtil.showToast("你们怎么都那么好看又有钱");
                    return true;
                }
                return super.onJsPrompt(view, url, message, defaultValue, result);
            }
        });
        mWebView.loadUrl("file:///android_asset/test.html");

H5端示例代码

//js中的点击方法调用
<div onclick="test()" ></div>
<script>
        function test(){
          prompt("douyin")
        }

</script>

三种使用方式的对比

1.比较简单,但存在致命漏洞
2.需要双方约定协议,但不存在漏洞
3.与方式2很相似,只是拦截对象不同,也不存在漏洞

写在最后
这些交互方式各有特点,而且并不难以理解,个人认为都应该掌握。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,547评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,399评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,428评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,599评论 1 274
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,612评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,577评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,941评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,603评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,852评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,605评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,693评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,375评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,955评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,936评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,172评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,970评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,414评论 2 342

推荐阅读更多精彩内容