Android WebView拍照和上传文件

Android webview支持H5页面通过js实现文件上传、图片上传 一、问题场景: 项目中遇到通过网页上传文件的需求,IOS直接是支持的,安卓端却没反应,有些机型甚至闪退。其实是Android的webview默认是不支持<input type="file"/>文件上传的。现在的前端页面需要处理的是: 1.打开本地文件选择器 2.用户选择需要上传的文件 3.处理用户选择的文件通知webview ... 阅读详情

1. 前言

拍照上传或者上传图片、视频、文档等文件,这种需求对于移动端来说是很基本的。Android原生实现这种需求没什么特别大的难度。但如果是嵌套的H5页面的话,就需要踩点坑了。Android 的这个 WebView 真是个不让人省心的控件啊!

2. 解决方案

废话不多说,直接上关键代码。首先,重写 WebView 的 WebChromeClient 中的 openFileChooser() 方法。

mWebView.setWebChromeClient(new WebChromeClient() {

    // For Android < 3.0
    public void openFileChooser(ValueCallback<Uri> uploadMsg) {
        mAcceptType = "*/*";
        toOpenFileChooser(uploadMsg);
    }

    // For Android >= 3.0
    public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType) {
        if (TextUtils.isEmpty(acceptType)) {
            mAcceptType = "*/*";
        }
        mAcceptType = acceptType;
        toOpenFileChooser(uploadMsg);
    }

    // For Android >= 4.1.1
    public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType, String capture) {
        if (TextUtils.isEmpty(acceptType)) {
            mAcceptType = "*/*";
        }
        mAcceptType = acceptType;
        toOpenFileChooser(uploadMsg);
    }

    // For Android >= 5.0
    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    @Override
    public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> filePathCallback, FileChooserParams fileChooserParams) {
        String[] acceptTypes = fileChooserParams.getAcceptTypes();
        if (acceptTypes.length > 0) {
            if (TextUtils.isEmpty(acceptTypes[0])) {
                mAcceptType = "*/*";
            } else {
                mAcceptType = acceptTypes[0];
            }
        } else {
            mAcceptType = "*/*";
        }
        toOpenFileChooserAnother(filePathCallback);
        return true;
    }
});

Android的碎片化真严重,得重写4个方法,但根据参数的情况,只有2种处理方案。这里其实有一个大坑,就是Android 5.0以下的部分设备,会触发不了 openFileChooser() 方法。而且这个大坑没有任何解决方法,好在现在都2020年了,大多数人用的系统都是5.0以上的。

toOpenFileChooser(uploadMsg) 和 toOpenFileChooserAnother(filePathCallback) 这两个方法的具体代码如下所示:

private static final int REQUEST_CODE_FILE_CHOOSER = 0;
private static final int REQUEST_CODE_FILE_CHOOSER_ANOTHER = 1;
/**
 * 拍照上传的请求码
 */
private static final int REQUEST_CODE_PHOTO_UPLOAD = 3;

/**
 * 打开文件选择器,适用于Android 5.0 以下
 *
 * @param uploadMsg 加载文件的信息
 */
private void toOpenFileChooser(ValueCallback<Uri> uploadMsg) {
    mUploadMessage = uploadMsg;
    Intent i = new Intent(Intent.ACTION_GET_CONTENT);
    i.addCategory(Intent.CATEGORY_OPENABLE);
    i.setType(mAcceptType);
    startActivityForResult(Intent.createChooser(i, getString(R.string.choose_app)), REQUEST_CODE_FILE_CHOOSER);
}

/**
 * 打开文件选择器,适用于Android 5.0 及以上
 *
 * @param uploadMsg 加载文件的信息
 */
private void toOpenFileChooserAnother(ValueCallback<Uri[]> uploadMsg) {
    mUploadMessageAnother = uploadMsg;
    if ((mAcceptType.equals("*/*") || mAcceptType.contains("image"))
      && ContextCompat.checkSelfPermission(mContext, Manifest.permission.CAMERA) == PackageManager.PERMISSION_DENIED) {
        long oldTime = PreferencesUtils.getLong(mContext, Constant.PREF_REQUEST_CAMERA_TIME);
        long newTime = System.currentTimeMillis();

        if (oldTime == -1) { // 首次要提示申请权限
            PreferencesUtils.putLong(mContext, Constant.PREF_REQUEST_CAMERA_TIME, newTime);
            toRequestCameraPermission();
            return;
        } else {
            if (newTime - oldTime >= 7 * 24 * 60 * 60 * 1000) { // 7天后再提示申请权限
                PreferencesUtils.putLong(mContext, Constant.PREF_REQUEST_CAMERA_TIME, newTime);
                toRequestCameraPermission();
                return;
            }
        }
    }
    toOpenFileChooserAnother();
}

