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显然是不现实的 但是我们同时也知道,云函数是后台服务端, ...
随机推荐
- Handlebars模板库浅析
Handlebars模板库简单介绍 Handlebars是JavaScript一个语义模板库,通过对view(模板)和data(ajax请求的数据,一般是json)的分离来快速构建Web模板.它采用& ...
- JQuery 概况
- DATE 日期格式
Oracle TO_DATE 日期格式 Oracle中TO_DATE格式2009-04-14 10:53TO_DATE格式(以时间:2007-11-02 13:45:25为例) ...
- C# DataTable 和List之间相互转换的方法
介绍:List/IEnumerable转换到DataTable/DataView,以及DataTable转换到List 正文: 一.List<T>/IEnumerable转换到DataTa ...
- oracle 学习笔记2
1.oracle 中rowid和rownum的区别 oracle 数据库中,每一行都有一个唯一行的标识符,ROWID,数据库内部用来存储行的物理位置.ROWID是一个18位数字,采用base-64编码 ...
- 发现 git忽略没用
git rm --cached GuoJiWeb/Properties/PublishProfiles/Profile1.pubxml
- 网络编程——URL编程
URL:是统一资源定位器的简称,它表示Internet某一资源的地址.通过URL我们可以访问Internet上的各种网络资源,比如最常见的www,ftp站点.浏览器通过解析给定的URL可以在网络上查找 ...
- linux服务器TCP并发连接数优化
1.查看用户单一进程最大文件打开数 [root@localhost ~]# ulimit -n 1024 2.修改/etc/security/limits.conf文件,添加下面两行, [root@l ...
- Linux 中 Vi 编辑器的简单操作
Linux 中 Vi 编辑器的简单操作 Vi 编辑器一共有3种模式:命名模式(默认),尾行模式,编辑模式.3种模式彼此需要切换. 一.进入 Vi 编辑器的的命令 vi filename //打开或新 ...
- C#读取Excel的三种方式以及比较
(1)OleDB方式 优点:将Excel直接当做数据源处理,通过SQL直接读取内容,读取速度较快. 缺点:读取数据方式不够灵活,无法直接读取某一个单元格,只有将整个Sheet页读取出来后(结果为Dat ...