WebView踩坑系列(二)

WebView传递图片给前端

webView中常常会遇到许多的问题,而这些问题给我们开发带来的痛苦已经不能用言语来形容,以下是可能会遇到的问题之一。

开发场景:
开发中可能会有这样的需求,webview加载的网页中要从本地获取图片(或者文件,这里以获取图片为例),获取的图片包括从本地文件夹中获取和拍照获取,在ios系统上前端是可以直接调用拍照或者从相册中获取图片的,但在Android系统上面这一些都要自己来处理,那好吧,我们自己来解决这个问题。

第一步:设置回调

允许webview接受文件,webview中属性如下

/**
     * Enables or disables file access within WebView. File access is enabled by default.  Note that this enables or disables file system access only.
     Assets and resources are still accessible using file:///android_asset and file:///android_res.
     */
    public abstract void setAllowFileAccess(boolean allow);

注释的意思是webview默认允许接收文件,但这个属性只作用于系统文件,即使这个属性设置为false,resources和assets下的文件仍然可用。
所以我们可以不设置这个属性,但如果设置了的话不要赋值为false。

重写WebChromeClient,获取ValueCallback回调对象,可以将该对象理解为快递员,他要去客户端取货并将该物品返回给前端:

public class MyWebChormeClient extends WebChromeClient {

    private WebCall webCall;

    public MyWebChormeClient(WebCall webCall) {
        this.webCall = webCall;
    }

    // For Android 3.0+
    public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType) {
        if (webCall != null)
            webCall.fileChose(uploadMsg);
    }

    // For Android < 3.0
    public void openFileChooser(ValueCallback<Uri> uploadMsg) {
        openFileChooser(uploadMsg, "");
    }

    // For Android > 4.1.1
    public void openFileChooser(ValueCallback<Uri> uploadMsg,String acceptType, String capture) {
        //openFileChooser(uploadMsg, acceptType);
        if(webCall != null){
            webCall.fileChose(uploadMsg);
        }
    }

    // For Android > 5.0
    @Override
    public boolean onShowFileChooser(WebView webView,
                 ValueCallback<Uri[]> filePathCallback,
                 FileChooserParams fileChooserParams) {
        if (webCall != null) {
            webCall.fileChose5(filePathCallback);
            Log.e("getValueCallBack", "onShowFileChooser: ");
        }
        return true;
    }

    public interface WebCall {

        void fileChose(ValueCallback<Uri> uploadMsg);

        void fileChose5(ValueCallback<Uri[]> uploadMsg);
    }
}

第二步:回调处理

当WebView中执行获取图片操作,会执行openFileChooser方法或者onShowFileChooser方法,这两个方法会给我们传递ValueCallback
这个对象,该对象的泛型可以用两种对象代替,Uri和Uri数组,分别适用不同版本的系统,我们客户端通过拍照获取图片文件或者从本地选取文件之后,将文件交给ValueCallback对象来处理,处理方式如下:

if (uri != null) {
   if (mUploadMessage != null) {
      mUploadMessage.onReceiveValue(uri);
      mUploadMessage = null
   } else if (mUploadMessageForAndroid5 != null) {              
      mUploadMessageForAndroid5.onReceiveValue(new Uri[]{uri});
      mUploadMessageForAndroid5 = null;
   }
}

上述代码中的mUploadMessage对象和mUploadMessageForAndroid5对象由WebCall接口回调过来。

第三步:释放对象

在对ValueCallback的onReceiveValue方法进行赋值之后,要将ValueCallback的对象释放。

以下为主要代码:

收到来自前端要获取图片的ValueCallback对象

@Override
    public void fileChose(ValueCallback<Uri> uploadMsg) {
        openFileChooserImpl(uploadMsg);
    }

    @Override
    public void fileChose5(ValueCallback<Uri[]> uploadMsg) {
        openFileChooserImplForAndroid5(uploadMsg);
    }

    private void openFileChooserImpl(ValueCallback<Uri> uploadMsg) {
        mUploadMessage = uploadMsg;
        showBottomPopupWindow();
    }

    private void openFileChooserImplForAndroid5(ValueCallback<Uri[]> uploadMsg) {
        mUploadMessageForAndroid5 = uploadMsg;
        showBottomPopupWindow();
    }

