Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> android與js交互-jsbridge

android與js交互-jsbridge

編輯:關於Android編程

完整項目: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,配置WebView
JSBridge jsBridge = new JSBridge(this, webview);
jsBridge.configWebView();

//2.WebView 加載網頁資源
webview.loadUrl("file:///android_asset/demo.html");

然後結合業務,自定義jsapi

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

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved