我有一个使用cordova和angularjs构建的混合应用程序,对于Android我使用人行横道运行应用程序。
我一直在网上搜索html5文件输入的解决方案,以允许选择多个文件。
我正在使用以下元素进行文件选择:
<input type="file" multiple="multiple" name="files[]" />
我正在运行Android Lollipop版本5.1.1和Crosswalk版本20,我已经使用Crosswalk版本18和19进行了测试。 Chrome已安装在运行最新版本的设备上,但我认为这不会产生任何影响。
当我点击上面的输入元素时,我得到了预期的对话框,要求我从我的文档或相机中进行选择。如果我选择从我的文档中选择,那么我只能选择单个文件,在这种情况下是图像。对于我可以从中选择图像的每个应用程序都是如此,因此默认的Android“图像”,“视频”,“音频”等以及Google照片等外部应用程序 - 所有这些只允许我一次选择一个文件。
在下面的图像中,您可以看到列出的文件,长按每个图块不会将文件添加到多个选择中。
这适用于App的IOS版本。
在深入了解我可以在网上找到的所有材料后,似乎Android 5+运行Chrome 49+支持多重属性。
我不确定这是一个人行横道浏览器实现还是Android操作系统问题,还是其他什么?任何人都可以建议。
编辑
只是为了确认这与使用或不使用Crosswalk无效。
经过数周的努力解决这个问题,我终于开始工作了(没有Crosswalk的Cordova)。这是在Windows中使用Cordova Tools完成的,所以请原谅下面的文件规范。
步骤1:将platforms \ Android \ CordovaLib \ AndroidManifest.xml中的minSdkVersion更改为21说明:在LOLLIPOP(API 21)中引入了onShowFileChooser
API。它允许返回url[]
而不是url
在早期API版本中返回的showFileChooser
。仅在将API更改为21或更高时才会调用此方法。
第2步:更新/替换onActivityResult
方法以检索多个文件。使用fileChooserParams
创建intent后添加以下内容以允许选择多个文件:
intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
位置:platforms \ android \ CordovaLib \ src \ org \ apache \ cordova \ engine \ SystemWebChromeClient.java
第3步:使用onActivityResult
更新相应的intent.getClipData()
方法以返回多个网址。
注意事项:
最终守则:
Uri photoUri;
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
@Override
public boolean onShowFileChooser(WebView webView, final ValueCallback<Uri[]> filePathsCallback, final WebChromeClient.FileChooserParams fileChooserParams) {
// Check and use MIME Type.
String mimeType = "*/*";
int ACTION_CODE = FILECHOOSER_RESULTCODE;
try {
if (fileChooserParams.getAcceptTypes().length > 0) {
mimeType = fileChooserParams.getAcceptTypes()[0];
} else {
mimeType = "*/*";
}
} catch (Exception e) {
mimeType = "*/*";
};
// Check if Mutiple is specified
Boolean selectMultiple = false;
if (fileChooserParams.getMode() == WebChromeClient.FileChooserParams.MODE_OPEN_MULTIPLE) {
selectMultiple = true;
};
Intent intent = new Intent();
intent.setAction(Intent.ACTION_GET_CONTENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
if (selectMultiple) { intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true); };
intent.setType(mimeType);
ACTION_CODE = FILECHOOSER_RESULTCODE;
final Intent chooserIntent = Intent.createChooser(intent, "Select Source");
// Add camera intent to the chooser if image and send URI to return full image
if (mimeType.equals("image/*")) {
photoUri = null;
try {
File photoFile = createImageFile();
photoUri = Uri.fromFile(photoFile);
}
catch (Exception ex) {
photoUri = null;
}
if (photoUri != null) {
Intent camIntent = new Intent();
camIntent.setAction(MediaStore.ACTION_IMAGE_CAPTURE);
camIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoUri);
camIntent.putExtra("return-data", true);
chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, new Intent [] {camIntent} );
}
}
try {
parentEngine.cordova.startActivityForResult(new CordovaPlugin() {
@Override
public void onActivityResult(int requestCode, int resultCode, Intent intent) {
if (resultCode == Activity.RESULT_OK && intent != null) {
if (intent.getData() != null)
{
Uri[] result = WebChromeClient.FileChooserParams.parseResult(resultCode, intent);
filePathsCallback.onReceiveValue(result);
}
else
{
if (intent.getClipData() != null) {
final int numSelectedFiles = intent.getClipData().getItemCount();
Uri[] result = new Uri[numSelectedFiles];
for (int i = 0; i < numSelectedFiles; i++) {
result[i] = intent.getClipData().getItemAt(i).getUri();
}
filePathsCallback.onReceiveValue(result);
}
else {
filePathsCallback.onReceiveValue(null);
}
}
}
else if(resultCode == Activity.RESULT_OK && (intent == null || intent.getData() == null )) {
Uri[] result = new Uri[1];
result[0] = photoUri;
filePathsCallback.onReceiveValue(result);
} else {
filePathsCallback.onReceiveValue(null);
}
}
}, chooserIntent, ACTION_CODE);
} catch (ActivityNotFoundException e) {
Log.w("No activity found to handle file chooser intent.", e);
filePathsCallback.onReceiveValue(null);
}
return true;
}