Android WebView與javaScript交互

操作前提
webview.getSettings().setJavaScriptEnabled(true);

通過webView調用JavaScript方法
webView.loadUrl("javascript:METHOD")
或者 webView.evaluateJavaScript("javascript:METHOD",CallBack) //只能在4.4以上調用,效率高,能拿到返回結果

loadUrl在4.4之前的系統中會導致網頁重載,4.4以後無影響
如果調用的方法有參數的話,javascript是弱類型,如果參數是字符串形式,則需要使用單引號’'進行包括,如果包含\之類的符號,則需要轉義,使用\

JavaScript調用Java方法
webView.addJavaScriptInterface("接口對象","接口名字"); //這個名字給js端當做對象來調用內部方法
然後在接口對象類裏面給所有JavaScript可以調用的Java方法添加@JavaScriptInterface註解,加註解是防止h5進行攻擊,因爲沒有註解的話,h5可以持有對象,可以調用對象的任何方法,私有的可以通過對象拿到Class進行反射調用

webview內存泄漏問題解決
在銷燬過程中需保證 先執行webView的onDetachedFromWindow 然後執行destroy()釋放webview
onDestroy()中

 if (mWebView != null) {
      ViewParent parent = mWebView.getParent();
      if (parent != null) {
         ((ViewGroup) parent).removeView(mWebView);
      }
      mWebView.removeAllViews();
      mWebView.destroy();  //如果只寫這一行代碼,則不能保證onDetachedFromWindo會執行, 導致內存泄漏,因爲這個方法內部判斷了if(!isDestroyed){執行釋放邏輯}
      mWebView = null;
   }

注:webview字體大小不隨系統字體大小解決方法 webSettings.setTextZoom(100);

JSBridge庫

下面是基於JSBridge庫的封裝

public abstract class BaseWebView extends BridgeWebView {
    public BaseWebView(Context context, AttributeSet attrs) {
        super(context, attrs);
        setWebAttr();
        registerDefaultHandlers();
    }

    public BaseWebView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        setWebAttr();
        registerDefaultHandlers();
    }

    public BaseWebView(Context context) {
        super(context);
        setWebAttr();
        registerDefaultHandlers();
    }

    protected void setWebAttr() {
        WebSettings settings = this.getSettings();
        settings.setDomStorageEnabled(true);
        setWebChromeClient(new WebChromeClient() {
            @Override
            public void onReceivedTitle(WebView view, String title) {
                BaseWebView.this.onReceivedTitle(title);
                super.onReceivedTitle(view, title);
            }

            @Override
            public void onProgressChanged(WebView view, int newProgress) {
                BaseWebView.this.onProgressChanged(newProgress);
                super.onProgressChanged(view, newProgress);
            }
        });
    }

    protected abstract void registerDefaultHandlers();

    protected abstract void onReceivedTitle(String title);

    protected abstract void onProgressChanged(int progress);
}
public class DefaultWebView extends BaseWebView implements OpenNativePageHandler.Callback {

    public interface Callback {
        boolean openNativePage(JSONObject param);

        void onReceivedError(WebView view);

        void onReceivedTitle(String title);

        void onProgressChanged(int progress);
    }

    public static abstract class SimpleCallBack implements Callback {
        public void onReceivedError(WebView view) {
        }

        public void onReceivedTitle(String title) {
        }

        public void onProgressChanged(int progress) {

        }
    }

    private static final String WEBVIEW_VERSION = "0";
    private Callback mCallback;

    public DefaultWebView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public DefaultWebView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    public DefaultWebView(Context context) {
        super(context);
    }

    public Callback getCallback() {
        return mCallback;
    }

    public void setCallback(Callback callback) {
        this.mCallback = callback;
    }

    @Override
    protected void registerDefaultHandlers() {
    	//這些是提前註冊好的handler,供h5在需要的時候調用
        this.registerHandler("getInfo", new GetInfoHandler());
        this.registerHandler("getLocation", new GetLocationHandler());
        this.registerHandler("openNativePage", new OpenNativePageHandler(this));
    }

    @Override
    protected void onReceivedTitle(String title) {
        if (mCallback != null) {
            mCallback.onReceivedTitle(title);
        }
    }

