Android 内嵌WebView之选择文件上传及扩展
16lz
2021-01-23
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 一致的开发体验在本地平台上构建世界一流的应用程序体验。
我们都应该学习学习!
更多相关文章
- 顛覆性的傳輸功能:Android Beam
- android运行时ART加载OAT文件解析
- 如何检测android上的多媒体文件属于音频、视频还是图片?
- Android中的文件读写操作
- 【源码】android新闻日报源码、android 企业级erp商业应用源码、
- Android手机软件汉化教程---第三课 xml文件汉化