完整项目: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 安卓创建文件夹
  2. 三步搞定:Vue.js调用Android原生方法
  3. 调用Android摄像头与打开相册
  4. android SubscriptionInfo更新流程
  5. [转]Android事件处理
  6. ch026 Android(安卓)Socket
  7. Android调用WebService系列之KSoap2对象解析
  8. Android(安卓)测试工具集02
  9. 安卓调用键盘回车键做保存或调用搜索键执行操作

随机推荐

  1. Android的基本概念的小整理(二)
  2. 【OSC手机App技术解析】- 集成新浪微博An
  3. android系统学习笔记三
  4. 深入探讨Android----必不可少的高级功能
  5. 一个轻量级、高可用性的 Android 版本更
  6. Android中图像变换Matrix的原理应用
  7. 基于ffmpeg+opengl+opensl es的android视
  8. Android蓝牙开发简介
  9. 提升Android开发效率的最佳实践
  10. Android中添加自定义按键 ---- 非标准做