1. 程式人生 > >Android-WebView-解決對選擇檔案 input type="file"無響應

Android-WebView-解決對選擇檔案 input type="file"無響應

發現一個 WebView 的坑:

上個周,專案中有需要接入一個 H5 頁面,H5 中有上傳圖片的功能,接入測試的時候,發現 iOS 端正常,但是所有的 Android 手機在點選上傳圖片的按鈕時,都毫無反應 。當時我的表情是這樣的 (˶‾᷄ ⁻̫ ‾᷅˵) 。

問題原因:

原因是 H5 訪問本地檔案的時候,使用的<input type="file"> ,WebView 出於安全性的考慮,限制了以上操作。

解決方法:

重寫 WebviewChromeClient 中的 openFileChooser() 和 onShowFileChooser()方法響應<input type="file">

,然後使用原生程式碼來實現呼叫本地相簿和拍照的功能,最後在 onActiivtyResult 把選擇的圖片 URI 回傳給 WebviewChromeClient。

邏輯分析

首先明確下,我需要做的工作有:

1.彈出對話方塊選擇相機或相簿
2.呼叫系統相簿的實現程式碼
3.呼叫系統相機拍照的實現程式碼
4.需要相容 6.0 的動態許可權問題和 7.0 的檔案管理問題。
5.相機拍照後的圖片上傳後要進行刪除,以免佔用手機儲存空間

列下來覺得還是蠻多的。

博主實現完 Demo,並扔給你一段核心程式碼

WebviewChromeClient 中重寫方法響應 <input type="file">

4.1以上系統,使用 openFileChooser() ,該方法5.0已經被廢棄

5.0以上系統,使用 onShowFileChooser()

 mWebView.setWebChromeClient(new WebChromeClient() {
            //For Android  >= 5.0
            @Override
            public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> filePathCallback, FileChooserParams fileChooserParams) {

                uploadMessageAboveL = filePathCallback;
                //呼叫系統相機或者相簿
uploadPicture(); return true; } //For Android >= 4.1 public void openFileChooser(ValueCallback<Uri> valueCallback, String acceptType, String capture) uploadMessage = valueCallback; //呼叫系統相機或者相簿 uploadPicture(); } });

呼叫相機和相簿選擇圖片後,在 onActivityResult() 中將圖片的 Uri 通過 uploadMessage,5.0以上用 uploadMessageAboveL,使用 onReceiveValue 回傳過去。

這裡需要注意的是,當取消拍照或者未選擇照片的時候,uploadMessage 或者 uploadMessageAboveL 要返回 null.因為 valueCallback 持有的是 WebView,在 onReceiveValue 沒有回傳值的情況下,WebView 無法進行下一步操作,會導致取消選擇檔案後,點選 <input type = 'file'>,不會再響應。

@Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);

        if (requestCode == REQUEST_CODE_ALBUM || requestCode == REQUEST_CODE_CAMERA) {

            if (uploadMessage == null && uploadMessageAboveL == null) {
                return;
            }

            //取消拍照或者圖片選擇時,返回null,否則<input file> 就是沒有反應
            if (resultCode != RESULT_OK) {
                if (uploadMessage != null) {
                    uploadMessage.onReceiveValue(null);
                    uploadMessage = null;
                }
                if (uploadMessageAboveL != null) {
                    uploadMessageAboveL.onReceiveValue(null);
                    uploadMessageAboveL = null;

                }
            }

            //拍照成功和選取照片時
            if (resultCode == RESULT_OK) {
                Uri imageUri = null;

                switch (requestCode) {
                    case REQUEST_CODE_ALBUM:

                        if (data != null) {
                            imageUri = data.getData();
                        }

                        break;
                    case REQUEST_CODE_CAMERA:

                        if (!TextUtils.isEmpty(mCurrentPhotoPath)) {
                            File file = new File(mCurrentPhotoPath);
                            Uri localUri = Uri.fromFile(file);
                            Intent localIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, localUri);
                            sendBroadcast(localIntent);
                            imageUri = Uri.fromFile(file);
                            mLastPhothPath = mCurrentPhotoPath;
                        }
                        break;
                }


                //上傳檔案
                if (uploadMessage != null) {
                    uploadMessage.onReceiveValue(imageUri);
                    uploadMessage = null;
                }
                if (uploadMessageAboveL != null) {
                    uploadMessageAboveL.onReceiveValue(new Uri[]{imageUri});
                    uploadMessageAboveL = null;

                }

            }

        }


    }

最後不要忘記,在專案的混淆檔案中加入以下規則,保護 openFileChooser() 不被混淆,否則混淆後的包在 Android 4.X 不能正常使用。

#確保openFileChooser方法不被混淆
-keepclassmembers class * extends android.webkit.WebChromeClient{
 public void openFileChooser(...);
 }

呼叫系統相機和相簿的程式碼,因為動態許可權申請和檔案刪除的功能,搞的太長了,就不貼了。下面是完整程式碼的 github 專案地址:

參考資料


歡迎關注博主的微信公眾號,快快加入哦,期待與你一起成長!