当前位置:首页 > 实时新闻 > 正文

Android WebView 拍照和选择图片

摘要: AndroidWebView拍照和选择图片最佳答案53678位专家为你答疑解惑AndroidWebView拍照和选择图片Andr...

Android WebView 拍照和选择图片

最佳答案 53678位专家为你答疑解惑

Android WebView 拍照和选择图片

Android WebView 嵌套网页中有js调取拍照和选择图片上传的功能,这个需要在我们的代码中去实现方法

首先基础WebView设置

        WebSettings settings=mWebView.getSettings();        settings.setJavaScriptEnabled(true);    //设置webview支持javascript//        settings.setJavaScriptCanOpenWindowsAutomatically(true);        settings.setLoadsImagesAutomatically(true);    //支持自动加载图片        settings.setUseWideViewPort(true);    //设置webview推荐使用的窗口,使html界面自适应屏幕        settings.setLoadWithOverviewMode(true);        settings.setSaveFormData(true);    //设置webview保存表单数据        settings.setSavePassword(true);    //设置webview保存密码        int mDensity=DensityUtils.getDensityDpi(context);        if (mDensity==120) {            settings.setDefaultZoom(WebSettings.ZoomDensity.CLOSE);        } else if (mDensity==160) {            settings.setDefaultZoom(WebSettings.ZoomDensity.MEDIUM);        } else if (mDensity==240) {            settings.setDefaultZoom(WebSettings.ZoomDensity.FAR);        }//        settings.setDefaultZoom(WebSettings.ZoomDensity.MEDIUM);    //设置中等像素密度,medium=160dpi        settings.setSupportZoom(true);    //支持缩放        settings.setSupportMultipleWindows(true);        settings.setAppCacheEnabled(true); //设置APP可以缓存        settings.setDatabaseEnabled(true);        settings.setDomStorageEnabled(true);//返回上个界面不刷新  允许本地缓存        //        settings.setCacheMode(WebSettings.LOAD_DEFAULT);// 设置缓存LOAD_DEFAULT   LOAD_CACHE_ONLY,LOAD_NO_CACHE        settings.setAllowFileAccess(true);// 设置可以访问文件        settings.setLayoutAlgorithm(WebSettings.LayoutAlgorithm.SINGLE_COLUMN);//不支持放大缩小        settings.setDisplayZoomControls(false);//不支持放大缩小        //      NORMAL:正常显示,没有渲染变化。        //      SINGLE_COLUMN:把所有内容放到WebView组件等宽的一列中。   //这个是强制的,把网页都挤变形了        //      NARROW_COLUMNS:可能的话,使所有列的宽度不超过屏幕宽度。 //好像是默认的        mWebView.setLongClickable(true);        mWebView.setScrollbarFadingEnabled(true);        mWebView.setScrollBarStyle(View.SCROLLBARS_INSIDE_OVERLAY);        mWebView.setDrawingCacheEnabled(true)

js调取拍照和选择图片功能,兼容3.0以上

//5.0以下使用    private ValueCallback<Uri> uploadMessage;// 5.0及以上使用    private ValueCallback<Uri[]> uploadMessageAboveL;                    //覆盖WebView默认使用第三方或系统默认浏览器打开网页的行为,使网页用WebView打开                     mWebView.setWebChromeClient(new WebChromeClient() {                           // For Android < 3.0                           public void openFileChooser(ValueCallback<Uri> valueCallback) {                                 uploadMessage=valueCallback;                                 openImageChooserActivity();                            }                            // For Android  >=3.0                           public void openFileChooser(ValueCallback valueCallback, String acceptType) {                                uploadMessage=valueCallback;                                openImageChooserActivity();                            }                            //For Android  >=4.1                            public void openFileChooser(ValueCallback<Uri> valueCallback, String acceptType, String capture) {                                uploadMessage=valueCallback;                                openImageChooserActivity();                            }                            // For Android >=5.0                            @Override                            public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> filePathCallback, WebChromeClient.FileChooserParams fileChooserParams) {                                uploadMessageAboveL=filePathCallback;                                openImageChooserActivity();                                return true;                            }                      });

这里需要弹出一个对话框让用户选择拍照和图库,这里用的是第三方MaterialDialog

这里有个需要注意的地方,就是如果没有调用onReceiveValue(null)的方法,下一次js将无法生效,我这里让用户不能按返回键和点击屏幕外消失,当点击取消按钮的时候调用onReceiveValue(null)方法

//图片    private final static int FILE_CHOOSER_RESULT_CODE=128;//拍照    private final static int FILE_CAMERA_RESULT_CODE=129;//拍照图片路径    private String cameraFielPath;    private void openImageChooserActivity() {        new MaterialDialog.Builder(this)                .items(R.array.photo)                .positiveText("取消")                .onPositive(new MaterialDialog.SingleButtonCallback() {                    @Override                    public void onClick(@NonNull MaterialDialog dialog, @NonNull DialogAction which) {                        if (uploadMessageAboveL !=null) {                            uploadMessageAboveL.onReceiveValue(null);                            uploadMessageAboveL=null;                        }                        if (uploadMessage !=null) {                            uploadMessage.onReceiveValue(null);                            uploadMessage=null;                        }                        dialog.dismiss();                    }                })                .cancelable(false)                .canceledOnTouchOutside(false)                .itemsCallback(new MaterialDialog.ListCallback() {                    @Override                    public void onSelection(MaterialDialog dialog, View itemView, int position, CharSequence text) {                        if (position==0) {                            takeCamera();                        } else if (position==1) {                            takePhoto();                        }                    }                }).show();    } //选择图片 private void takePhoto() {        Intent i=new Intent(Intent.ACTION_GET_CONTENT);        i.addCategory(Intent.CATEGORY_OPENABLE);        i.setType("image/*");        startActivityForResult(Intent.createChooser(i, "Image Chooser"), FILE_CHOOSER_RESULT_CODE);    }//拍照    private void takeCamera() {        Intent intent=new Intent(MediaStore.ACTION_IMAGE_CAPTURE);        if (CommonUtil.hasSdcard()) {              //这里可能需要检查文件夹是否存在              //File file=new File(Environment.getExternalStorageDirectory() + "/APPNAME/");              //if (!file.exists()) {              //  file.mkdirs();              //}            cameraFielPath=Environment.getExternalStorageDirectory() + "upload.jpg";            File outputImage=new File(cameraFielPath);            intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(outputImage));            startActivityForResult(intent, FILE_CAMERA_RESULT_CODE);        }    }

