最近公司项目里线上用户反馈出一个bug,介入的第三方平台中有个添加图片的功能,当点击H5中的按钮的时候,调不起本地文件管理器,在不少手机上都出现这种状况javascript
刨除定制化的webview来讲,原生webview是支持上传文件的。可是众多版本的迭代扩展,api参数也不同。通常拿到上传文件的需求时,你们都会照搬android brower的代码(聪明),api以下:html
// Android > 4.1.1 调用这个方法
public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType, String capture) {
LogUtils.d("openFileChooser 4.1.1 = ");
}
// 3.0 + 调用这个方法
public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType) {
LogUtils.d("openFileChooser 3.0 = ");
}
// Android < 3.0 调用这个方法
public void openFileChooser(ValueCallback<Uri> uploadMsg) {
LogUtils.d("openFileChooser < 3.0 = ");
}复制代码
5.0以后,系统提供了onShowFileChooser来让咱们实现选择文件的方法。前端
看了Sam的文章知道了这点:Samjava
以后,本觉得没有问题了,测试的时候发现,坑又来了。android
咱们能够看出,在这个功能上,有很明显的api升级痕迹,在试过众多手机以后,发现,4.4.0到4.4.2的系统没法调用这个api,固然也无从上传文件了,是怎么回事?ios
在这篇博客找到了详细的答案:穿衣助手技术博客web
原来google在4.4更改webkit内核为chromium以后,把这个api删除了!通常升级api,都会保留对原有api的支持,@deprecated掉旧的api,加入新的api,可是google却2个都没作,开发团队解释,咱们正在开发一个新的共有的api,这个api会更好,咱们会在正式版本上推出。结果呢,在4.4.3版本,他又把这个api加回来了json
因而怎么解决呢,网络上大多都放弃或是没有解决方案了,太过于麻烦,有这么三个方式:
参考这个,不过并无给出具体的代码,只有思路,而且只有第三个思路是较靠谱的api
第一种,H5直接使用新的video标签经过获取navigator的getUserMedia来获取视频流stream中截取一张图的方式来实现,不过这种方式在mobile上的支持比较晚。其中,android是从Android5.0才开始支持,ios未知。因此这种实现思路不作考虑。服务器
第二种,H5直接用之前Html旧有的input标签来实现。其中这种方式在ios支持上还不错,在android上的支持则不怎么使人满意。由于它直接涉及到了webkit在android各个平台不一样的实现方式,有很大的风险性。可是,出于方便让ios能直接调用的缘由这个方式的可行性仍是很大的。固然,问题并不是不能解决,这个下面再讲。
第三种,H5直接利用js和本地进行交互来实现。这种方式的采用很成功的例子就是微信公众帐号的实现,它经过实现一套js库来支持网页的各类调用
关于第三种方式的解决方案以下:
用js调用的本地方法以下:
final class ModuleJavaScriptInterface {
ModuleJavaScriptInterface() {
}
@JavascriptInterface
public void finishWebview(String json) {
if (!TextUtils.isEmpty(json)) {
Toast.makeText(BrowserActivity.this, "json= " + json, Toast.LENGTH_SHORT).show();
}
}
@JavascriptInterface
public void uploadImage() {
Toast.makeText(BrowserActivity.this, "upload ", Toast.LENGTH_SHORT).show();
//打开相册
Intent i = new Intent(Intent.ACTION_GET_CONTENT);
i.addCategory(Intent.CATEGORY_OPENABLE);
i.setType("*/*");
startActivityForResult(Intent.createChooser(i, "File Chooser"), KITKAT_RESULTCODE);
/* 在onActivityResult中 KITKAT_RESULTCODE 1 上传图片 2 上传成功后 将服务器返回的URL 返回给 js : UploadedFileName String UploadedFileName = ""; mWebView.loadUrl("javascript:CheckImage('" + UploadedFileName + "')"); */
}
}复制代码
以前项目里面已经处理好了,因此并无显现出来,以下:
调用系统app选择文件的时候,若弹出选择框,cancel掉选择框以后,发现webview无响应了,没法刷新,加载,点击,甚至退出这个activity也没法加载!后果很严重~
缘由是当你选择上传文件的时候,webview的ValueCallback对象(就是选择图片的回调)会持有这个webview,在没有收到回调以前,你没法对这个webview作任何的操做!
知道缘由以后,就很好解决了,若是cancel了,那么直接调用该对象的onReceiveValue()方法,传入null便可,webview就能够正常操做了
最后给出剩下的代码事例:
public class SafeWebViewClient extends WebViewClient {
@Override
public void onProgressChanged(WebView view, int newProgress) {
super.onProgressChanged(view, newProgress);
activity.mWebLoadingProgressBar.setProgress(newProgress);
if (newProgress >= 90 && activity.mWebLoadingProgressBar.getVisibility() == View.VISIBLE) {
activity.mWebLoadingProgressBar.setVisibility(View.GONE);
}
}
// For Android < 3.0
public void openFileChooser(ValueCallback<Uri> uploadMsg) {
activity.mUploadMessage = uploadMsg;
Intent i = new Intent(Intent.ACTION_GET_CONTENT);
i.addCategory(Intent.CATEGORY_OPENABLE);
i.setType("image/*");
activity.startActivityForResult(Intent.createChooser(i, "File Chooser"), activity.FILECHOOSER_RESULTCODE);
}
// For Android 3.0+
public void openFileChooser(ValueCallback uploadMsg, String acceptType) {
activity.mUploadMessage = uploadMsg;
Intent i = new Intent(Intent.ACTION_GET_CONTENT);
i.addCategory(Intent.CATEGORY_OPENABLE);
i.setType("*/*");
activity.startActivityForResult(Intent.createChooser(i, "File Browser"), activity.FILECHOOSER_RESULTCODE);
}
//For Android 4.1
public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType, String capture) {
activity.mUploadMessage = uploadMsg;
Intent i = new Intent(Intent.ACTION_GET_CONTENT);
i.addCategory(Intent.CATEGORY_OPENABLE);
i.setType("image/*");
activity.startActivityForResult(Intent.createChooser(i, "File Chooser"), activity.FILECHOOSER_RESULTCODE);
}
//For Android 5.0
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> filePathCallback, FileChooserParams fileChooserParams) {
// make sure there is no existing message
if (activity.uploadMessage != null) {
activity.uploadMessage.onReceiveValue(null);
activity.uploadMessage = null;
}
activity.uploadMessage = filePathCallback;
Intent intent = fileChooserParams.createIntent();
try {
activity.startActivityForResult(intent, activity.REQUEST_SELECT_FILE);
} catch (ActivityNotFoundException e) {
activity.uploadMessage = null;
return false;
}
return true;
}
}复制代码
选中图片以后走:
public void onActivityResult(int requestCode, int resultCode, Intent intent) {
if (requestCode == FILECHOOSER_RESULTCODE) {
if (null == mUploadMessage) return;
Uri result = intent == null || resultCode != RESULT_OK ? null : intent.getData();
mUploadMessage.onReceiveValue(result);
mUploadMessage = null;
} else if (requestCode == REQUEST_SELECT_FILE) {
if (uploadMessage == null) return;
uploadMessage.onReceiveValue(WebChromeClient.FileChooserParams.parseResult(resultCode, intent));
uploadMessage = null;
}复制代码
Thanks && END