/**
 * 打开文件选择器,适用于Android 5.0 及以上
 */
private void toOpenFileChooserAnother() {
    Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
    if ((mAcceptType.equals("*/*") || mAcceptType.contains("image"))
        && takePictureIntent.resolveActivity(mContext.getPackageManager()) != null) {
        File photoFile = null;
        try {
            if (ContextCompat.checkSelfPermission(mContext, Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED) {
                String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.CHINA).format(new Date());
                String imageFileName = "PIC_" + timeStamp + "_";
                File storageDir = new File(DirUtils.getPictures());
                if (!storageDir.exists()) {
                    storageDir.mkdirs();
                }
                photoFile = File.createTempFile(imageFileName, ".jpg", storageDir);
            }
        } catch (Exception e) {
            Log.d(Constant.TAG, mClassName + " Unable to create Image File", e);
        }

        if (photoFile != null) {
            mCameraPhotoPath = photoFile.getAbsolutePath();
            Log.d(Constant.TAG, "图片路径 : " + mCameraPhotoPath);
            takePictureIntent.putExtra("PhotoPath", "file:" + mCameraPhotoPath);
            takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(photoFile));
        } else {
            takePictureIntent = null;
        }
    } else {
        takePictureIntent = null;
    }

    Intent[] intentArray;
    if (takePictureIntent != null) {
        intentArray = new Intent[]{takePictureIntent};
    } else {
        intentArray = new Intent[0];
    }

    Intent contentSelectionIntent = new Intent(Intent.ACTION_GET_CONTENT);
    contentSelectionIntent.addCategory(Intent.CATEGORY_OPENABLE);
    contentSelectionIntent.setType(mAcceptType);

    Intent chooserIntent = new Intent(Intent.ACTION_CHOOSER);
    chooserIntent.putExtra(Intent.EXTRA_INTENT, contentSelectionIntent);
    chooserIntent.putExtra(Intent.EXTRA_TITLE, getString(R.string.choose_app));
    chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, intentArray);

    startActivityForResult(chooserIntent, REQUEST_CODE_FILE_CHOOSER_ANOTHER);
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
    switch (requestCode) {
        case REQUEST_CODE_FILE_CHOOSER:
            if (mUploadMessage == null) {
                return;
            }
            Uri result = (intent == null || resultCode != RESULT_OK) ? null : intent.getData();
            mUploadMessage.onReceiveValue(result);
            mUploadMessage = null;
            break;
        case REQUEST_CODE_FILE_CHOOSER_ANOTHER: // Android 5.0 及以上
            if (mUploadMessageAnother == null) {
                return;
            }

            Uri[] results = null;
            if (resultCode == RESULT_OK) {
                if (intent != null) {
                    results = new Uri[]{intent.getData()};
                } else {
                    if (mCameraPhotoPath != null) {
                        results = new Uri[]{Uri.parse("file:" + mCameraPhotoPath)};
                    }
                }
            } else {
                if (!TextUtils.isEmpty(mCameraPhotoPath)) {
                    File file = new File(mCameraPhotoPath);
                    file.delete();
                }
            }

            mUploadMessageAnother.onReceiveValue(results);
            mUploadMessageAnother = null;
            break;
        case REQUEST_CODE_PHOTO_UPLOAD:
            toOpenFileChooserAnother();
            break;
        default:
            super.onActivityResult(requestCode, resultCode, intent);
            break;
    }
}

拍照上传,是需要申请“相机权限”的,上面的 toRequestCameraPermission() 方法就是申请权限的,具体代码我就不贴出来了。如果想看完整的demo,可以查看我放在GitHub上面的项目 AndroidWebView。

 

如果想进一步交流和学习的同学,可以加一下QQ群哦!

Android——UI篇:WebView里调用相机/文件选取照片并上传。         最近的开发项目中有一个需求,就是在嵌入webview上,需要在webview端来调起本地的相机拍照,或者调起本地文件选择图片并上传到服务器,当然上传这一块的接口是Web端的事情啦,所以我们只管把我们拍照/选取文件的文件地址传给webview端,就可以了,因为我也是刚工作没多久,这个需求以前也是从没接触过,所以这些东西也是从网上参考过来的,然后经过自己的修改,最后测试成功。     ... 阅读详情

