WebView中拍照或从相册上传图片

转载自WebView中拍照或从相册上传图片

注,安卓4.4系统的浏览器内核会出问题,即使使用本篇文章所讲的方法也无法吊起这个方法,属于谷歌系统的问题Stack Overflow 问题,但是4.4以上的系统完全没有问题,目前市场主流的都是4.4系统以上的机子占多数,所以请放心使用本轮子,首先还是感谢本轮子的作者~~

WebView 上传图片, 想必很多人都碰到过这样的场景. 而且 WebView 在4.4前后的区别非常大, 比如对URL跳转的格式, 对JS的注入声明等等, 4.4以后的WebView 已经是chromium内核, 有多强大就无需我赘述. 说这些, 其实也是为了说明也因为WebView的前后变化太大了, 所以在低版本和版本上, WebView上传文件的方式都略有不同, 而且在安卓4.4.4的一些设备上难以保证所有机型都成功.

实现过程:
在4.4之前, WebView的webkit中支持openFileChooser. 当WebView加载一个HTML页面, 点击按钮需要模拟form提交的方式去上传文件时, 就会回调

openFileChooser(...)

方法. 然后在这个方法里接收并处理参数ValueCallback <uri> uploadMsg. 里面的 uri 就是所从本地选择的文件路径.

然后通过Intent的startActivityForResult(…) 方法跳转到系统选择文件的界面进行文件选择, 最后在

onActivityResult(int requestCode, int resultCode, Intent data)

方法中获取 data中的字符串路径, 并转换成Uri格式, 并传给uploadMsg 即可, 类似:

String sourcePath = ImageUtil.retrievePath(this, mSourceIntent, data);

if (TextUtils.isEmpty(sourcePath) || !new File(sourcePath).exists()) {
    Log.e(TAG, "sourcePath empty or not exists.");
    break;
}
Uri uri = Uri.fromFile(new File(sourcePath));
mUploadMsg.onReceiveValue(uri);

  
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

这样, 接下来的上传工作, WebView会自动完成. 当然, 这是顺利的流程, 如果 onActivityResult(…) 中返回的 resultcode 不等于 Activity.RESULT_OK , 也要做一点处理, 不然再去点击第二次上传文件时是没有反应的. 类似这样:

if (resultCode != Activity.RESULT_OK) {
    if (mUploadMsg != null) {
        mUploadMsg.onReceiveValue(null);
    }
    return;
}

  
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

传个 null 即可.

OK, 上面就是4.4 以前的实现过程, 上面提及的代码在下载的demo里会有, 为保证篇幅不会放在文章里. 那么5.0及以上的sdk变动时, webkit不再支持
openFileChooser(...)

而是提供了一个代替的方法:

public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> filePathCallback,
            FileChooserParams fileChooserParams) {
    return false;
}

  
  
  • 1
  • 2
  • 3
  • 4

这个方法的参数跟 openFileChooser(…) 方法很像, 其实作用都是类似的, 只是 从
ValueCallback <uri> uploadMsg
变成了
ValueCallback<Uri[]> filePathCallback, 还多了FileChooserParams类型参数. fileChooserParams 其实是一个属性封装的参数, 里面包含了acceptType, title等这样的文件属性, 名称等信息.

所以, onShowFileChooser(…) 的使用方法跟 openFileChooser(…) 是很类似的, 这里通过 onActivityResult(…) 看两者的使用区别:

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
    if (resultCode != Activity.RESULT_OK) {
        if (mUploadMsg != null) {
            mUploadMsg.onReceiveValue(null);
        }

        if (mUploadMsgForAndroid5 != null) {         // for android 5.0+
            mUploadMsgForAndroid5.onReceiveValue(null);
        }
        return;
    }
    switch (requestCode) {
        case REQUEST_CODE_IMAGE_CAPTURE:
        case REQUEST_CODE_PICK_IMAGE: {
            try {
                if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
                    if (mUploadMsg == null) {
                        return;
                    }

                    String sourcePath = ImageUtil.retrievePath(this, mSourceIntent, data);

                    if (TextUtils.isEmpty(sourcePath) || !new File(sourcePath).exists()) {
                        Log.e(TAG, "sourcePath empty or not exists.");
                        break;
                    }
                    Uri uri = Uri.fromFile(new File(sourcePath));
                    mUploadMsg.onReceiveValue(uri);

                } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                    if (mUploadMsgForAndroid5 == null) {        // for android 5.0+
                        return;
                    }

                    String sourcePath = ImageUtil.retrievePath(this, mSourceIntent, data);

                    if (TextUtils.isEmpty(sourcePath) || !new File(sourcePath).exists()) {
                        Log.e(TAG, "sourcePath empty or not exists.");
                        break;
                    }
                    Uri uri = Uri.fromFile(new File(sourcePath));
                    mUploadMsgForAndroid5.onReceiveValue(new Uri[]{uri});
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            break;
        }
    }
}

  
  
  • 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

主要是针对 5.0前后的系统做了一些区别处理, 其他无大异.

测试说明
这里要特别说明的是, 经过我测试9部安卓手机, 从4.2 到6.0.1, 有8部都是正常使用. 其中包含 一部Android 4.4.2系统的手机 和 两部Android 4.4.4的手机, 发现在魅蓝note(4.4.4)上面是无法使用的, 因为4.4 Kitkat中webview是一个有点奇葩的存在, 问题这里不赘述, 有兴趣可以自行了解.

提高兼容性的解决方案:
1. 使用加强版的WebView, cordova , 可以考虑编译这个项目获得jar包, 然后导入项目中使用它的WebView组件.
2. 也可以通过JS调用本地的方法自行实现上传.

以上两个方法的兼容性都相当不错, 可自行尝试.

可能导致失败的原因
如果选择文件到上传文件的过程中失败, 有可能是以下原因导致的:
1. 文件的路径包含中文. (9部设备中, vivo X6D不支持中文路径包含中文)
2. 手机系统是Android 6.0以上 (API >= 23), 且没有获得文件和摄像头权限.

如果你的项目中还兼容到4.0以下的版本, build.gradle 配置文件中的compileSdkVersion 和 targetSdkVersion 是16甚至更低, 那么恭喜你, 直接使用
openFileChooser(...)
这种处理方法即可.

demo下载

参考文章:
WebView File Upload Over Kitkat
HTML file input in android webview (android 4.4, kitkat)
CORDOVA Android WebViews
使用Cordova来解决HTML5制作的WebView手机不兼容的问题
android4.4webview支持openFileChooser文件/照片上传
Android使用WebView从相册/拍照中添加图片

测试设备列表
1. 中移动 CM601 (4.2.2)
2. 华为荣耀6 H60-L01 (4.4.2)
3. 华为荣耀畅玩4X Che1-CL20 (4.4.4)
4. 魅蓝note (4.4.4)
5. 联想K50-t5 (5.0)
6. 魅蓝note3 (5.1)
7. vivo X6D (5.1)
8. 小米note (6.0.1)
9. 华为mate8 (6.0.1)
10. 三星Galaxy S6 SM-G9200 (6.0.1)

下面附上测试部分测试手机图, 由于拿了真实项目的地址做测试, 这里做了一些可爱的马赛克处理 请谅解谅解~
这里写图片描述

这里写图片描述

这里写图片描述

这里写图片描述

这里写图片描述

这里写图片描述

</article>

这篇博客写的很不错了,但是6.0以上的手机要自己做处理,比如权限适配啊,7.0的还要处理uri,伸手党出门右拐,不送!

猜你喜欢

转载自blog.csdn.net/sinat_25136209/article/details/82893783