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

Interaction between Native and js #35

Open
yunshuipiao opened this issue May 23, 2019 · 0 comments
Open

Interaction between Native and js #35

yunshuipiao opened this issue May 23, 2019 · 0 comments
Labels

Comments

@yunshuipiao
Copy link
Owner

yunshuipiao commented May 23, 2019

Interaction between Native and js

[TOC]

这篇文章介绍 Android 与 js 的交互。由于目前很少有纯 native 的应用,并且电商类 APP 都含有大量的网页,所以这块知识属于必须掌握的。

交互方式概览

Android 和 js 交互实际上是通过 WebView 互相调用方法:

  • Android 调用 js 的代码
  • js 调用 Android 的代码

那么对于 Android 调用 js 的方法有两种:

  • 通过 webview 的 loadUrl() 方法
  • 通过 webview 的 evaluateJavascript() 方法

而对于 js 调用 android 代码的方式有 3 种:

  • 通过 webview.addJavascriptInterface() 进行对象映射
  • 通过 webviewClient 的 shouoverrideUrlLoading() 方法回调拦截 url。
  • 通过 WebChromeClient 的 onJsAlert(), onJsConfirm(), onJsPromot() 方法回调拦截 js 的对话框,alert(), confirm(), promot() 消息。

Android 调用 JS

通过 weview 的 loadUrl()

比较常用,用于加载给定的 url 或者本地 网页,或者执行 js 代码。

// 注意调用的JS方法名要对应上
// 调用javascript的callJS()方法
mWebView.loadUrl("javascript:callJS()");

这里需要注意,JS 代码调用一定要在 onPageFinished() 回调之后, 表示页面加载结束。

通过 webview 的 evaluateJavascript() 方法

该方法比第一种方法效率更高,使用更简洁。

  1. 因为该方法的执行不会刷新页面,而第一种方法会刷新页面
  2. Android 4.4 以后才支持
// 只需要将第一种方法的loadUrl()换成下面该方法即可
    mWebView.evaluateJavascript"javascript:callJS()", new ValueCallback<String>() {
        @Override
        public void onReceiveValue(String value) {
            //此处为 js 返回的结果
        }
    });
}

JS 调用 Android 代码

通过 webview.addJavascriptInterface() 进行对象映射

  1. 定义一个与 JS 对象映射关系的 Android 类,AndroidToJs。

    // 继承自Object类
    public class AndroidtoJs extends Object {
    
        // 定义JS需要调用的方法
        // 被JS调用的方法必须加入@JavascriptInterface注解
        @JavascriptInterface
        public void hello(String msg) {
            System.out.println("JS调用了Android的hello方法");
        }
    }
  2. 需要调用的 js 代码如下:

    function callAndroid(){
            // 由于对象映射,所以调用test对象等于调用Android映射的对象
            test.hello("js调用了android中的hello方法");
    }
  3. 在 Android 里面添加对应的映射关系

  4.  // 设置与Js交互的权限
    webSettings.setJavaScriptEnabled(true);
    
            // 通过addJavascriptInterface()将Java对象映射到JS对象
            //参数1:Javascript对象名
            //参数2:Java对象名
    mWebView.addJavascriptInterface(new AndroidtoJs(), "test");//AndroidtoJS类对象映射到js的test对象

优点:使用简单,仅需要 Android 和 JS 对象的映射。

缺点:当 JS 拿到 Android 这个对象后,就可以调用这个 Android 对象中所有的方法,包括系统类(java.lang.Runtime 类),从而进行任意代码执行。

如可以执行命令获取本地设备的SD卡中的文件等信息从而造成信息泄露

解决方案:

  1. Google 在Android 4.2 版本中规定对被调用的函数以 @JavascriptInterface进行注解从而避免漏洞攻击
  2. 在Android 4.2版本之前采用**拦截prompt()**进行漏洞修复。

通过 webviewClient 的 shouoverrideUrlLoading() 方法回调拦截 url

具体原理是:

  1. Android 通过 WebViewClient 的 回调方法 shouoverrideUrlLoading() 拦截 url
  2. 解析该 url 的协议
  3. 如果检测到的是预先约定好的协议,就调用相应方法。
  • 优点:不存在方式1的漏洞;
  • 缺点:JS获取Android方法的返回值复杂。

通过 WebChromeClient 的方法,自定义协议

原理:通过 WebViewClient 的 onJsAlert(), onJsConfirm(), onJsPromot() 方法回调分别拦截对应的 JS 对话框。最常见的拦截 promot 对话框。

  1. 常用的拦截是:拦截 JS的输入框(即prompt()方法)
  2. 因为只有prompt()可以返回任意类型的值,操作最全面方便、更加灵活;而alert()对话框没有返回值;confirm()对话框只能返回两种状态(确定 / 取消)两个值

需要返回值时,通过上述 Android 调用 Js 代码将返回值传会 Js 端。

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

1 participant