Android-WebView-解決對選擇檔案 input type="file"無響應
發現一個 WebView 的坑:
上個周,專案中有需要接入一個 H5 頁面,H5 中有上傳圖片的功能,接入測試的時候,發現 iOS 端正常,但是所有的 Android 手機在點選上傳圖片的按鈕時,都毫無反應 。當時我的表情是這樣的 (˶‾᷄ ⁻̫ ‾᷅˵) 。
問題原因:
原因是 H5 訪問本地檔案的時候,使用的<input type="file">
,WebView 出於安全性的考慮,限制了以上操作。
解決方法:
重寫 WebviewChromeClient 中的 openFileChooser() 和 onShowFileChooser()方法響應<input type="file">
邏輯分析
首先明確下,我需要做的工作有:
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 專案地址:
參考資料
歡迎關注博主的微信公眾號,快快加入哦,期待與你一起成長!