解決的問題
當(dāng)webview
與h5
交互時(shí)蒜魄,遇到選擇圖片的情況诬乞,如果使用了系統(tǒng)相冊因妙,默認(rèn)是選一張的,可是h5
的代碼是類似這樣附帶multiple
多選屬性:
<input type="file" id="myfileinput" multiple>
IOS
和Android
系統(tǒng)瀏覽器都可以識別并默認(rèn)能多選芜抒,偏偏Android webview
不爭氣
解決的方案1:手動讓系統(tǒng)相冊自帶多選(需要android5.0+)
系統(tǒng)相冊既然默認(rèn)是單選的,那肯定可以多選托启。直接上代碼:
/**
* android 5.0(含) 系統(tǒng)自帶的圖片選擇
*
*/
private void openFileChooseProcess5(ValueCallback<Uri[]> filePathCallback,WebChromeClient.FileChooserParams fileChooserParams) {
mValueCallback = filePathCallback;
Intent intent = new Intent(Intent.ACTION_PICK);
intent.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "image/*");
if (fileChooserParams != null && fileChooserParams.getMode() == WebChromeClient.FileChooserParams.MODE_OPEN_MULTIPLE) {
//關(guān)鍵在這
intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
}
startActivityForResult(intent, 0);
}
/**
* 5.0以下
*/
private void openFileChooseProcess(ValueCallback<Uri> uploadMsg) {
mUploadMsg = uploadMsg;
Intent i = new Intent(Intent.ACTION_GET_CONTENT);
i.addCategory(Intent.CATEGORY_OPENABLE);
i.setType("image/*");
startActivityForResult(Intent.createChooser(i, "Image Chooser"), 0);
}
注意這句intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
必須加宅倒,否則還是單選。
方法openFileChooseProcess5
須在WebChromeClient
的覆蓋方法onShowFileChooser
中調(diào)用,
具體代碼如下
// For Android 3.0+
public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType) {
openFileChooseProcess(uploadMsg);
}
// For Android < 3.0
public void openFileChooser(ValueCallback<Uri> uploadMsgs) {
openFileChooseProcess(uploadMsg);
}
// For Android > 4.1.1
// @Override
public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType, String capture) {
openFileChooseProcess(uploadMsg);
}
// For Android >= 5.0
@Override
public boolean onShowFileChooser(WebView webView,
ValueCallback<Uri[]> filePathCallback,
WebChromeClient.FileChooserParams fileChooserParams) {
openFileChooseProcess5(filePathCallback屯耸,fileChooserParams);
return true;
}
實(shí)現(xiàn)當(dāng)前Activity
的onActivityResult
方法拐迁,獲得選中的圖片并傳給h5
蹭劈,代碼如下:
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode == RESULT_CANCELED) {
if (mUploadMsg != null) {
mUploadMsg.onReceiveValue(null);
mUploadMsg = null;
}
if (mValueCallback != null) {
mValueCallback.onReceiveValue(null);
mValueCallback = null;
}
}
if (resultCode == Activity.RESULT_OK) {
switch (requestCode) {
case 0:
if (null == mUploadMsg && null == mValueCallback) {
return;
}
Uri result = data == null || resultCode != RESULT_OK ? null : data.getData();
if (mValueCallback != null) {
//處理相關(guān)數(shù)據(jù)
onActivityResultAboveL(data);
} else if (mUploadMsg != null) {
mUploadMsg.onReceiveValue(result);
}
break;
default:
break;
}
}
}
//選中圖片并傳給js
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
private void onActivityResultAboveL(Intent intent) {
Uri[] results = null;
if (intent != null) {
String dataString = intent.getDataString();
ClipData clipData = intent.getClipData();
if (clipData != null) {
results = new Uri[clipData.getItemCount()];
for (int i = 0; i < clipData.getItemCount(); i++) {
ClipData.Item item = clipData.getItemAt(i);
results[i] = item.getUri();
}
}
if (dataString != null) {
results = new Uri[]{Uri.parse(dataString)};
}
}
mValueCallback.onReceiveValue(results);
mValueCallback = null;
}
注意onActivityResultAboveL
方法的作用,多選的情況需要用到intent.getClipData()
獲取選中數(shù)據(jù)线召,在intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
這行代碼的第一個(gè)參數(shù)源碼里可以看到注釋上倒數(shù)第二行有標(biāo)記說明{@link #getClipData()}
/**
* Extra used to indicate that an intent can allow the user to select and
* return multiple items. This is a boolean extra; the default is false. If
* true, an implementation is allowed to present the user with a UI where
* they can pick multiple items that are all returned to the caller. When
* this happens, they should be returned as the {@link #getClipData()} part
* of the result Intent.
*
* @see #ACTION_GET_CONTENT
* @see #ACTION_OPEN_DOCUMENT
*/
public static final String EXTRA_ALLOW_MULTIPLE =
"android.intent.extra.ALLOW_MULTIPLE";
解決的方案2:自己寫一個(gè)圖片選擇器或者調(diào)用第三方圖片選擇器庫铺韧,并處理選擇回調(diào)
public void showOptions() {
//調(diào)用自己實(shí)現(xiàn)的圖片選擇器
ImageUtils.pictureMultiSelected(getActivity(), PictureConfig.CHOOSE_REQUEST, 9);
}
在上面的openFileChooser
和onShowFileChooser
中調(diào)用此方法诲侮。方法內(nèi)部的實(shí)現(xiàn)這里不貼了捧存,回調(diào)如下:
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode == RESULT_CANCELED) {
if (mUploadMsg != null) {
mUploadMsg.onReceiveValue(null);
mUploadMsg = null;
}
if (mValueCallback != null) {
mValueCallback.onReceiveValue(null);
mValueCallback = null;
}
}
if (resultCode == Activity.RESULT_OK) {
switch (requestCode) {
case PictureConfig.CHOOSE_REQUEST:
List<LocalMedia> selectList = PictureSelector.obtainMultipleResult(data);
try {
if (mUploadMsg != null) {
String path;
if (selectList.get(0).isCompressed()) {
LogUtils.e("getCompressPath) =" + selectList.get(0).getCompressPath());
path = selectList.get(0).getCompressPath();
} else {
path = selectList.get(0).getPath();
}
if (!CheckUtils.isAvailable(path) || !new File(path).exists()) {
LogUtils.e("sourcePath empty or not exists.");
break;
}
File file = new File(path);
Uri uri = Uri.fromFile(file);
mUploadMsg.onReceiveValue(uri);
mUploadMsg = null;
} else if (mValueCallback != null) {
Uri[] uris = new Uri[selectList.size()];
for (int i = 0; i < selectList.size(); i++) {
String path;
if (selectList.get(i).isCompressed()) {
LogUtils.e("getCompressPath) =" + selectList.get(i).getCompressPath());
path = selectList.get(i).getCompressPath();
} else {
path = selectList.get(i).getPath();
}
File file = new File(path);
uris[i] = Uri.fromFile(file);
}
if (uris.length > 0) {
mValueCallback.onReceiveValue(uris);
} else {
LogUtils.e("sourcePath empty or not exists.");
}
break;
}
} catch (Exception e) {
e.printStackTrace();
}
break;
default:
break;
}
}
}
總結(jié)和發(fā)散
兩種方法個(gè)人覺得第一種更省事,代碼量更小挖炬。
脫離webview
讯壶,其實(shí)很多地方我們也會用到多圖上傳的操作料仗,這時(shí)候如果不需要自定義UI、選擇數(shù)量限制等可以直接使用第一種方法比較省事