完整项目:https://github.com/snailycy/android_jsbridge

1.1 配置WebView

    public void configWebView() {        try {            WebSettings settings = this.mWebView.getSettings();            settings.setJavaScriptEnabled(true);            settings.setJavaScriptCanOpenWindowsAutomatically(true);            settings.setDatabaseEnabled(true);            settings.setBuiltInZoomControls(false);            settings.setDomStorageEnabled(true);            settings.setAppCacheEnabled(true);            //设置localStorage存储路径            String localStorageDBPath = this.mWebView.getContext().getFilesDir().getAbsolutePath();            settings.setDatabasePath(localStorageDBPath);            this.mWebView.setWebViewClient(new JSWebViewClient(this));            this.mWebView.setWebChromeClient(new JSWebChromeClient(this));        } catch (Exception e) {            LogUtils.e(TAG, "configWebView error.");        }    }

1.2 安卓端拦截js的请求在WebChromeClient类中的onJsAlert方法中处理
注:如果是用addJavascriptInterface的方式接受js请求,那么在android 4.2系统以下版本有js注入漏洞(在4.2及以上系统时引入@JavascriptInterface可避免)

    @Override    public boolean onJsAlert(WebView view, String url, String message, JsResult result) {        if (message.startsWith(JS_REQUEST_PREFIX)) {            if (this.jsBridge == null) {                result.cancel();                return true;            }            parseJSProtocol(message);            result.cancel();            return true;        }        return super.onJsAlert(view, url, message, result);    }

1.3 自定义JS 请求协议:myjsbridge:///request?class=指定调用的类名&method=指定调用的方法名¶ms=指定的参数&callId=指定的请求ID
解析时按照协议格式分别解析出类名,方法名,参数,callId

/**     * 解析JS协议     *     * @param message: myjsbridge:///request?class=指定调用的类名&method=指定调用的方法名¶ms=指定的参数&callId=指定的请求ID     */    private void parseJSProtocol(String message) {        String[] tokens = message.substring(JS_REQUEST_PREFIX.length()).split("&");        String target = null;        String method = null;        String params = null;        long callID = -1;        for (String token : tokens) {            String[] pair = token.split("=");            if (pair.length != 2) {                continue;            }            try {                String key = pair[0];                String value = Uri.decode(pair[1]);                if (JS_REQUEST_CLASS_KEY.equals(key)) {                    target = value;                } else if (JS_REQUEST_METHOD_KEY.equals(key)) {                    method = value;                } else if (JS_REQUEST_PARAMETERS_KEY.equals(key)) {                    params = value;                } else if (JS_REQUEST_CALL_ID_KEY.equals(key)) {                    callID = Long.parseLong(value);                }            } catch (Exception e) {                // Ignores.            }        }        if (target != null && method != null && callID >= 0) {            this.jsBridge.requestAndroid(target, method, params, callID);        }    }

1.4 拿到对应的类名,方法名,参数后通过发射调用对应的jsapi

/**     * 由JS发起的对android端的请求     *     * @param className  类名     * @param methodName 方法名     * @param params     参数     * @param callID     请求ID     */    public void requestAndroid(final String className, final String methodName,                               final String params, final long callID) {        this.mWebView.post(new Runnable() {            @Override            public void run() {                try {                    //拼接全类名: 包名.jsapi.className                    String fullClassName = mWebView.getContext().getPackageName() + ".jsapi" + "." + className;                    Class<?> cls = Class.forName(fullClassName);                    //JSAPI 方法形参为(JSBridge jsbridge,long callId,JSONObject params)                    Method declaredMethod = cls.getDeclaredMethod(methodName, JSBridge.class,                            Long.class, JSONObject.class);                    Object instance = cls.newInstance();                    //将请求参数转换成JSONObject                    JSONObject requestParams;                    try {                        requestParams = new JSONObject(params);                    } catch (JSONException e) {                        requestParams = new JSONObject();                    }                    //反射调用JSAPI                    declaredMethod.invoke(instance, JSBridge.this, callID, requestParams);                } catch (Exception e) {                    reportError(callID);                }            }        });        LogUtils.d(TAG, "requestAndroid : " + className + " , " + methodName + " , " + params);    }

1.5 jsapi demo

public class JSUIControl {    public void showToast(JSBridge jsBridge, Long callId, JSONObject requestParams) {        String content = requestParams.optString("content");        Toast.makeText(jsBridge.getActivity(), content, Toast.LENGTH_LONG).show();        //回调JS        jsBridge.reportSuccess(callId);    }}

1.6 jsapi处理完逻辑后,将结果回调给js

    /**     * 回调JS     *     * @param callID 请求ID (由JS请求android端时带过来的请求ID)     * @param type   JSAPI执行成功与否     * @param params 回传参数     */    private void callbackJS(long callID, JSCallbackType type, String params) {        try {            if (callID < 0) {                return;            }            //组装回调js            StringBuilder js = new StringBuilder("javascript:");            js.append(MY_JS_BRIDGE);            js.append(".callbackFromNative(");            js.append(callID);            js.append(",");            js.append(type.getValue());            if (TextUtils.isEmpty(params)) {                js.append(",{});");            } else {                js.append(",");                js.append(params);                js.append(");");            }            String callbackJS = js.toString();            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {                //4.4及以上使用evaluateJavascript                this.mWebView.evaluateJavascript(callbackJS, null);            } else {                this.mWebView.loadUrl(callbackJS);            }            LogUtils.d(TAG, "callbackJS : " + callbackJS);        } catch (Exception e) {            //ignore        }    }

1.7 js端使用alert方式调用android接口:

var json = JSON.stringify({"content":"js call native!"});alert("myjsbridge:///request?class=JSUIControl&method=showToast¶ms="+ encodeURIComponent(json)+"&callId=1");

使用:

//1.实例化JSBridge,配置WebViewJSBridge jsBridge = new JSBridge(this, webview);jsBridge.configWebView();//2.WebView 加载网页资源webview.loadUrl("file:///android_asset/demo.html");

然后结合业务,自定义jsapi

完整项目:https://github.com/snailycy/android_jsbridge

更多相关文章

  1. Android P(api28) 不支持 http 协议解决方法
  2. Android 模拟器创建参数说明
  3. 参数设置
  4. android图片压缩质量参数Bitmap.Config RGB_565等的含义
  5. android中一些配置文件的参数的意义
  6. Android通过http协议POST传输方式(输出流提交到服务端)
  7. Andriod AOA协议通信总结
  8. Android sdk tool android 命令参数
  9. Android shape 参数

随机推荐

  1. android——单点触控移动,多点触控放大缩
  2. Android(安卓)SQLite数据库操作代码类分
  3. 完整版MVP框架
  4. android 编写自己的异常捕获类
  5. 挨踢人的脚步(2015.11.04)
  6. Android(安卓)时间日期选择器
  7. Android(安卓)-- 编辑框更改样式
  8. android 一个activity跳转另一个activity
  9. 85 Android(安卓)ListView 和 ScrollView
  10. Android获取移动设备IP地址