WebView 上传文件 WebChromeClient之openFileChooser函数
原链接:http://blog.saymagic.cn/2015/11/08/webview-upload.html?utm_source=tuicool&utm_medium=referral
从零开始
我们在xml中写入一个简单的Webview组件:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"android:layout_height="match_parent"tools:context=".MainActivity"><WebViewandroid:id="@+id/webview"android:layout_width="fill_parent"android:layout_height="fill_parent"android:layout_margin="5dp"></WebView></RelativeLayout>
然后在Java代码中使用其加载一个能够提供上传服务的URL:
WebView webview = (WebView) findViewById(R.id.webview);webview.loadUrl(A_UPLOAD_URL);
之后,要加网络权限:
<uses-permission android:name="android.permission.INTERNET"></uses-permission>
如果想让Webview能够访问本地资源,SD卡的读写权限也是避免不了的:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/><uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
最后,我们运行,会发现根本不能访问本地资源。Why?
让我们来填补第一个坑:
支持上传文件
Webview执行上传操作的逻辑是这样的:首先准备上传时会回调WebChromeClient类下的openFileChooser方法,在这个方法中给我们机会发起Intent来打开支持提供文件的第三方应用,最后在onActivityResult回调中将第三方应用提供的内容通过一个叫做ValueCallback的参数返回给Webview(详细点来说:ValueCallback是在openFileChooser 方法里由webview提供给我们的,里面包裹一个Uri,我们在onActivityResult 里将选中的Uri反馈给ValueCallback,这时候相当于Webview就知道我们选择了什么文件),因此,我们需要为Webview设置一个提供openFileChooser方法的WebChromeClient,这个方法在不同版本的Android中参数是不同的,为此我们一般需要写三个重载函数,大致像这个样子:
private ValueCallback<Uri> mUploadMessage;//设置`WebChromeClient`:webview.setWebChromeClient(new WebChromeClient(){public void openFileChooser(ValueCallback<Uri> uploadMsg) {Log.d(TAG, "openFileChoose(ValueCallback<Uri> uploadMsg)");mUploadMessage = uploadMsg;Intent i = new Intent(Intent.ACTION_GET_CONTENT);i.addCategory(Intent.CATEGORY_OPENABLE);i.setType("*/*");MainActivity.this.startActivityForResult(Intent.createChooser(i, "File Chooser"), FILECHOOSER_RESULTCODE);}public void openFileChooser( ValueCallback uploadMsg, String acceptType ) {Log.d(TAG, "openFileChoose( ValueCallback uploadMsg, String acceptType )");mUploadMessage = uploadMsg;Intent i = new Intent(Intent.ACTION_GET_CONTENT);i.addCategory(Intent.CATEGORY_OPENABLE);i.setType("*/*");MainActivity.this.startActivityForResult(Intent.createChooser(i, "File Browser"),FILECHOOSER_RESULTCODE);}public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType, String capture){Log.d(TAG, "openFileChoose(ValueCallback<Uri> uploadMsg, String acceptType, String capture)");mUploadMessage = uploadMsg;Intent i = new Intent(Intent.ACTION_GET_CONTENT);i.addCategory(Intent.CATEGORY_OPENABLE);i.setType("*/*");MainActivity.this.startActivityForResult( Intent.createChooser( i, "File Browser" ), MainActivity.FILECHOOSER_RESULTCODE );}});//onActivityResult回调@Overrideprotected void onActivityResult(int requestCode, int resultCode, Intent data) {super.onActivityResult(requestCode, resultCode, data);if(requestCode==FILECHOOSER_RESULTCODE){if (null == mUploadMessage && null == mUploadCallbackAboveL) return;Uri result = data == null || resultCode != RESULT_OK ? null : data.getData();if (mUploadMessage != null) {mUploadMessage.onReceiveValue(result);mUploadMessage = null;}}}
还有重要的一点:如果这个上传操作涉及到JS操作,别忘记对Webview开启对JS的支持:
WebSettings settings = webview.getSettings();settings.setJavaScriptEnabled(true);
这样,打个debug包测试看以下,不出意外我们的Webview应该可以支持上传操作了。
别高兴得太早,如果这个时候产品要将release包推向市场,当你把release包交给产品时,你会发现你的Webview又不能上传了,什么情况?
请听Webview上传操作的第二个坑。
支持release版
debug版是好的,为什么release就不行了呢?准确的说,开启了混淆的release包是不可以的,究其原因在于,openFileChooser 方法并不是WebChromeClient 的对外开放的方法,因此这个方法会被混淆,解决办法也比较简单,只需要在混淆文件里控制一下即可:
-keepclassmembers class * extends android.webkit.WebChromeClient{public void openFileChooser(...);}
好了,我们的Webview可以作为应用内的一个部分对外发布了,等等,有5.0以上用户反映用不了?纳尼????
别回心,来看看这第三个坑。
支持5.0
在5.0发布后,Android人家说了,这次我们回调的不是openFileChooser方法,而是onShowFileChooser方法,并且上文提到的ValueCallback参数里包裹着不再是Uri,而是Uri数组,因此我们必须为5.0+的机器做适配,大致思路如下:
webview.setWebChromeClient(new WebChromeClient(){public void openFileChooser(ValueCallback<Uri> uploadMsg) {...}public void openFileChooser( ValueCallback uploadMsg, String acceptType ) {...}public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType, String capture){...}// For Android 5.0+public boolean onShowFileChooser (WebView webView, ValueCallback<Uri[]> filePathCallback, WebChromeClient.FileChooserParams fileChooserParams) {mUploadCallbackAboveL = filePathCallback;Intent i = new Intent(Intent.ACTION_GET_CONTENT);i.addCategory(Intent.CATEGORY_OPENABLE);i.setType("*/*");MainActivity.this.startActivityForResult(Intent.createChooser(i, "File Browser"),FILECHOOSER_RESULTCODE);return true;}});@Overrideprotected void onActivityResult(int requestCode, int resultCode, Intent data) {super.onActivityResult(requestCode, resultCode, data);if(requestCode==FILECHOOSER_RESULTCODE){if (null == mUploadMessage && null == mUploadCallbackAboveL) return;Uri result = data == null || resultCode != RESULT_OK ? null : data.getData();if (mUploadCallbackAboveL != null) {onActivityResultAboveL(requestCode, resultCode, data);}else if (mUploadMessage != null) {mUploadMessage.onReceiveValue(result);mUploadMessage = null;}}}@TargetApi(Build.VERSION_CODES.LOLLIPOP)private void onActivityResultAboveL(int requestCode, int resultCode, Intent data) {if (requestCode != FILECHOOSER_RESULTCODE|| mUploadCallbackAboveL == null) {return;}Uri[] results = null;if (resultCode == Activity.RESULT_OK) {if (data == null) {} else {String dataString = data.getDataString();ClipData clipData = data.getClipData();if (clipData != null) {results = new Uri[clipData.getItemCount()];for (int i = 0; i < clipData.getItemCount(); i++) {ClipData.Item item = clipData.getItemAt(i);results[i] = item.getUri();}}if (dataString != null)results = new Uri[]{Uri.parse(dataString)};}}mUploadCallbackAboveL.onReceiveValue(results);mUploadCallbackAboveL = null;return;}
如上,我们的Webview应该就可以适应5.0+的机器了。
WebView 上传文件 WebChromeClient之openFileChooser函数的更多相关文章
- Android webview 上传文件不调用openFileChooser解决办法
html页面带有图片上传功能,关于使用openFileChooser方法去选择图片,并且在onActivityResult方法里面设置返回的图片url文件路径,网上有很多,再次不再赘述. 实践中发现, ...
- android使用webview上传文件(支持相册和拍照)
老夫最近需要做一个项目,需要调用服务器段的一些网页来选择文件,刚开始还挺纠结的,不知从何下手,网上大致预览了大神们走过的路,他们传统的方式都是使用一下代码: public void openFileC ...
- Android应用开发中webview上传文件的几种思路
1. 常规方法,重写WebChromeClient 的 openFileChooser 方法 private class MyWebChromeClient extends WebChromeClie ...
- 关于Android WebView上传文件的解决方案
我们在开发需求的时候,难免会接入一下第三方的H5页面,有些H5页面是具有上传照片的功能,Android 中的 WebView是不能直接打开文件选择弹框的 接下来我讲简单提供一下解决方案,先说一下思路 ...
- phpcms前端页面上传文件
PHPCMS其实有一个叫做附件的模块,上传用的就是这个东西,现在我们来看一下对应的文件:phpcms\modules\attachment \attachments.php就是这个文件,大概在29行上 ...
- Angular2使用ng2-file-upload上传文件
Angular2中有两个比较好用的上传文件的第三方库,一个是ng2-file-upload,一个是ng2-uploader.ng2-uploader是一个轻便的上传文件的支持库,功能较弱,而ng2-f ...
- webview 本地上传文件
参考http://blog.csdn.net/zhtsuc/article/details/49154099 直接上代码 public class MainActivity1 extends Ac ...
- Android WebView 上传各种文件(包括拍照 录像 录音 文件 音乐 等,用到图片或拍照的,可以参考下)
我也是从网上扒下来的,经过多次实验,找到了个好用的.网上能搜到最多的也就是这个解决方案,我英文不好,也没仔细研究,但大多数都是出自这: http://stackoverflow.com/questio ...
- 小程序云开发--云函数上传文件或图片 base64
云函数开发遇到的问题 在微信云开发环境当中,普通的用户并没有往云存储内写入文件的权限 所以普通用户想要使用wx.cloud.uploadFile显然是不现实的 但是我们同时也知道,云函数是后台服务端, ...
随机推荐
- UNIX域套接字(unix domain)
UNIX域套接字用于在同一台机器上运行的进程之间的通信. UNIX域套接字提供流和数据报两种接口. 说明:UNIX域套接字比因特网套接字效率更高.它仅赋值数据:不进行协议处理,如添加或删除网络报头.计 ...
- nagios二次开发(四)---nagios监控原理和nagios架构简介
nagios监控原理 下面根据上面摘自网络的原理图对nagios的监控原理进行一下简单的说明: 1.nagios通过nsca进行被动监控.那么什么是被动监控呢?被动监测:就是指由被监测的服务器主动上传 ...
- Qt 自定义消息窗口
用于设置取消时,询问是否保存修改的DLGvoid SetWindow::cancelButton() { if( m_IsChange) { QMessageBox msgBox; msgBox.se ...
- 关于前端build工具
第一.build工具的核心就是帮你安装和帮你做事.安装类工具:Npm.Bower.Yeoman等 做事类工具:Node.Grunt.gulp.Webpack等 安装类工具几乎什么东西 ...
- 史航416第十次作业&总结
作业1: 计算两数的和与差.要求自定义一个函数 #include <stdio.h> void sum_diff(float op1,float op2,float *psum , flo ...
- selenium--环境搭建步骤
1.安装Python 2.安装setuptools 3.安装pip(Python3.X自带pip) 4.安装selenium(步骤在另一个博客中已提及)
- db2 常用函数
语法:VALUE(EXPRESSION1,EXPRESSION2) VALUE函数是用返回一个非空的值,当其第一个参数非空,直接返回该参数的值,如果第一个参数为空,则返回第一个参数的值. eg: -- ...
- 'Missing recommended icon file - The bundle does not contain an app icon for iPhone / iPod Touch of exactly '120x120' pixels, in .png format'
创建120像素的高分辨率和60个像素定期如上,苹果文档中提到,并设置名称的新图标.例如,icon-120.png和icon-152.png. 将这个图标到你的项目资源文件夹并添加该图标到项目: 在此之 ...
- ViewFlipper(翻转视图)的使用
android developers java.lang.Object --android.view.View ----android.view.ViewGroup ------android.wid ...
- nginx + lua +redis环境搭建
环境搭建,其实主要是lua的环境,这个环境够麻烦的,在网上找了很多前辈的文章,终于完成了 ,安装redis wget http://download.redis.io/releases/redis-3 ...