Android 使用腾讯X5浏览器上传图片(拍照/相册)

2,804 阅读3分钟

这几天在客户端接入一个Web页的客服系统,用来接受用户的反馈和建议。Android客户端集成这个客服H5之后,图片死活传递不上去。看了一下iOS同事的集成效果,可以自由上传图片,再把H5的地址用Android原生浏览器打开,也可以正常打开相册上传图片。

What??? 见鬼了, 气抖冷!!!

看了一些博客,使用Android的WebView在默认情况下是不能够支持上传文件的(需要重写 onShowFileChooser方法)。那就只能撸起袖子自己干了。

项目中使用的浏览器内核是腾讯X5浏览器,那就去腾讯X5的技术文档看看有没有实现方式:TBS开发指引, 找了一下发现还真有

1、文件选择

方法一: 文件单选:设置client回调

mWebView.setWebChromeClient(new WebChromeClient() {
    @Override
    public void openFileChooser(
        ValueCallback<Uri> uploadFile,
        String acceptType, 
        String captureType) {
        //保存对应的valuecallback供选择后使用
        //通过startActivityForResult启动文件选择窗口或自定义文件选择
    } 
});

文件多选:设置client回调

mWebView.setWebChromeClientExtension(new ProxyWebChromeClientExtension() {
    @Override
    public void openFileChooser(
        android.webkit.ValueCallback<Uri[]> uploadFile, 
        String acceptType,
        String captureType) {
        //保存对应的valuecallback供选择后使用
        //通过startActivityForResult启动文件选择窗口或自定义文件选择    
    }
});

方法二: 设置client回调(单选多选均会回调该接口)

mWebView.setWebChromeClient(new WebChromeClient() {
    @Override
    public boolean onShowFileChooser(
        IX5WebViewBase webView, 
        ValueCallback<Uri[]> filePathCallback,
        FileChooserParams fileChooserParams) {
        //保存对应的valuecallback供选择后使用
        //通过startActivityForResult启动文件选择窗口或自定义文件选择
    }    
});

然后在activity返回时将用户的选择设置给对应的ValueCallback

protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    //如果是文件选择
    if (resultCode == RESULT_OK) {
        //给文件选择的ValueCallback设置onReceiveValue值
    } else if (resultCode == RESULT_CANCELED) {
        //给文件选择的ValueCallback设置null值
    }
}

2、实现文件单选

在项目自定义的WebChromeClient 中,重写openFileChooser方法, 调用项目中图片选择组件,图片选择成功后将生成的uri使用valueCallback回调,即可上传成功

    // 图片单选上传
    @Override
    public void openFileChooser(ValueCallback<Uri> valueCallback, String s, String s1) {
        Log.i(TAG, "openFileChooser: acceptType:  " + s + "    captureType:  " + s1);
        
        // 调用项目中图片选择组件
        // 图片选择成功后将生成的uri使用valueCallback回调 
        // 即可上传成功
        
    }
    // 很多博客介绍了, 要写很多Android各个API的兼容代码, 其实不用。 X5在这个方法底层其实实现了兼容各系统的能力,不需要上层开发者来实现。 只需实现这一个方法即可
    

实现效果:

3、举个例子

为简单起见, 集成一个第三方的图片选择控件

github.com/thewyp/Avat…

集成方式:

dependencies {
                ...
                compile 'me.thewyp:avatar:1.0.4'
           }

使用方式:

new AvatarStudio.Builder(activityContext)
                            .needCrop(true)//是否裁剪,默认裁剪
                            .setTextColor(Color.BLUE)
                            .dimEnabled(true)//背景是否dim 默认true
                            .setAspect(1, 1)//裁剪比例 默认1:1
                            .setOutput(200, 200)//裁剪大小 默认200*200
                            .setText("打开相机", "从相册中选取", "取消")
                            .show(new AvatarStudio.CallBack() {
                                @Override
                                public void callback(String uri) {
                                     //uri为图片路径
                                     Picasso.with(activityContext).load(new File(uri)).into(mImageView);
                                }
                            });

实现Web上传图片

public class WebChromeClientImpl extends WebChromeClient {
    ......
        // 图片单选上传
    @Override
    public void openFileChooser(ValueCallback<Uri> valueCallback, String s, String s1) {
        Log.i(TAG, "openFileChooser: acceptType:  " + s + "    captureType:  " + s1);
        
        new AvatarStudio.Builder(context)
            .needCrop(true)//是否裁剪,默认裁剪
            .setTextColor(Color.BLUE)
            .dimEnabled(true)//背景是否dim 默认true
            .setAspect(1, 1)//裁剪比例 默认1:1
            .setOutput(200, 200)//裁剪大小 默认200*200
            .setText("打开相机", "从相册中选取", "取消")
            .show(new AvatarStudio.CallBack() {
                @Override
                public void callback(String uri) {
                    //uri为图片路径
                    valueCallback.onReceiveValue(Uri.parse(uri)); // 将生成的Uri使用valueCallback 回调给X5底层,实现图片上传
                }
            });
    }
    ......
}

至此,图片的上传就实现了。文件的实现也是同理, 大家感兴趣的可以试试