相关推荐

Android WebView中文件上传功能的实现

在该方法中,我们首先检查之前的文件上传回调是否已存在,如果存在,则取消之前的回调。如果是,我们首先检查fileUploadCallback是否存在,如果存在,则获取文件选择器返回的结果,并通过fileUploadCallback.onReceiveValue()方法将结果传递给WebView。通过以上步骤,我们就实现了在Android应用的WebView中支持文件上传的功能。在网页中,当用户点击文件上传按钮时,将会启动文件选择器,用户可以选择本地文件进行上传操作。如果你有任何问题,请随时提问。

ScriptCharm的博客 1449

webview 嵌入H5网页支持 拍照、录像、文件选择等功能

在日常开发中,app中经常有嵌入前端网页的需求,里面如果有一些调用相机拍照、录视频、查看本地图片功能时,需要Android WebView端做一些配置、来保证能顺利调起相应的Intent,来适配前端程序需求一:webView端调用相机拍照,同时回传给前端程序@Override//数据回传会用到,记录成全局= null) {//最终通过fileChooserParams.isCaptureEnabled()方法来解决你的困惑 官方解释是否为设备//所以这里写调用相机逻辑} else {

黑夜骑士 2296

Android下WebView中调用系统相机拍照范例

自定义webview中的网页“拍照”按钮调用系统相机拍照的API接口MyBrowserAPI.CapturePhoto(filename),在网页JavaScript中调用以后返回存放照片的完整路径名,默认将照片存放在系统SD卡的根目录,包含整个工程中需要添加的每个重要代码和JavaScript网页代码及详细描述。实测从Android2.1-4.22版虚拟机与真机均可正常使用。

Android WebView 选择图片并上传(调用相机拍照/相册/选择文件)

前言: 这个功能其实我才刚接触。不熟...在这个给大家提供的都是经过本人验证之后的一些案例。可以在项目中跑的。 最近项目嵌入混合开发,都是使用WebView来跳转,页面展示。有用到这个图片上传的功能。 原本是一脸懵的,查了很多资料看一些大神都写的很多代码很复杂(原谅我是小白) 正文: 先看一下效果先: 代码: 我这里代码都是写在Fragment里面的 直接...

WL-鬼 1万+

Matlab2021a破解版安装与激活实战教程(含详细步骤截图)

本文详细介绍了MATLAB R2021a的正版安装流程与核心功能优化,包括系统要求、安装步骤、性能调优及深度学习工具箱的应用。通过实战教程和代码示例,帮助用户高效搭建开发环境并掌握关键技术,特别适合工程计算与科学研究的专业人士。

vvv99的博客 461

abaqus运行报错 WindowsError:[Error 2]

