WebView调H5上传文件点击取消时无法再次响应H5上的选择文件事件

最近一直都在做与H5交互的事情,算是踩了好多坑吧,再加上个人原因好长时间没更博了,再次回到状态,于是乎更了这篇博客。

项目中有需求WebView加载H5上页面,然后响应H5上的上传文件事件,由于安卓无法像IOS的那样直接调系统原生的接口,所以只能自己封装方法,再加上android M之后运行时权限的问题,像选文件或者拍照,这种敏感的事件都需要单独处理,总之好多坑。

代码写完之后,测试的时候偶然发现的BUG还真难解。

 

H5上上传文件协议为:

// <input type="file" name="fileField" id="fileField" />

 

在安卓这边我自己封装了从图库选图或者拍照,选择完文件之后,需要回显在H5上,这些并不麻烦,WebView为我们提供

WebChromeClient 这个类,拓展这个类,然后复写里面的方法,处理起来并不是太麻烦,在此可能需要对不同版本的安卓手机做不同的处理:

代码如下:

package com;

import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import android.webkit.ValueCallback;
import android.webkit.WebChromeClient;
import android.webkit.WebView;

public class OpenFileWebChromeClient extends WebChromeClient {
    public static final int REQUEST_FILE_PICKER = 1;
    public ValueCallback<Uri> mFilePathCallback;
    public ValueCallback<Uri[]> mFilePathCallbacks;
    Activity mContext;

    @Override
    public void onReceivedTitle(WebView webView, String s) {
        super.onReceivedTitle(webView, s);
        mCenterTitle.setText(s);
    }

    public OpenFileWebChromeClient(Activity mContext) {
        super();
        this.mContext = mContext;
    } // Android < 3.0 调用这个方法

    public void openFileChooser(final ValueCallback<Uri> filePathCallback) {
        mFilePathCallback = filePathCallback;
        takeOrPickPicture();
    }

    // 3.0 + 调用这个方法
    public void openFileChooser(final ValueCallback filePathCallback, final String acceptType) {
        mFilePathCallback = filePathCallback;
        takeOrPickPicture();
    }

    // js上传文件的<input type="file" name="fileField" id="fileField" />事件捕获 // Android > 4.1.1 调用这个方法
    public void openFileChooser(final ValueCallback<Uri> filePathCallback, final String acceptType, final String capture) {
        mFilePathCallback = filePathCallback;
        takeOrPickPicture();
    }

    @Override
    public boolean onShowFileChooser(final WebView webView, final ValueCallback<Uri[]> filePathCallback, final WebChromeClient.FileChooserParams fileChooserParams) {
        mFilePathCallbacks = filePathCallback;
        takeOrPickPicture();
        return true;
    }

    private void takeOrPickPicture() {
        //系统选照片
//        Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
//        intent.addCategory(Intent.CATEGORY_OPENABLE);
//        intent.setType("*/*");
        mContext.startActivityForResult(Intent.createChooser(intent, "File Chooser"), REQUEST_FILE_PICKER);
        Intent intent = new Intent(ResumeEditActivity.this, SelectPhotoFromActivity.class);
        mContext.startActivityForResult(intent, REQUEST_FILE_PICKER);
    }
}


takeOrPickPicture()调用的是自己封装的拍照选图的操作,然后给webview设置WebChromeClient之后选图操作完成

mWebView.setWebChromeClient(mOpenFileWebChromeClient);
 

在H5上回显则需要在当前Activity里面复写onActivityResult回调方法

代码如下:
 
 /**
     * 以下代码是为了适应H5调用本地图片并且显示在h5上
     */
    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent intent) {
        if (requestCode == OpenFileWebChromeClient.REQUEST_FILE_PICKER && resultCode == Activity.RESULT_OK) {
            if (mOpenFileWebChromeClient.mFilePathCallback != null) {
                Uri result = intent == null || resultCode != Activity.RESULT_OK ? null : intent.getData();
                if (result != null) {
                    String path = ProviderPathUtils.getPath(this, result);
                    Uri uri = Uri.fromFile(new File(path));
                    mOpenFileWebChromeClient.mFilePathCallback.onReceiveValue(uri);
                } else {
                    mOpenFileWebChromeClient.mFilePathCallback.onReceiveValue(null);
                }
            }
            if (mOpenFileWebChromeClient.mFilePathCallbacks != null) {
                Uri result = intent == null || resultCode != Activity.RESULT_OK ? null : intent.getData();
                if (result != null) {
                    String path = ProviderPathUtils.getPath(this, result);
                    Uri uri = Uri.fromFile(new File(path));
                    mOpenFileWebChromeClient.mFilePathCallbacks.onReceiveValue(new Uri[]{uri});
                } else {
                    mOpenFileWebChromeClient.mFilePathCallbacks.onReceiveValue(null);
                }
            }
            onReceiveImage(intent, mOpenFileWebChromeClient.mFilePathCallback, mOpenFileWebChromeClient.mFilePathCallbacks);
            mOpenFileWebChromeClient.mFilePathCallback = null;
            mOpenFileWebChromeClient.mFilePathCallbacks = null;
        } else if (resultCode == Activity.RESULT_CANCELED) {
            if (mOpenFileWebChromeClient.mFilePathCallbacks != null) {
                //xie :直接点击取消时,ValueCallback回调会被挂起,需要手动结束掉回调,否则再次点击选择照片无响应
                mOpenFileWebChromeClient.mFilePathCallbacks.onReceiveValue(null);
                mOpenFileWebChromeClient.mFilePathCallbacks = null;
            }
        }
    }

onReceiveImage方法:

 

private void onReceiveImage(final Intent intent, final ValueCallback<Uri> filePathCallback, final ValueCallback<Uri[]> filePathCallbacks) {
        Uri imageUri = null;
        String image = intent.getStringExtra("cropImageUri");
        if (!TextUtils.isEmpty(image)) {
            imageUri = Uri.parse(image);
        }
        if(filePathCallback != null) {
            filePathCallback.onReceiveValue(imageUri);
        }
        if(filePathCallbacks != null) {
            if(imageUri != null) {
                filePathCallbacks.onReceiveValue(new Uri[]{imageUri});
            }else {
                filePathCallbacks.onReceiveValue(null);
            }
        }
    }



至此整个过程处理完毕,我来分析下,开篇提到的BUG,其实还是因为粗心所致,问题是这样的,我们选图时会回调ValueCallBack,但是恰巧此时你并没有选图而是直接点击取消

而整个ValueCallBack会被挂起,也就是说,此次回调一直在等待回调结果,但是一直等不到结果,所以后面再有请求触发就会一直得不到响应,所以导致出现了这个问题。
那我们需要做的就是,当用户并没有选择文件的时候,我们需要手动结束调此次回调过程,避免请求被挂起。
 
   if(resultCode==Activity.RESULT_CANCELED){
        if (mOpenFileWebChromeClient.mFilePathCallbacks != null) {
            //xie :直接点击取消时,ValueCallback回调会被挂起,需要手动结束掉回调,否则再次点击选择照片无响应
            mOpenFileWebChromeClient.mFilePathCallbacks.onReceiveValue(null);
            mOpenFileWebChromeClient.mFilePathCallbacks = null;
        }
    }


方法总比困难多,BUG并不怕,怕的是找不到出BUG的原因呢。

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值