Android 内嵌WebView之选择文件上传及填坑记录

  • Android 内嵌WebView之选择文件上传及填坑记录
  • 前言
  • 实现
    • 开发中遇到的问题
    • 功能的具体实现
  • 总结
  • 扩展

前言

今天老大给我提了个醒,年前的一个问题还没解决…然而我早已忘记… 既然说了,那么咱就研究研究这问题。

问题是关于内嵌webView时网页内无法调用系统的拍照功能/文件选择功能。于是我写起一个demo试试,发现确实无法调起来,而浏览器上可以正常使用,恩…那就是我们支持的不够咯~

这不,发现带有input type = file标签的Html页面通过webVie显示就无法正常功能做,那么我们要做的是在webView中增加对这类js的支持…

实现

1.我们先写一个简单的demo, 通过webView打开一个有调用打开文件功能的网页(文末附源码)

WebView mWeb = (WebView) findViewById(R.id.webView);WebSettings settings = mWeb.getSettings();mWeb.requestFocusFromTouch();settings.setJavaScriptEnabled(true);   //支持js  settings.setAllowFileAccess(true);     //设置可以访问文件mWeb.loadUrl("file:///android_asset/getFile.html");

开发中遇到的问题

点击打开webView时跳转至系统自带的浏览器/第三方浏览器解决办法:覆盖WebView的WebViewClient对象。mWeb.setWebViewClient(new WebViewClient(){public boolean shouldOverrideUrlLoading(WebView view, String url){     view.loadUrl(url);    return true;    }});同时扩展一下:在不做任何处理下按系统返回键,整个Browser回调用finis()销毁,而一般我们是希望按历史记录逐步回退,那么这个时候我们需要在当前Activity中消费掉Back事件。@Overridepublic boolean onKeyDown(int keyCode, KeyEvent event) {    if (keyCode == KeyEvent.KEYCODE_BACK && mWeb.canGoBack()){        mWeb.goBack();        return true;    }    return super.onKeyDown(keyCode, event);}

注:这里我们将Html文件放到assets目录下

功能的具体实现

通过Google大法终于找出常用的解决办法。【重写WebVie的webChromeClien覆盖OpenFileChooser方法】Android在不同版本中调用相机的方法不同:Android 3.0 以下public void openFileChooser(ValueCallback uploadMsg)Android 3.0以上public void openFileChooser(ValueCallback uploadMsg, String acceptType)Androi 4.4以下public void openFileChooser(ValueCallback uploadMsg, String acceptType, String capture)Android 5.0以上public boolean onShowFileChooser(WebView mWebView, ValueCallback filePathCallback, FileChooserParams fileChooserParams)

代码如下:

