此文章发布于61
个月前,部分信息可能已经过时
,请自行斟酌确认。
Andrid WebView 不支持文件多选
之前使用 Vue
开发了一个 H5
移动端项目,其中有图片上传功能,可拍照上传也可选择文件上传,现在想增加批量多选文件上传,然后发现 Android
竟然不支持 input
的 multiple
属性。
网上一翻搜索得出以下结论:如果只是开发 H5 页面,那么很遗憾无法解决。
参考:https://segmentfault.com/q/1010000002739580
Android web对于input-file的支持不太好, 到了android 4.4是连选择文件的窗口都打不开....
这个如果你是app里面嵌入webview,建议上传文件这一环节交给原生去做,原生上传好文件给到web文件信息.
如果是纯webapp的话,微信可以用公众平台提供的js api,里面有上传图片的接口.其它的web就没什么好的方式了.
解决方案
如果是自己开发了 Android 原生应用,那可以通过自定义 WebView 来实现,还好我的 H5 页面是嵌入在原生应用中运行的。
核心代码如下:
//上传文件相关变量
private Uri mImageUri;
private ValueCallback<Uri> mUploadMessage;
private ValueCallback<Uri[]> mUploadCallbackAboveL; //Android 5.0+
private static final int REQUEST_CODE_SELECT_FILE = 2;
/**
* 文件选择返回结果,Android L 以上用
*
* @param requestCode
* @param resultCode
* @param intent
*/
@SuppressWarnings("null")
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
private void onActivityResultAboveL(int requestCode, int resultCode, Intent intent) {
if (requestCode != REQUEST_CODE_SELECT_FILE || mUploadCallbackAboveL == null) {
return;
}
Uri[] results = null;
if (resultCode == Activity.RESULT_OK) {
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++) {
results[i] = clipData.getItemAt(i).getUri();
}
} else if (dataString != null) {
results = new Uri[]{Uri.parse(dataString)};
}
}
if (results == null) {
results = new Uri[]{mImageUri};
}
}
mUploadCallbackAboveL.onReceiveValue(results);
mUploadCallbackAboveL = null;
}
/**
* 初始化webView
*/
private void initWebView() {
mWebView = findViewById(R.id.webView);
mWebView.setDefaultHandler(new DefaultHandler());
mWebView.getSettings().setJavaScriptEnabled(true);
mWebView.getSettings().setDomStorageEnabled(true);
if (Build.VERSION.SDK_INT >= 21) {
//android 5.0 以上允许同时加载 http 和 https
mWebView.getSettings().setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW);
}
//TODO:临时不用缓存,防止服务端更新后客户端仍加载旧页面
mWebView.getSettings().setCacheMode(WebSettings.LOAD_NO_CACHE);
deleteDatabase("WebView.db");
deleteDatabase("WebViewCache.db");
mWebView.clearCache(true);
mWebView.clearFormData();
getCacheDir().delete(); //清空缓存目录;
mWebView.setWebChromeClient(new WebChromeClient() {
/** 下面的几个方法用于解决web中type="file"的按钮不能选择文件的问题 **/
//Android 3.0以下
protected void openFileChooser(ValueCallback<Uri> uploadMsg) {
mUploadMessage = uploadMsg;
takeImg();
}
//Android 3.0+,android 4.0 以下
protected void openFileChooser(ValueCallback uploadMsg, String acceptType) {
mUploadMessage = uploadMsg;
takeImg();
}
//Android 4.0-4.3
protected void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType, String capture) {
mUploadMessage = uploadMsg;
takeImg();
}
//Android 4.4 无方法,囧~~
//Android 5.0+
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> filePathCallback, FileChooserParams fileChooserParams) {
if (mUploadCallbackAboveL != null) {
mUploadCallbackAboveL.onReceiveValue(null);
mUploadCallbackAboveL = null;
}
mUploadCallbackAboveL = filePathCallback;
takeImg();
return true;
}
});
mWebView.loadUrl(mUrl);
//注册供js调用的方法
registerJsMethod();
//发送消息给js
mWebView.send("hello");
}
/**
* 拍照或选择照片(android L 及以上支持多选)
*/
private void takeImg() {
//创建图片存储目录及生成文件名,如:/storage/emulated/0/Pictures/Temp/IMG_20180809124757356.jpg
File imageStorageDir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), "Temp");
if (!imageStorageDir.exists()) {
imageStorageDir.mkdirs();
}
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddhhmmssSSS");
String dateString = sdf.format(new Date());
File file = new File(imageStorageDir + File.separator + "IMG_" + dateString + ".jpg");
mImageUri = Uri.fromFile(file);
//遍历所有相机应用
final List<Intent> cameraIntents = new ArrayList<>();
final Intent captureIntent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
final PackageManager packageManager = getPackageManager();
final List<ResolveInfo> listCam = packageManager.queryIntentActivities(captureIntent, 0);
for (ResolveInfo res : listCam) {
final String packageName = res.activityInfo.packageName;
final Intent i = new Intent(captureIntent);
i.setComponent(new ComponentName(res.activityInfo.packageName, res.activityInfo.name));
i.setPackage(packageName);
i.putExtra(MediaStore.EXTRA_OUTPUT, mImageUri);
i.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true); //多选
cameraIntents.add(i);
}
//浏览图片Intent+所有相机应用Intent
Intent i = new Intent(Intent.ACTION_GET_CONTENT);
i.addCategory(Intent.CATEGORY_OPENABLE);
i.setType("image/*");
i.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true); //多选
Intent chooserIntent = Intent.createChooser(i, "选择图片或相机拍摄");
chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, cameraIntents.toArray(new Parcelable[]{}));
//打开浏览或相机
startActivityForResult(chooserIntent, REQUEST_CODE_SELECT_FILE);
}