WebView上传文件的深坑与研究

直接切入主题了

最近公司项目里线上用户反馈出一个bug,介入的第三方平台中有个添加图片的功能,当点击H5中的按钮的时候,调不起本地文件管理器,在很多手机上都出现这种情况

原因如下

刨除定制化的webview来说,原生webview是支持上传文件的。但是众多版本的迭代扩展,api参数也不一样。一般拿到上传文件的需求时,大家都会照搬android brower的代码(聪明),api如下:

        // 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的文章知道了这点:Sam


之后,本以为没有问题了,测试的时候发现,坑又来了。

我们可以看出,在这个功能上,有很明显的api升级痕迹,在试过众多手机之后,发现,4.4.0到4.4.2的系统无法调用这个api,当然也无从上传文件了,是怎么回事?

在这篇博客找到了详细的答案:穿衣助手技术博客

原来google在4.4更改webkit内核为chromium之后,把这个api删除了!一般升级api,都会保留对原有api的支持,@deprecated掉旧的api,加入新的api,但是google却2个都没做,开发团队解释,我们正在开发一个新的共有的api,这个api会更好,我们会在正式版本上推出。结果呢,在4.4.3版本,他又把这个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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,539评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,911评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,337评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,723评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,795评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,762评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,742评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,508评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,954评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,247评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,404评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,104评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,736评论 3 324
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,352评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,557评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,371评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,292评论 2 352

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 172,035评论 25 707
  • 发现 关注 消息 iOS 第三方库、插件、知名博客总结 作者大灰狼的小绵羊哥哥关注 2017.06.26 09:4...
    肇东周阅读 12,089评论 4 62
  • 前言 总结 Android WebView 常用的相关知识点,令包含以下干货内容分析:Js注入漏洞、WebView...
    無名小子的杂货铺阅读 69,796评论 17 169
  • (闻文老师 理疗瑜珈 课堂笔记速记版) 昨天谈到瑜珈疗法与其它治疗的差异。。。 优势:安全,有效,随时随地,可深...
    鹏之翼阅读 486评论 0 2
  • 人生无处不选择,选择做什么,选择吃什么,选择这个,选择那个。有的无关紧要,有的则关乎一生,在你无从选择的时候,你会...
    说说侃侃聊聊阅读 340评论 0 1