1. 程式人生 > >Android WebView 踩過的坑

Android WebView 踩過的坑

首先wenview大家都知道的一些API
這裡寫圖片描述
這裡寫圖片描述

WebChromeClient是輔助WebView處理Javascript的對話方塊,網站圖示,網站title,載入進度等 :

onCloseWindow(關閉WebView)   

onCreateWindow()   

onJsAlert (WebView上alert是彈不出來東西的,需要定製你的WebChromeClient處理彈出)   

onJsPrompt   

onJsConfirm   

onProgressChanged   

onReceivedIcon   

onReceivedTitle 
  1. WebView 檔案上傳,直接看程式碼:
webView.setWebChromeClient(new MyWebChromeClient());
private ValueCallback<Uri[]> mUploadCallbackAboveL;
private ValueCallback<Uri> mUploadMessage;

private class MyWebChromeClient extends WebChromeClient {

        // For Android 3.0+
        public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType) {
            if
(mUploadMessage != null) return; mUploadMessage = uploadMsg; showPhotoView(); } // For Android < 3.0 public void openFileChooser(ValueCallback<Uri> uploadMsg) { openFileChooser(uploadMsg, ""); } // For Android > 4.1.1
public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType, String capture) { openFileChooser(uploadMsg, acceptType); } // For Android 5.0+ public boolean onShowFileChooser (WebView webView, ValueCallback<Uri[]> filePathCallback, WebChromeClient.FileChooserParams fileChooserParams) { if (mUploadCallbackAboveL != null){ return false; } mUploadCallbackAboveL = filePathCallback; showPhotoView(); return true; } }
 /**
     * 自定義的檔案選擇框,包括相機 相簿
     */
    private void showPhotoView() {
        photoSelectFragment = new PhotoSelectFragment();
        photoSelectFragment.setOnPhotoListItemClickListener(this);
        photoSelectFragment.setOnDismissListener(this);
        photoSelectFragment.show(getSupportFragmentManager(),
                "photoSelectFragment");
    }

當檔案選擇的dialog消失時或者取消時要呼叫以下程式碼,否則就會出現再次點選不再彈出選擇dialog:

/**
     * 重置 mUploadMessage
     */
    private void clearUploadCallBack(){
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {//5.0以下
            if (mUploadMessage != null){
                mUploadMessage.onReceiveValue(null);
                mUploadMessage = null;
            }

        }else {
            if(mUploadCallbackAboveL != null){
                mUploadCallbackAboveL.onReceiveValue(null);
                mUploadCallbackAboveL = null;
            }
        }
    }

2.WebView 圖片延遲載入:
有些頁面如果包含網路圖片,在移動裝置上我們等待載入圖片的時間可能會很長,所以我們需要讓圖片延時載入,這樣不影響我們載入頁面的速度,同樣程式碼說話:

定義變數:

boolean blockLoadingNetworkImage=false;

在WebView初始化的時候設定,就是這麼簡單就可以了:

blockLoadingNetworkImage = true;

webView.setWebViewClient(new WebViewClient() {
            @Override
            public boolean shouldOverrideUrlLoading(WebView view, String url) {
                //返回值是true的時候控制去WebView開啟,為false呼叫系統瀏覽器或第三方瀏覽器
                return true;
            }

            @Override
            public void onPageStarted(WebView view, String url, Bitmap favicon) {
                super.onPageStarted(view, url, favicon);
                if (!blockLoadingNetworkImage){
                    webView.getSettings().setBlockNetworkImage(true);
                }
            }

            @Override
            public void onPageFinished(WebView view, String url) {
                super.onPageFinished(view, url);
                if (blockLoadingNetworkImage){
                    webView.getSettings().setBlockNetworkImage(false);
                }
            }
        });

3.JS呼叫native:
js呼叫原生大概有兩種方法
1.擷取url,獲取指定的url,例如頁面上有個撥打電話的呼叫,我們就可以在wenview中這樣擷取:

webView.setWebViewClient(new WebViewClient() {
            @Override
            public boolean shouldOverrideUrlLoading(WebView view, String url) {
                //返回值是true的時候控制去WebView開啟,為false呼叫系統瀏覽器或第三方瀏覽器
                Log.e("zhaogl", url);
                if (url.startsWith("tel:")){//撥打電話
                    String[] ss = url.split(":");
                    if (ss.length > 1 && ss[1] != null){
                        CommonUtil.call(WebViewActivity.this,ss[1]);
                    }
                }else if (url.equalsIgnoreCase("http://www.baidu.com/")){
                    WebViewActivity.this.finish();
                }else {
                    view.loadUrl(url);
                }
                return true;
            }
        });

2.呼叫Java寫好的方法:
首先我們要定義一個方法給js呼叫,這裡我把這個方法封裝到一個類中:

public class InJavaScript {
    private static InJavaScript instance;

    public InJavaScript() {
    }

    public static InJavaScript getInstance() {
        if (instance == null){
            instance = new InJavaScript();
        }
        return instance;
    }

    /**
     * 分享
     * @param str  內容
     * @param targetUrl url
     */
    @JavascriptInterface
    public void runOnAndroidShare(String str,String targetUrl) {
        WebViewEvent event = new WebViewEvent();
        event.isShare = true;
        event.content = str;
        event.url = targetUrl;
        EventBus.getDefault().post(event);
    }

    /**
     * 關閉 window.close 不起作用,代替之
     */
    @JavascriptInterface
    public void closeWindowForAndroid(){
        WebViewEvent event = new WebViewEvent();
        event.isCloseWindow = true;
        EventBus.getDefault().post(event);
    }
}

寫好的java類及方法如果想讓js呼叫,還需要有如下設定:

webView.addJavascriptInterface(InJavaScript.getInstance(), "injs");

js中就可以用以下方式呼叫:

function sendToAndroid(){  
        window.injs.runOnAndroidShare(str,str);//呼叫android的函式  
}

注意,第二中方法在4.2以下版本存在js安全漏洞,但是目前市場上的安卓大部分都已經在4.2以上了,所以如果你的專案安全要求不是那麼高,可以正常使用。現在有很多第三方的框架解決這個問題,大家可以去自己查詢。

3.處理返回按鍵:

@Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if (keyCode == KeyEvent.KEYCODE_BACK && webView.canGoBack()) {
            if (photoSelectFragment != null){
                photoSelectFragment.dismiss();
                clearUploadCallBack();
            }
            webView.goBack();// 返回前一個頁面
            return true;
        }
        return super.onKeyDown(keyCode, event);
    }

整理出來的原始碼
原始碼下載