弹出选择框,选择拍照、从本地选择照片或者是取消,取消时要将ValueCallback对象释放。

    private boolean isTouchEvent;

    /**
     * 弹出底部照片选择框
     */
    private void showBottomPopupWindow() {
        if (softInputIsActive()) {
            hideSoftInput(mToolBar);
        }
        isTouchEvent = false;
        final CommonPopupWindow popupWindow = new CommonPopupWindow(this, mToolBar);
        popupWindow.setOnText1ClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                isTouchEvent = true;
                takePhoto();
                popupWindow.dismiss();
            }
        });
        popupWindow.setOnText2ClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                isTouchEvent = true;
                choicePic();
                popupWindow.dismiss();
            }
        });
        popupWindow.setOnDismissListener(new PopupWindow.OnDismissListener() {
            @Override
            public void onDismiss() {
                popupWindow.popupDismiss();
                if (!isTouchEvent)
                    if (mUploadMessage != null) {
                        mUploadMessage.onReceiveValue(Uri.EMPTY);
                        mUploadMessage = null;
                    } else if (mUploadMessageForAndroid5 != null) {
                        mUploadMessageForAndroid5.onReceiveValue(new Uri[]{Uri.EMPTY});
                        mUploadMessageForAndroid5 = null;
                    }
            }
        });
        popupWindow.show();
    }

拍照和选择照片,大家可以使用自己的方法

/**
     * 拍照
     */
    private void takePhoto() {
        Intent imageCaptureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
        String strImgPath = Config.PATH_IMAGE_TEMP_PATH;// 存放照片的文件夹,Config.PATH_IMAGE_TEMP_PATH是自定义的存放图片的路径
        String fileName = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date()) + ".jpg";// 照片命名
        File out = new File(strImgPath);
        if (!out.exists()) {
            out.mkdirs();
        }
        out = new File(strImgPath, fileName);
        imagePath = strImgPath + fileName;// 该照片的绝对路径
        Uri uri = Uri.fromFile(out);
        imageCaptureIntent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
        startActivityForResult(imageCaptureIntent, REQUEST_CAMERA);
    }

    /**
     * 选择照片
     */
    private void choicePic() {
        Intent intent = new Intent(Intent.ACTION_PICK, null);
        intent.setDataAndType(
                MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
                "image/*");
        startActivityForResult(intent, REQUEST_IMAGE);
    }

对ValueCallback的onReceiveValue方法赋值,并在赋值之后释放对象

 @Override
    protected void onActivityResult(int requestCode, int resultCode,
                                    Intent data) {
        if (mUploadMessage == null && mUploadMessageForAndroid5 == null) {
            return;
        }
        Uri uri = null;
        if (resultCode == RESULT_OK) {
            switch (requestCode) {
                case REQUEST_CAMERA:
                    uri = Uri.fromFile(new File(imagePath));
                    break;
                case REQUEST_IMAGE:
                    //本地选择图片后返
                    if (data != null && data.getData() != null) {
                        uri = Uri.parse(data.getData().toString());
                        ContentResolver cr = this.getContentResolver();
                        Cursor cursor = cr.query(uri, null, null, null, null);
                        if (cursor != null) {
                            cursor.moveToFirst();
                            for (int i = 0; i < cursor.getColumnCount(); i++) {
                                imagePath = cursor.getString(cursor
                                        .getColumnIndex("_data"));
                            }
                        } else {
                            imagePath = uri.getPath();
                        }
                    }
                    break;
            }
            if (uri != null) {
                if (mUploadMessage != null) {
                    mUploadMessage.onReceiveValue(uri);
                    mUploadMessage = null;
                } else if (mUploadMessageForAndroid5 != null) {
                    mUploadMessageForAndroid5.onReceiveValue(new Uri[]{uri});
                    mUploadMessageForAndroid5 = null;
                }
            }
        } else {
            if (mUploadMessage != null) {
                mUploadMessage.onReceiveValue(null);
                mUploadMessage = null;
            } else {
                mUploadMessageForAndroid5.onReceiveValue(new Uri[]{null});
                mUploadMessageForAndroid5 = null;
            }
        }

    }

文件处理要比图片处理简单一些,文件处理不需要拍照,所以没有弹框选择,等同于图片处理中直接从本地获取图片。
以上是我对webView中进行图片(文件)处理的解决方法,如果出现错误的地方,还请指正。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值