WebView 上傳圖片, 想必很多人都碰到過這樣的場景. 而且 WebView 在4.4前后的區(qū)別非常大, 比如對URL跳轉(zhuǎn)的格式, 對JS的注入聲明等等, 4.4以后的WebView 已經(jīng)是chromium內(nèi)核, 有多強大就無需我贅述. 說這些, 其實也是為了說明也因為WebView的前后變化太大了, 所以在低版本和版本上, WebView上傳文件的方式都略有不同, 而且在安卓4.4.4的一些設(shè)備上難以保證所有機型都成功.
實現(xiàn)過程:
在4.4之前, WebView的webkit中支持openFileChooser. 當(dāng)WebView加載一個HTML頁面, 點擊按鈕需要模擬form提交的方式去上傳文件時, 就會回調(diào)
openFileChooser(...)
方法. 然后在這個方法里接收并處理參數(shù)ValueCallback <uri> uploadMsg. 里面的 uri 就是所從本地選擇的文件路徑.
然后通過Intent的startActivityForResult(...) 方法跳轉(zhuǎn)到系統(tǒng)選擇文件的界面進行文件選擇, 最后在
onActivityResult(int requestCode, int resultCode, Intent data)
方法中獲取 data中的字符串路徑, 并轉(zhuǎn)換成Uri格式, 并傳給uploadMsg 即可, 類似:
String sourcePath = ImageUtil.retrievePath(this, mSourceIntent, data);
if (TextUtils.isEmpty(sourcePath) || !new File(sourcePath).exists()) {
Log.e(TAG, "sourcePath empty or not exists.");
break;
}
Uri uri = Uri.fromFile(new File(sourcePath));
mUploadMsg.onReceiveValue(uri);
這樣, 接下來的上傳工作, WebView會自動完成. 當(dāng)然, 這是順利的流程, 如果 onActivityResult(...) 中返回的 resultcode 不等于 Activity.RESULT_OK , 也要做一點處理, 不然再去點擊第二次上傳文件時是沒有反應(yīng)的. 類似這樣:
if (resultCode != Activity.RESULT_OK) {
if (mUploadMsg != null) {
mUploadMsg.onReceiveValue(null);
}
return;
}
傳個 null 即可.
OK, 上面就是4.4 以前的實現(xiàn)過程, 上面提及的代碼在下載的demo里會有, 為保證篇幅不會放在文章里. 那么5.0及以上的sdk變動時, webkit不再支持
openFileChooser(...)
而是提供了一個代替的方法:
public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> filePathCallback,
FileChooserParams fileChooserParams) {
return false;
}
這個方法的參數(shù)跟 openFileChooser(...) 方法很像, 其實作用都是類似的, 只是 從
ValueCallback <uri> uploadMsg
變成了
ValueCallback<Uri[]> filePathCallback, 還多了FileChooserParams類型參數(shù). fileChooserParams 其實是一個屬性封裝的參數(shù), 里面包含了acceptType, title等這樣的文件屬性, 名稱等信息.
所以, onShowFileChooser(...) 的使用方法跟 openFileChooser(...) 是很類似的, 這里通過 onActivityResult(...) 看兩者的使用區(qū)別:
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode != Activity.RESULT_OK) {
if (mUploadMsg != null) {
mUploadMsg.onReceiveValue(null);
}
if (mUploadMsgForAndroid5 != null) { // for android 5.0+
mUploadMsgForAndroid5.onReceiveValue(null);
}
return;
}
switch (requestCode) {
case REQUEST_CODE_IMAGE_CAPTURE:
case REQUEST_CODE_PICK_IMAGE: {
try {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
if (mUploadMsg == null) {
return;
}
String sourcePath = ImageUtil.retrievePath(this, mSourceIntent, data);
if (TextUtils.isEmpty(sourcePath) || !new File(sourcePath).exists()) {
Log.e(TAG, "sourcePath empty or not exists.");
break;
}
Uri uri = Uri.fromFile(new File(sourcePath));
mUploadMsg.onReceiveValue(uri);
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
if (mUploadMsgForAndroid5 == null) { // for android 5.0+
return;
}
String sourcePath = ImageUtil.retrievePath(this, mSourceIntent, data);
if (TextUtils.isEmpty(sourcePath) || !new File(sourcePath).exists()) {
Log.e(TAG, "sourcePath empty or not exists.");
break;
}
Uri uri = Uri.fromFile(new File(sourcePath));
mUploadMsgForAndroid5.onReceiveValue(new Uri[]{uri});
}
} catch (Exception e) {
e.printStackTrace();
}
break;
}
}
}
主要是針對 5.0前后的系統(tǒng)做了一些區(qū)別處理, 其他無大異.
測試說明
這里要特別說明的是, 經(jīng)過我測試9部安卓手機, 從4.2 到6.0.1, 有8部都是正常使用. 其中包含 一部Android 4.4.2系統(tǒng)的手機 和 兩部Android 4.4.4的手機, 發(fā)現(xiàn)在魅藍note(4.4.4)上面是無法使用的, 因為4.4 Kitkat中webview是一個有點奇葩的存在, 問題這里不贅述, 有興趣可以自行了解.
提高兼容性的解決方案:
- 使用加強版的WebView, cordova , 可以考慮編譯這個項目獲得jar包, 然后導(dǎo)入項目中使用它的WebView組件.
- 也可以通過JS調(diào)用本地的方法自行實現(xiàn)上傳.
以上兩個方法的兼容性都相當(dāng)不錯, 可自行嘗試.
可能導(dǎo)致失敗的原因
如果選擇文件到上傳文件的過程中失敗, 有可能是以下原因?qū)е碌?
- 文件的路徑包含中文. (9部設(shè)備中, vivo X6D不支持中文路徑包含中文)
- 手機系統(tǒng)是Android 6.0以上 (API >= 23), 且沒有獲得文件和攝像頭權(quán)限.
如果你的項目中還兼容到4.0以下的版本, build.gradle 配置文件中的compileSdkVersion 和 targetSdkVersion 是16甚至更低, 那么恭喜你, 直接使用
openFileChooser(...)
這種處理方法即可.
參考文章:
WebView File Upload Over Kitkat
HTML file input in android webview (android 4.4, kitkat)
CORDOVA Android WebViews
使用Cordova來解決HTML5制作的WebView手機不兼容的問題
android4.4webview支持openFileChooser文件/照片上傳
Android使用WebView從相冊/拍照中添加圖片
測試設(shè)備列表
- 中移動 CM601 (4.2.2)
- 華為榮耀6 H60-L01 (4.4.2)
- 華為榮耀暢玩4X Che1-CL20 (4.4.4)
- 魅藍note (4.4.4)
- 聯(lián)想K50-t5 (5.0)
- 魅藍note3 (5.1)
- vivo X6D (5.1)
- 小米note (6.0.1)
- 華為mate8 (6.0.1)
- 三星Galaxy S6 SM-G9200 (6.0.1)
下面附上測試部分測試手機圖, 由于拿了真實項目的地址做測試, 這里做了一些可愛的馬賽克處理 請諒解諒解~