Android WebView 上传文件支持全解析
默认情况下情况下,使用Android的WebView是不能够支持上传文件的。而这个,也是在我们的前端工程师告知之后才了解的。因为Android的每个版本WebView的实现有差异,因此需要对不同版本去适配。花了一点时间,参考别人的代码,这个问题已经解决,这里把我踩过的坑分享出来。 主要思路是重写WebChromeClient,然后在WebViewActivity中接收选择到的文件Uri,传给页面去上传就可以了。 创建一个WebViewActivity的内部类 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 public class XHSWebChromeClient extends WebChromeClient { // For Android 3.0+ public void openFileChooser(ValueCallback<Uri> uploadMsg) { CLog.i("UPFILE", "in openFile Uri Callback"); if (mUploadMessage != null) { mUploadMessage.onReceiveValue(null); } mUploadMessage = uploadMsg; Intent i = new Intent(Intent.ACTION_GET_CONTENT); i.addCategory(Intent.CATEGORY_OPENABLE); i.setType("*/*"); startActivityForResult(Intent.createChooser(i, "File Chooser"), FILECHOOSER_RESULTCODE); } // For Android 3.0+ public void openFileChooser(ValueCallback uploadMsg, String acceptType) { CLog.i("UPFILE", "in openFile Uri Callback has accept Type" + acceptType); if (mUploadMessage != null) { mUploadMessage.onReceiveValue(null); } mUploadMessage = uploadMsg; Intent i = new Intent(Intent.ACTION_GET_CONTENT); i.addCategory(Intent.CATEGORY_OPENABLE); String type = TextUtils.isEmpty(acceptType) ? "*/*" : acceptType; i.setType(type); startActivityForResult(Intent.createChooser(i, "File Chooser"), FILECHOOSER_RESULTCODE); } // For Android 4.1 public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType, String capture) { CLog.i("UPFILE", "in openFile Uri Callback has accept Type" + acceptType + "has capture" + capture); if (mUploadMessage != null) { mUploadMessage.onReceiveValue(null); } mUploadMessage = uploadMsg; Intent i = new Intent(Intent.ACTION_GET_CONTENT); i.addCategory(Intent.CATEGORY_OPENABLE); String type = TextUtils.isEmpty(acceptType) ? "*/*" : acceptType; i.setType(type); startActivityForResult(Intent.createChooser(i, "File Chooser"), FILECHOOSER_RESULTCODE); } //Android 5.0+ @Override @SuppressLint("NewApi") public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> filePathCallback, FileChooserParams fileChooserParams) { if (mUploadMessage != null) { mUploadMessage.onReceiveValue(null); } CLog.i("UPFILE", "file chooser params:" + fileChooserParams.toString()); mUploadMessage = filePathCallback; Intent i = new Intent(Intent.ACTION_GET_CONTENT); i.addCategory(Intent.CATEGORY_OPENABLE); if (fileChooserParams != null && fileChooserParams.getAcceptTypes() != null && fileChooserParams.getAcceptTypes().length > 0) { i.setType(fileChooserParams.getAcceptTypes()[0]); } else { i.setType("*/*"); } startActivityForResult(Intent.createChooser(i, "File Chooser"), FILECHOOSER_RESULTCODE); return true; } } 上面openFileChooser是系统未暴露的接口,因此不需要加Override的注解,同时不同版本有不同的参数,其中的参数,第一个ValueCallback用于我们在选择完文件后,接收文件回调到网页内处理,acceptType为接受的文件mime type。在Android 5.0之后,系统提供了onShowFileChooser来让我们实现选择文件的方法,仍然有ValueCallback,在FileChooserParams参数中,同样包括acceptType。我们可以根据acceptType,来打开系统的或者我们自己创建文件选择器。当然如果需要打开相机拍照,也可以自己去使用打开相机拍照的Intent去打开即可。 处理选择的文件 以上是打开响应的选择文件的界面,我们还需要处理接收到文件之后,传给网页来响应。因为我们前面是使用startActivityForResult来打开的选择页面,我们会在onActivityResult中接收到选择的结果。Show code: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == FILECHOOSER_RESULTCODE) { if (null == mUploadMessage) return; Uri result = data == null || resultCode != RESULT_OK ? null : data.getData(); if (result == null) { mUploadMessage.onReceiveValue(null); mUploadMessage = null; return; } CLog.i("UPFILE", "onActivityResult" + result.toString()); String path = FileUtils.getPath(this, result); if (TextUtils.isEmpty(path)) { mUploadMessage.onReceiveValue(null); mUploadMessage = null; return; } Uri uri = Uri.fromFile(new File(path)); CLog.i("UPFILE", "onActivityResult after parser uri:" + uri.toString()); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { mUploadMessage.onReceiveValue(new Uri[]{uri}); } else { mUploadMessage.onReceiveValue(uri); } mUploadMessage = null; } } 以上代码主要就是调用ValueCallback的onReceiveValue方法,将结果传回web。 注意,其他要说的,重要 由于不同版本的差别,Android 5.0以下的版本,ValueCallback 的onReceiveValue接收的参数类型是Uri, 5.0及以上版本接收的是Uri数组,在传值的时候需要注意。 选择文件会使用系统提供的组件或者其他支持的app,返回的uri有的直接是文件的url,有的是contentprovider的uri,因此我们需要统一处理一下,转成文件的uri,可参考以下代码(获取文件的路径)。 调用getPath可以将Uri转成真实文件的Path,然后可以自己生成文件的Uri 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 public class FileUtils { /** * @param uri The Uri to check. * @return Whether the Uri aut
以上内容来自博客订阅源,版权归原作者。关注作者后可以在 关注列表 第一时间查看作者文章。

登录后,加入这场讨论。
登录参与