mWeb.setWebChromeClient(new MyWebChromeClient()); private class MyWebChromeClient extends WebChromeClient {        //  Android 3.0 以下        @SuppressWarnings("unused")        public void openFileChooser(ValueCallback uploadMsg) {            openFileChooser(uploadMsg, null);        }        // Android 3.0以上        public void openFileChooser(ValueCallback uploadMsg, String acceptType) {            openFileChooser(uploadMsg, acceptType, null);        }        // Androi 4.4以下        @SuppressWarnings("unused")        public void openFileChooser(ValueCallback uploadMsg, String acceptType, String capture) {            openFileInput(uploadMsg, null, false);        }        //  Android 5.0以上        @SuppressWarnings("all")        public boolean onShowFileChooser(WebView webView, ValueCallback filePathCallback, WebChromeClient.FileChooserParams fileChooserParams) {            if (Build.VERSION.SDK_INT >= 21) {                final boolean allowMultiple = fileChooserParams.getMode() == WebChromeClient.FileChooserParams.MODE_OPEN_MULTIPLE;//是否支持多选                openFileInput(null, filePathCallback, allowMultiple);                return true;            } else {                return false;            }        }    }    @SuppressLint("NewApi")    protected void openFileInput(final ValueCallback fileUploadCallbackFirst, final ValueCallback fileUploadCallbackSecond, final boolean allowMultiple) {        //Android 5.0以下版本        if (mFileUploadCallbackLowVersion != null) {            mFileUploadCallbackLowVersion.onReceiveValue(null);        }        mFileUploadCallbackLowVersion = fileUploadCallbackFirst;        //Android 5.0及以上版本        if (mFileUploadCallbackHighVersion != null) {            mFileUploadCallbackHighVersion.onReceiveValue(null);        }        mFileUploadCallbackHighVersion = fileUploadCallbackSecond;        Intent i = new Intent(Intent.ACTION_GET_CONTENT);        i.addCategory(Intent.CATEGORY_OPENABLE);        if (allowMultiple) {            if (Build.VERSION.SDK_INT >= 18) {                i.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);            }        }        i.setType(mFileTypes);        startActivityForResult(Intent.createChooser(i, "选择文件"), REQUEST_CODE_FILE_PICKER);    }

最后我们在Acitivity的onActivityResult()方法中处理,不管请求是否成功,我们都要在onReceiveValue()传nul,否则html中的j执行一次就不会再执行即我们点击不会在有响应了。

public void onActivityResult(final int requestCode, final int resultCode, final Intent intent) {        if (requestCode == REQUEST_CODE_FILE_PICKER) {            if (resultCode == Activity.RESULT_OK) {                if (intent != null) {                    //Android 5.0以下版本                    if (mFileUploadCallbackLowVersion != null) {                        mFileUploadCallbackLowVersion.onReceiveValue(intent.getData());                        mFileUploadCallbackLowVersion = null;                    } else if (mFileUploadCallbackHighVersion != null) {//Android 5.0及以上版本                        Uri[] dataUris = null;                        try {                            if (intent.getDataString() != null) {                                dataUris = new Uri[]{Uri.parse(intent.getDataString())};                            } else {                                if (Build.VERSION.SDK_INT >= 16) {                                    if (intent.getClipData() != null) {                                        final int numSelectedFiles = intent.getClipData().getItemCount();                                        dataUris = new Uri[numSelectedFiles];                                        for (int i = 0; i < numSelectedFiles; i++) {                                            dataUris[i] = intent.getClipData().getItemAt(i).getUri();                                        }                                    }                                }                            }                        } catch (Exception ignored) {                        }                        mFileUploadCallbackHighVersion.onReceiveValue(dataUris);                        mFileUploadCallbackHighVersion = null;                    }                }            } else {                //这里mFileUploadCallbackFirst跟mFileUploadCallbackSecond在不同系统版本下分别持有了                //WebView对象,在用户取消文件选择器的情况下,需给onReceiveValue传null返回值                //否则WebView在未收到返回值的情况下,无法进行任何操作,文件选择器会失效                if (mFileUploadCallbackLowVersion != null) {                    mFileUploadCallbackLowVersion.onReceiveValue(null);                    mFileUploadCallbackLowVersion = null;                } else if (mFileUploadCallbackHighVersion != null) {                    mFileUploadCallbackHighVersion.onReceiveValue(null);                    mFileUploadCallbackHighVersion = null;                }            }        }    }

总结

Android及iOS的webview的引擎都是webkit,对H5提供支持。webview有两个方法:setWebChromeClient 和setWebClientsetWebClientWebChromeClient:辅助WebView处理Javascript的对话框,网站图标,网站title,加载进度等WebViewClient就是帮助WebView处理各种通知、请求事件的。WebSetting常用方法总结:1.setJavaScriptEnabled(true); //支持js 2.setPluginsEnabled(true); //支持插件 3.setUseWideViewPort(false); //将图片调整到适合webview的大小 4.setSupportZoom(true); //支持缩放 5.setLayoutAlgorithm(LayoutAlgorithm.SINGLE_COLUMN); //支持内容重新布6.supportMultipleWindows(); //多窗口 7.setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK); //关闭webview中缓存 8.setAllowFileAccess(true); //设置可以访问文件 9.setNeedInitialFocus(true); //当webview调用requestFocus时为webview设置节点 webview10. webSettings.setBuiltInZoomControls(true); //设置支持缩放 11.setJavaScriptCanOpenWindowsAutomatically(true); //支持通过JS打开新窗口 12.setLoadWithOverviewMode(true); // 缩放至屏幕的大小 13.setLoadsImagesAutomatically(true); //支持自动加载图片

扩展

现在对于许多APP的开放方案已经从原生开发趋向于混合(Hybrid)开发的方式,我们应该去学习Java与JavaScript的交互;
React Native 结合了 Web 应用和 Native 应用的优势,可以使用 JavaScript 来开发 iOS 和 Android 原生应用。在 JavaScript 中用 React 抽象操作系统原生的 UI 组件,代替 DOM 元素来渲染等。
React Native 使你能够使用基于 JavaScript 和 React 一致的开发体验在本地平台上构建世界一流的应用程序体验。
我们都应该学习学习!

更多相关文章

  1. 顛覆性的傳輸功能:Android Beam
  2. android运行时ART加载OAT文件解析
  3. 如何检测android上的多媒体文件属于音频、视频还是图片?
  4. Android中的文件读写操作
  5. 【源码】android新闻日报源码、android 企业级erp商业应用源码、
  6. Android手机软件汉化教程---第三课 xml文件汉化

随机推荐

  1. [置顶] Canvas开篇之drawBitmap方法讲解
  2. Android(安卓)ActionBar的基本用法
  3. Android(安卓)借助Stetho在Chrome上调试A
  4. Doze和App Standby的优化(API23)
  5. Android(安卓)NDK r5 windows系统上安装
  6. 【ADT】亲测、有图goagent解决ADT下载过
  7. android——代码实现在指定位置显示View
  8. Android开发周报:Android(安卓)Studio2.0
  9. java获取页面输入的值
  10. EditText 的setKeyListener()方法的用法