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事件。

@Override
public 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<Uri> uploadMsg)

Android 3.0以上
public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType)

Androi 4.4以下
public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType, String capture)

Android 5.0以上
public boolean onShowFileChooser(WebView mWebView, ValueCallback<Uri[]> filePathCallback, FileChooserParams fileChooserParams)

代码如下:

mWeb.setWebChromeClient(new MyWebChromeClient());

 private class MyWebChromeClient extends WebChromeClient {

        //  Android 3.0 以下
        @SuppressWarnings("unused")
        public void openFileChooser(ValueCallback<Uri> uploadMsg) {
            openFileChooser(uploadMsg, null);
        }

        // Android 3.0以上
        public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType) {
            openFileChooser(uploadMsg, acceptType, null);
        }

        // Androi 4.4以下
        @SuppressWarnings("unused")
        public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType, String capture) {
            openFileInput(uploadMsg, null, false);
        }

        //  Android 5.0以上
        @SuppressWarnings("all")
        public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> 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<Uri> fileUploadCallbackFirst, final ValueCallback<Uri[]> 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 和setWebClientsetWebClient
WebChromeClient:辅助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设置节点 webview

10. 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 一致的开发体验在本地平台上构建世界一流的应用程序体验。
我们都应该学习学习!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一条苍老的小鱼

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值