    @Override
    protected void onProgressChanged(int progress) {
        if (mCallback != null) {
            mCallback.onProgressChanged(progress);
        }
    }

    public Map<String, String> getDefaultHeaders() {
        Map<String, String> headers = new HashMap<>();
        JSONObject utk = new JSONObject();
        try {
            User user = ServerHandler.getCurrentUser();
            if (user != null) {
                Integer userId = user.getUserId();
                if (userId != null) {
                    utk.put("id", String.valueOf(userId));
                }
                String atk = user.getAtk();
                if (atk != null) {
                    utk.put("atk", atk);
                }
            }

            if (ColorVConst.DEVICE_ID != null) {
                utk.put("udid", ColorVConst.DEVICE_ID);
            }
            utk.put("webview_ver", WEBVIEW_VERSION);
        } catch (JSONException e) {
            e.printStackTrace();
        }

        headers.put("utk", utk.toString());
        return headers;
    }

    public void loadUrl(String url) {
        super.loadUrl(url, getDefaultHeaders());
    }

    @Override
    public boolean openNativePage(JSONObject param) {
        if (mCallback != null) {
            return mCallback.openNativePage(param);
        }
        return false;
    }

    @Override
    public boolean showMoreBtn(int type, boolean showMore) {
        if (mCallback != null) {
            return mCallback.showMoreBtn(type, showMore);
        }
        return false;
    }

    @Override
    protected BridgeWebViewClient generateBridgeWebViewClient() {
        return new MyBridgeWebViewClient(this);
    }

    class MyBridgeWebViewClient extends BridgeWebViewClient {
        public MyBridgeWebViewClient(BridgeWebView webView) {
            super(webView);
        }

        @Override
        public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) {
            super.onReceivedError(view, request, error);
            if (mCallback != null) {
                mCallback.onReceivedError(view);
            }
        }

        @Override
        public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
            super.onReceivedError(view, errorCode, description, failingUrl);
            if (mCallback != null) {
                mCallback.onReceivedError(view);
            }
        }

        @Override
        @TargetApi(Build.VERSION_CODES.LOLLIPOP)
        public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) {
            LogUtils.println("web view request url: " + request.getUrl());
            LogUtils.println("web view request url: " + request.getMethod());
            Map<String, String> headers = request.getRequestHeaders();
            if (headers != null && headers.size() > 0) {
                LogUtils.println("web view headers start-----------");
                for (String key : headers.keySet()) {
                    String value = headers.get(key);
                    LogUtils.println("web view header " + key + ": " + value);
                }
                LogUtils.println("web view headers end-----------");
            }
            return super.shouldInterceptRequest(view, request);
        }

        @Override
        public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
            LogUtils.println("web view request url: " + url);
            return super.shouldInterceptRequest(view, url);
        }
    }
}

public abstract class BaseHandler implements BridgeHandler {

    private static final String DEFAULT_ERROR_MESSAGE="出錯了";

    private static final String ERROR_MESSAGE_KEY = "error_message";
    private static final String ERROR_CODE_KEY = "error_code";

    protected void handlerError(String errorMsg,int errorCode, CallBackFunction function)
    {
        JSONObject jsonObject = new JSONObject();

        try {
            if (errorMsg != null) {
                jsonObject.put(ERROR_MESSAGE_KEY, errorMsg);
            }
            else {
                jsonObject.put(ERROR_MESSAGE_KEY,DEFAULT_ERROR_MESSAGE);
            }
            jsonObject.put(ERROR_CODE_KEY,errorCode);
        } catch (JSONException e) {
            e.printStackTrace();
        }

        if (function != null) {
            function.onCallBack(jsonObject.toString());
        }
    }

    protected void handlerError(String errorMsg,CallBackFunction function)
    {
        this.handlerError(errorMsg,0,function);
    }

    protected void handlerError(CallBackFunction function)
    {
        this.handlerError(null,0,function);
    }
}

public class GetInfoHandler extends BaseHandler {

    @Override
    public void handler(String data, CallBackFunction function) {
        JSONObject info = new JSONObject();
        try {
            //塞入數據
        } catch (Exception e) {
            e.printStackTrace();
            this.handlerError(e.getLocalizedMessage(),function);
            return;
        }

        function.onCallBack(info.toString());
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章