Android中WebView选择本地图片上传

引言

在我们使用webView的时免不了要和原生的交互,其中就会遇到WebView上传文件的逻辑:当我们在Web页面上点击选择文件的控件()时,会回调WebChromeClient下的openFileChooser()(5.0及以上系统回调onShowFileChooser())。这个时候我们在openFileChooser方法中通过Intent打开系统相册或者支持该Intent的第三方应用来选择图片。

解决方式.

1.首先我们要自定义一个WebChromeClient继承WebChromeClient并实现相关的方法

Android3.0以下的调用

public void openFileChooser(ValueCallback<Uri> uploadMsg)

Android3.0以上:

public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType)

Android4.4以下:

public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType, String capture)

Android5.0以上:

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

提示:这里有个漏洞,4.4.x的由于系统内核发生了改变,没法调用以上方法,现在仍然找不到解决办法,唯一的方法就是4.4直接使用手机浏览器打开,这个是可以的。

具体代码如下:

private ValueCallback<Uri> mUploadMessage;
private ValueCallback<Uri[]> mUploadCallbackAboveL;
public class MyWebViewChromeClient extends WebChromeClient {
public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType) {
    openFileChooserImpl(uploadMsg);
}

//3.0--
public void openFileChooser(ValueCallback<Uri> uploadMsg) {
    openFileChooserImpl(uploadMsg);
}

//4.1
public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType, String capture) {

    openFileChooserImpl(uploadMsg);
}


@Override
public boolean onShowFileChooser(WebView mWebView, ValueCallback<Uri[]> filePathCallback, FileChooserParams fileChooserParams) {
    openFileChooserImplForAndroid5(filePathCallback);

    return true;
}
}
private void openFileChooserImplForAndroid5(ValueCallback<Uri[]> uploadMsg) {
    mUploadCallbackAboveL = uploadMsg;
    dispatchTakePictureIntent();
}

//5.0以下的掉用
private void openFileChooserImpl(ValueCallback<Uri> uploadMsg) {
    mUploadMessage = uploadMsg;
    dispatchTakePictureIntent();
}

//拍照
private void dispatchTakePictureIntent() {
    selectImgDialog();

}
 private void takePhoto() {
        Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
        if (takePictureIntent.resolveActivity(getActivity().getPackageManager()) != null) {
            Uri imageUri = null;
            try {
                imageUri = Uri.fromFile(createImageFile());
            } catch (IOException e) {
                e.printStackTrace();
            }
            takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
            startActivityForResult(takePictureIntent, FILECHOOSER_RESULTCODE);
        }
    }

    /**  * 209.  * 本地相册选择图片  * 210.  */  private void chosePic() {
        Intent innerIntent = new Intent(Intent.ACTION_GET_CONTENT);
        String IMAGE_UNSPECIFIED = "image/*";
        innerIntent.setType(IMAGE_UNSPECIFIED); // 查看类型
        Intent wrapperIntent = Intent.createChooser(innerIntent, null);
        startActivityForResult(wrapperIntent, REQ_CHOOSE);
    }


    String mCurrentPhotoPath = null;
    String FileName = "forum";

    //创建文件夹包装图片
    private File createImageFile() throws IOException {
        File storageDir = new File(Util.getAppPath(getActivity()) + FileName);

        if (!storageDir.exists()) {
            storageDir.mkdirs();
        }
        storageDir = new File(Util.getAppPath(getActivity()) + FileName + "/", System.currentTimeMillis() + ".jpg");
        //保存当前图片路径
        mCurrentPhotoPath = storageDir.getAbsolutePath();
        return storageDir;
    }

    //onActivityResult回调
    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);

        if (requestCode == FILECHOOSER_RESULTCODE || requestCode == REQ_CHOOSE) {
            if (null == mUploadMessage && null == mUploadCallbackAboveL) return;
            Uri result = data == null || resultCode != RESULT_OK ? null : data.getData();
            if (mUploadCallbackAboveL != null) {
                onActivityResultAboveL(requestCode, data);
            } else if (mUploadMessage != null) {
                mUploadMessage.onReceiveValue(result);
                mUploadMessage = null;
            }
        }

    }

    //5.0以上版本,由于api不一样,要单独处理
//    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    private void onActivityResultAboveL(int requestCode, Intent data) {

        if (mUploadCallbackAboveL == null) {
            return;
        }
        Uri result = null;
        if (requestCode == FILECHOOSER_RESULTCODE) {
            File file = new File(mCurrentPhotoPath);
            Uri localUri = Uri.fromFile(file);
            Intent localIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, localUri);
            getActivity().sendBroadcast(localIntent);
            result = Uri.fromFile(file);

        } else if (requestCode == REQ_CHOOSE) {
            result = data.getData();
        }
        mUploadCallbackAboveL.onReceiveValue(new Uri[]{result});
        mUploadCallbackAboveL = null;
        return;
    }

解决5.0以下机型还是无法弹出的问题.

注意:现openFileChooser()是系统API,如果release包是开启了混淆的,所以在打包的时候混淆了openFileChooser(),这就导致无法回调openFileChooser()了。因此我们需要在混淆文件里面进行keep

-keepclassmembers class * extends android.webkit.WebChromeClient{
       public void openFileChooser(...);
}

接下来解决某些设备只弹出一次问题

在stackoverflow搜了半天也没有找到合适答案,于是再看了下onShowFileChooser的api,忽然发现了一句话
To cancel the request, call filePathCallback.onReceiveValue(null) and return true.
恍然大悟,原来取消依然是需要回调onReceiveValue。因此在当前页面onResume时候加上如下代码
filePathCallback.onReceiveValue(null);问题就可以得到解决。
在onactivityresult函数里面进行判断就可以了.

 if (requestCode == UCrop.REQUEST_CROP || requestCode == REQ_CHOOSE) {
     if (data == null) {
         if (mUploadCallbackAboveL != null) {
             mUploadCallbackAboveL.onReceiveValue(null);
             mUploadCallbackAboveL = null;
         }
         if (mUploadMessage != null) {
             mUploadMessage.onReceiveValue(null);
             mUploadMessage = null;
         }
     }
 }
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值