使用openFileChooser存在的问题。当弹出选择图片/相机框之后,取消选择,就再也不能点击选择按钮了。这篇文章是为了记录这一点,为验证整个流程部署了后端,但是由于很久没接触后端,后端代码是网上的列子,所以后端代码和部署就不说了。单纯的说下Android端的解决方案。
更新:Android5.0+的方法。
自定义两个文件:
/**
* 自定义
*
* @Author KenChung
*/
public class ReWebViewClient extends WebViewClient {
@Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
super.onPageStarted(view, url, favicon);
}
@Override
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
}
}
/**
* ReWebChomeClient
*
* @Author KenChung
*/
public class ReWebChomeClient extends WebChromeClient {
private OpenFileChooserCallBack mOpenFileChooserCallBack;
public ReWebChomeClient(OpenFileChooserCallBack openFileChooserCallBack) {
mOpenFileChooserCallBack = openFileChooserCallBack;
}
//For Android 3.0+
public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType) {
mOpenFileChooserCallBack.openFileChooserCallBack(uploadMsg, acceptType);
}
// For Android < 3.0
public void openFileChooser(ValueCallback<Uri> uploadMsg) {
openFileChooser(uploadMsg, "");
}
// For Android > 4.1.1
public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType, String capture) {
openFileChooser(uploadMsg, acceptType);
}
// For Android 5.0+
@Override
public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> filePathCallback, FileChooserParams
fileChooserParams) {
mOpenFileChooserCallBack.showFileChooserCallBack(filePathCallback);
return true;
}
public interface OpenFileChooserCallBack {
void openFileChooserCallBack(ValueCallback<Uri> uploadMsg, String acceptType);
void showFileChooserCallBack(ValueCallback<Uri[]> filePathCallback);
}
}
选择图片弹框使用AlertDialog:
public void showOptions() {
AlertDialog.Builder alertDialog = new AlertDialog.Builder(this);
alertDialog.setOnCancelListener(new ReOnCancelListener());
alertDialog.setTitle(R.string.options);
alertDialog.setItems(R.array.options, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
if (which == 0) {
mSourceIntent = ImageUtil.choosePicture();
startActivityForResult(mSourceIntent, REQUEST_CODE_PICK_IMAGE);
} else {
mSourceIntent = ImageUtil.takeBigPicture();
startActivityForResult(mSourceIntent, REQUEST_CODE_IMAGE_CAPTURE);
}
}
}
);
alertDialog.show();
}
关键代码:(这里的意思是取消弹框之后要告诉WebView不要再等待返回结果,设置为空就等于重置了状态)
private class ReOnCancelListener implements DialogInterface.OnCancelListener {
@Override
public void onCancel(DialogInterface dialogInterface) {
if (mUploadMsg != null) {
mUploadMsg.onReceiveValue(null);
mUploadMsg = null;
}
if (mUploadMsg5Plus != null) {
mUploadMsg5Plus.onReceiveValue(null);
mUploadMsg5Plus = null;
}
}
}
完整MainActivity:
/**
* WebViewUpload
*
* @Author KenChung
*/
public class MyActivity extends Activity implements ReWebChomeClient.OpenFileChooserCallBack {
private static final String TAG = "MyActivity";
private static final int REQUEST_CODE_PICK_IMAGE = 0;
private static final int REQUEST_CODE_IMAGE_CAPTURE = 1;
private WebView mWebView;
private Intent mSourceIntent;
private ValueCallback<Uri> mUploadMsg;
private ValueCallback<Uri[]> mUploadMsg5Plus;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mWebView = (WebView) findViewById(R.id.webview);
mWebView.setWebChromeClient(new ReWebChomeClient(this));
mWebView.setWebViewClient(new ReWebViewClient());
fixDirPath();
//这里加载自己部署的(也可加载本地资源)
mWebView.loadUrl("file:///android_asset/input.html");
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode != Activity.RESULT_OK) {
return;
}
switch (requestCode) {
case REQUEST_CODE_IMAGE_CAPTURE:
case REQUEST_CODE_PICK_IMAGE: {
try {
if (mUploadMsg == null && mUploadMsg5Plus == null) {
return;
}
String sourcePath = ImageUtil.retrievePath(this, mSourceIntent, data);
if (TextUtils.isEmpty(sourcePath) || !new File(sourcePath).exists()) {
Log.w(TAG, "sourcePath empty or not exists.");
break;
}
Uri uri = Uri.fromFile(new File(sourcePath));
if (mUploadMsg != null) {
mUploadMsg.onReceiveValue(uri);
mUploadMsg = null;
} else {
mUploadMsg5Plus.onReceiveValue(new Uri[]{uri});
mUploadMsg5Plus = null;
}
} catch (Exception e) {
e.printStackTrace();
}
break;
}
}
}
@Override
public void openFileChooserCallBack(ValueCallback<Uri> uploadMsg, String acceptType) {
mUploadMsg = uploadMsg;
showOptions();
}
@Override
public void showFileChooserCallBack(ValueCallback<Uri[]> filePathCallback) {
mUploadMsg5Plus = filePathCallback;
showOptions();
}
public void showOptions() {
AlertDialog.Builder alertDialog = new AlertDialog.Builder(this);
alertDialog.setOnCancelListener(new ReOnCancelListener());
alertDialog.setTitle(R.string.options);
alertDialog.setItems(R.array.options, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
if (which == 0) {
mSourceIntent = ImageUtil.choosePicture();
startActivityForResult(mSourceIntent, REQUEST_CODE_PICK_IMAGE);
} else {
mSourceIntent = ImageUtil.takeBigPicture(MyActivity.this);
startActivityForResult(mSourceIntent, REQUEST_CODE_IMAGE_CAPTURE);
}
}
});
alertDialog.show();
}
private void fixDirPath() {
String path = ImageUtil.getDirPath();
File file = new File(path);
if (!file.exists()) {
file.mkdirs();
}
}
private class ReOnCancelListener implements DialogInterface.OnCancelListener {
@Override
public void onCancel(DialogInterface dialogInterface) {
if (mUploadMsg != null) {
mUploadMsg.onReceiveValue(null);
mUploadMsg = null;
}
if (mUploadMsg5Plus != null) {
mUploadMsg5Plus.onReceiveValue(null);
mUploadMsg5Plus = null;
}
}
}
}
有些哥们反馈没有附上html无法测试,放上html到本地即可:input.html
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="user-scalable=no">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
</head>
<body>
<input id="input" type="file"/>
</body>
</html>
源码没有附上本地html,需自行创建。源码下载地址: CSDN下载