abaqus提交job总是提示“WindowsError [Error 2”,报这个错误,可能是由于安装其他软件改变了abaqus软件的路径导致,总结了看到的教程,按照下面的方法可以解决这个问题。 步骤一:找到你的abaqus安装路径(我是按照一个安装视频安装的,安装路径为SIMULI1),然后找到SIMULIA文件夹,点击进入后找到commands文件夹,将这个路径复制下来。 步骤二:我的电脑右键属性,在左侧中找到高级系统设置并...

az101za的博客 1万+

android使用webview上传文件(支持相册和拍照),支持最高6.0安卓系统(改进版)

1.注意 mUploadMessage.onReceiveValue(Uri.parse("")); 必须得到调用,无论用户是否选了图,否则会出现再点击不响应的情况 [python] view plain copy ===文一==================================================================

HAPP NEW JAVA 1万+

如何在windows下使用cmake编译源码

MyProject/└── build/在MyProject目录下创建并编辑。创建build目录并进入。使用cmake命令生成构建文件。使用适当的命令编译项目。运行生成的可执行文件。

cdj444asdg的博客 3345

android兼容拍照相册多张,android使用webview上传文件(支持相册和拍照),支持最高6.0安卓系统(改进版)...

1.注意mUploadMessage.onReceiveValue(Uri.parse(""));必须得到调用,无论用户是否选了图,否则会出现再点击不响应的情况2.上面的参考由于比较老,不适用于安卓5.0系统,因为谷歌5.0以后对webkit做了改动,汇总改进后得出我写的:(最高6.0的安卓系统都支持,已测试使用)package com.fuiou.webviewupload;import jav...

weixin_28745067的博客 384

LPC2124定时器实现跑马灯

文章目录一、keil 4新建工程 一、keil 4新建工程 1、Create New Project,注意,最好添加进一个新建好的文件夹里,keil不会帮你新建。 2、添加设备类型:NXP目录下的LPC2124 3、选择启动文件Startu.s 4、new 一个file,保存命名为.c文件 5、添加进project里,右击,add 选中,添加 6、设置编译输出.hex文件 ...

qq_37937830的博客 5753

【保姆级教程】YOLOv8_OBB旋转目标检测:训练自己的数据集

【保姆级教程】YOLOv8_OBB旋转目标检测:训练自己的数据集

m0_51579041的博客 1万+

android使用webview上传文件,android使用webview上传文件(支持相册和拍照)

mWebView.setWebChromeClient(new TestWebChromeClient(new WebChromeClient()) {@Override public void openFileChooser(ValueCallback uploadFile) { //===文一===================================================...

weixin_42386504的博客 540

提升ARM Cortex-M系统性能的关键技术:TCM技术解析与实战指南

TCM技术为ARM Cortex-M处理器提供了宝贵的确定性性能提升手段,特别适合对时序敏感的实时应用。通过合理配置和优化,工程师可以显著提高系统性能、降低中断响应时间并优化功耗。随着嵌入式系统对实时性要求的不断提高,TCM技术将在工业控制、汽车电子、医疗设备等领域发挥更加重要的作用。未来,ARM处理器可能会进一步扩展TCM容量并优化其与其他内存子系统的协同工作方式,为开发者提供更强大的实时性能保障。

1681

android使用webview上传文件(支持相册和拍照)

mWebView.setWebChromeClient(new TestWebChromeClient(new WebChromeClient()) {@Override public void openFileChooser(ValueCallback uploadFile) { //

千里之外 5万+

老电脑续命神器:Windows 11 26H1 精简游戏版,帧率稳定无压力!(Win11 26H1 极致精简游戏版(3.17G):装完只占 8G 内存,Ultra CPU 性能拉满)

旧电脑福音也能安装windows11畅玩游戏🎮:文章分享一款 Windows 11 26H1 精简游戏版,仅 3.17G、C 盘占用 8G,开机进程约 50 个,内存占用 1.4G,内置游戏优化与运行库,支持离线安装、跳过 TPM 检测,让老电脑也能畅玩 3A 游戏和办公娱乐 🚀。

XiaoqiangClub的博客 1065

SpringBoot实战教程-springboot概论

Spring Boot 是一个快速开发框架,能够快速的整合第三方框架,简化XML配置,全部采用注解形式,以及自动配置。内置web容器,帮助开发者能够实现快速开发,简化了应用系统的初始搭建以及开发过程。

鸟哥哥的专栏 4155

Android:使用webview上传文件(支持相册和拍照) .

===文一==================================================================mWebView.setWebChromeClient(new TestWebChromeClient(new WebChromeClient()) {@Override public void openFil

Ke1vin的博客 988

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

在Android浏览器中通过WebView调用相机拍照/选择文件 上传到服务器

在Android浏览器中通过WebView调用相机拍照/选择文件 上传到服务器

qq_43685425的博客 522

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

RU DOS版、EFI版32bit/64bit BIOS常用工具

DOS版、EFI版的RU工具,可用来查看IO、MEM、PCI、SMBIOS等资源。亲测在EFI SHELL下可用。

深坑之Webview,解决H5调用android相机拍照和录像

最近在开发过程中遇到一个问题,主要是调用第三方的实名认证,需要拍照和录像; 办过支付宝大宝卡和腾讯的大王卡的都知道这玩意,办卡的时候就需要进行实名认证,人脸识别; 本来第三方平台(xxx流量公司)说的是直接用WebView加载这个H5界面就完事了,我心想这么简单,那不是分分钟的事,放着后面做(公司就我一个安卓,所以开发都是我说的算_,独立开发有的时候还是挺爽); 结果到项目快要上线的时候,只...

zgphacker2010的专栏 1694

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

上一篇: Android WebView播放视频并支持全屏
下一篇: 计算机及相关专业的同学如何规划大学四年?
Fantasy丶Lin
博客等级 码龄11年 92粉丝 59原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值