Android 处理webview内H5的input标签的上传问题

简介

本文将解决以下一些问题(如有错误,可指正,谢谢):

  1. 解决在webview中input标签type="file"不能使用的问题;
  2. 解决上传文件的多选问题;
  3. 解决Android获取input标签中accept属性,从而实现动态选择文件类型的问题;

碰到的问题

PS:以下都是搜索各种博客得来的信息;

HTML中input标签type="file"无法使用

默认的情况下在HTML中 写< input type=“file” />的时候回弹出选择文件的窗口,但实际上在webview中默认的是不弹出窗口的,不能打开android资源管理器。
是因为 android webview 由于考虑安全原因屏蔽了 < input type=“file”/> 这个功能 。

不过 Android 还是为我们预留出一些 api 来,我们可以进行一定的扩展和自由发挥。
但是这样的 api 又有版本的变化,适配变得比较麻烦了。

重写webview 的WebChromeClient
步骤:

  1. 重载文件选择按钮被点击后的方法,即onShowFileChooser()方法(Android>5.0)。

  2. 在onShowFileChooser()方法中声明一个意图,打开文件选择相对应的Activity,即FILE_CHOOSER_RESULT_CODE。

  3. 重载onActivityResult()方法,在里面接收用户选择的文件的Uri,传给input标签。

文件多选功能无法使用

  1. private ValueCallback<Uri[]> uploadMessage; //多选文件回调

  2. //此处增加参数 允许多选文件
    intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE,true);

  3. onActivityResult回调方法中配置好接收多选的文件

怎么获取input中accept属性的值

onShowFileChooser方法只提供了一个webview对象,一个ValueCallback回调,以及FileChooserParams。FileChooserParams提供的getAcceptTypes方法能够获取input中accept属性的值,但是它会将属性值通过逗号切割开,返回字符串数组。

intent.setType无法指定浏览本地多种类型的文件

这是正常的访问系统自带的文件管理器。但是setType只支持单个setType一般是以下这种(以只查看图片文件为例):

intent.setType("image/*");

在API>=19之后设置多个类型采用以下方式,setType不再支持多个类型;
需要使用intent.putExtra():

intent.putExtra(Intent.EXTRA_MIME_TYPES, mimetypes);

//例子:支持图片和pdf的上传
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
    intent.putExtra(Intent.EXTRA_MIME_TYPES,
            new String[]{"image/*","application/pdf"});
}

并且必须是MIME格式的

MimeType
多用途互联网邮件扩展(MIME,Multipurpose Internet Mail Extensions)是一个互联网标准,它扩展了电子邮件标准,使其能够支持非ASCII字符、二进制格式附件等多种格式的邮件消息。
请参阅 IANA MIME 类型,获得标准 MIME 类型的完整列表。

代码

Android代码



public class WebViewActivity extends AppCompatActivity {
    private Context context;
    private WebView webView;

    private ValueCallback<Uri> uploadMessage;//单选文件回调
    public ValueCallback<Uri[]> uploadMessageAboveL; //多选文件回调

    private final static int FILE_CHOOSER_RESULT_CODE = 10000;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.webview_layout);
        context = this;

        initView();
    }

    public void initView() {

        webView = findViewById(R.id.wView);

        自定义 WebChromeClient 辅助WebView处理图片上传操作【<input type=file> 文件上传标签】
        webView.setWebChromeClient(new WebChromeClient() {
            /*
            重写 WebChromeClient中的 openFileChooser() 和 onShowFileChooser()方法,由于在不同安卓版本的方法不大一样,所以要分别进行实现。

             通过对比这两个方法可以看出它们的区别,openFileChooser中传入的参数ValueCallback接口回传一个Uri的对象,
             而onShowFileChooser回传一个Uri[]数组,因此在onActivityResult回调方法中调用ValueCallback接口方法onReceiveValue传入参数需特别注意对于这两种方法的回调要区别对待。
             原文链接:https://blog.csdn.net/teagreen_red/article/details/75579016
             */
            // For Android >= 5.0   才支持多选
            @Override
            public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> filePathCallback, WebChromeClient.FileChooserParams fileChooserParams) {
                uploadMessageAboveL = filePathCallback;

                openImageChooserActivity(fileChooserParams.getAcceptTypes());

                return true;
            }
        });

        webView.getSettings().setJavaScriptEnabled(true);  //设置WebView属性,运行执行js脚本
        webView.getSettings().setDomStorageEnabled(true);//DOM Storage

        // 开启DOM缓存,开启LocalStorage存储(html5的本地存储方式)
        webView.getSettings().setDomStorageEnabled(true);

        webView.getSettings().setAllowContentAccess(true); // 是否可访问Content Provider的资源,默认值 true
        webView.getSettings().setAllowFileAccess(true);    // 是否可访问本地文件,默认值 true

        webView.loadUrl(Config.domain + "test2");          //调用loadUrl方法为WebView加入链接

    }

    /**
     * 打开文件管理器  选择文件
     */
    private void openImageChooserActivity(String[] acceptType) {
        Intent i = new Intent(Intent.ACTION_GET_CONTENT); //允许用户选择特殊种类的数据,并返回

        //一个布尔型值,声明用户是否可以一次选择多个文件。
        i.putExtra(Intent.EXTRA_ALLOW_MULTIPLE,true);
        i.addCategory(Intent.CATEGORY_OPENABLE); //增加一个可打开的分类

        i.setType("*/*");

        //在API>=19之后设置多个类型采用以下方式,setType不再支持多个类型
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
            i.putExtra(Intent.EXTRA_MIME_TYPES,
//                    new String[]{"image/jpeg","image/jpg","image/png","application/pdf"});
                    acceptType);
        }

        startActivityForResult(Intent.createChooser(i, "Image Chooser"), FILE_CHOOSER_RESULT_CODE);

    }

    /*
    回调函数?
    在onActivityResult里处理获取到的文件
    重载onActivityResult()方法,在里面接收用户选择的文件的Uri,传给input标签
     */
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode == FILE_CHOOSER_RESULT_CODE) {
            if (null == uploadMessage && null == uploadMessageAboveL) return;
            Uri result = data == null || resultCode != RESULT_OK ? null : data.getData();
            if (uploadMessageAboveL != null) {
                onActivityResultAboveL(requestCode, resultCode, data);
            } else if (uploadMessage != null) {
                uploadMessage.onReceiveValue(result);
                uploadMessage = null;
            }
        }

    }

    /*
    android 5.0
    多文件的结果返回处理
     */
    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    private void onActivityResultAboveL(int requestCode, int resultCode, Intent intent) {
        Log.d("test1234","onActivityResultAboveL");

        if (requestCode != FILE_CHOOSER_RESULT_CODE || uploadMessageAboveL == null)
            return;
        Uri[] results = null;
        if (resultCode == Activity.RESULT_OK) {
            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;
    }
}

HTML代码

前端H5配置好input标签的accept属性,遵守MIME格式的规则,供Android获取配置;

   <input type="file" accept="image/jpeg, image/jpg, image/png,application/pdf"/>

实现效果

搜索到配置得image和pdf
长按可选取多张图片上传

参考

安卓WebView文件上传的实现(解决安卓WebView中<input type=‘file‘/>标签点击没反应)
android下webview实现H5 html标签 input file类型文件多选 multiple 属性的支持
Android webview H5页面input选择文件传递参数
Android开发文档(文件存储-打开特定类型的文件)
android intent.setType指定浏览本地多种类型的文件

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值