最后一步在界面onActivityResult中判断进行操作

@Override    protected void onActivityResult(int requestCode, int resultCode, Intent data) {        super.onActivityResult(requestCode, resultCode, data);        if (null==uploadMessage && null==uploadMessageAboveL) return;        if (resultCode !=RESULT_OK) {//同上所说需要回调onReceiveValue方法防止下次无法响应js方法            if (uploadMessageAboveL !=null) {                uploadMessageAboveL.onReceiveValue(null);                uploadMessageAboveL=null;            }            if (uploadMessage !=null) {                uploadMessage.onReceiveValue(null);                uploadMessage=null;            }            return;        }        Uri result=null;        if (requestCode==FILE_CAMERA_RESULT_CODE) {            if (null !=data && null !=data.getData()) {                result=data.getData();            }            if (result==null && hasFile(cameraFielPath)) {                result=Uri.fromFile(new File(cameraFielPath));            }            if (uploadMessageAboveL !=null) {                uploadMessageAboveL.onReceiveValue(new Uri[]{result});                uploadMessageAboveL=null;            } else if (uploadMessage !=null) {                uploadMessage.onReceiveValue(result);                uploadMessage=null;            }        } else if (requestCode==FILE_CHOOSER_RESULT_CODE) {            if (data !=null) {                result=data.getData();            }            if (uploadMessageAboveL !=null) {                onActivityResultAboveL(data);            } else if (uploadMessage !=null) {                uploadMessage.onReceiveValue(result);                uploadMessage=null;            }        }    }    /**     * 判断文件是否存在     */    public static boolean hasFile(String path) {        try {            File f=new File(path);            if (!f.exists()) {                return false;            }        } catch (Exception e) {            // TODO: handle exception            return false;        }        return true;    }    @TargetApi(Build.VERSION_CODES.LOLLIPOP)    private void onActivityResultAboveL(Intent intent) {        Uri[] results=null;        if (intent !=null) {            String dataString=intent.getDataString();            ClipData clipData=intent.getClipData();            if (clipData !=null) {                results=new Uri[clipData.getItemCount()];                for (int i=0; i < clipData.getItemCount(); i++) {                    ClipData.Item item=clipData.getItemAt(i);                    results[i]=item.getUri();                }            }            if (dataString !=null)                results=new Uri[]{Uri.parse(dataString)};        }        uploadMessageAboveL.onReceiveValue(results);        uploadMessageAboveL=null;    }

完结 ,代码就这么多 经过测试可以完成图片的选择和拍照。做个记录方便下次使用

Android WebView多张图片选择

最近在做ionic开发的时候,需要实现webview调用原生图片选择的功能。我们在ionic代码里使用<input>标签选择文件,浏览器调试的时候,没有任何问题,结果放到Android手机里面,发现点击选择的时候,没有任何反应。后来参考网上的方法,能够实现图片选择,但是在Android上只能选择一张,ios上不存在这些问题(不得不吐槽一下,Android原生webview相比ios差太多了,很容易有奇怪的问题)。最后在查看了<input>的标签属性以后,对ionic代码和原生代码做了一些修改,最终实现了多张图片选择的功能(只针对5.0做了修改)。

首先Android webview在响应文件选择的时候,会触发WebChromeClient的onShowFileChooser()方法。

默认实现

这个方法有三个参数,第二个参数用于最后回传文件的uri给webview,第三个参数是文件选择时的一些条件,跟<input>标签里面的属性有关。Android的此方法默认是返回false,拦截了文件选择响应,所以我们需要重写此方法,在里面添加文件选择的实现,并返回true。在添加文件选择的实现之前,我们先简单了解一下FileChooserParams和<input>标签的一些关系,方便我们后续的处理。

FileChooserParams和<input>标签的相关对应关系

关系图

这个里面的multiple属性比较坑,我当时没有在<input>标签上添加这个属性,在ios上可以多次选择文件,虽然一次只能选择一张,但是在Android上只能选择一次,如果想再添加新的文件,必须把之前的删掉才能添加,且最多只能有一个文件。加上这个属性以后,在Android和ios上还是有差异的,ios有了这个属性之后,默认允许同时选择多张图片,但是在Android上还需要额外处理才能同时选择多张。

最后实现的代码片段如下:

ionic页面

原生实现

文件选择

处理完文件选择后,调用valueCallback的onReceiveValue方法,webview里的input标签才会调用change。以下是选择完文件后的回调处理,如果成功得到图片地址,则调用onReceiveValue方法把图片的本地uri数组回传给webview,失败或异常情况回传null给webview。

回调处理

valueCallback的回调执行以后,会触发<input>标签的change方法,在这个方法里面添加渲染图片的功能,这样就能完美实现图片选择和预览的功能了!

发表评论