头图

「持续兼容」微信H5选择照片(图片&视频)及拍照&录像

前言

做过H5调用手机相册或者拍照的同学可能深有体会,在不同型号手机和不同的浏览器上表现各有差异,实属头疼。由于手机自带浏览器或者第三方浏览器实在太多,结合最近正在做的项目用户群体P90在微信上,文本单从兼容微信浏览器方面进行实验分析。

差异表现

一般的,使用<input type="file" />调用其手机的文件资源管理器,通过accept="image/*,video/*"属性区分调用相册,相册中筛选文件类型,可以是图片具体的格式,或者是视频的具体格式。采用capture="camera"属性唤起相机,而在唤起相机后,是进行拍照还是录像是由accept决定。
然后,真的会如上标准定义操作我们的手机吗?答案是否定的,Android和IOS上的表现差异较大,下面分别分析一下它们的差异性。

accept在Android和IOS的表现

添加accept属性,在IOS微信浏览器上,点击后,会弹窗原生选择,待用户下一步操作,如果accept的属性值

  • 仅有image/xxx -> 选项【照片图库】【拍照】,点击【拍照】-> 唤起相机,只能拍照,点击【照片图库】-> 打开相册,只能选择图片
  • 仅有video/xxx -> 选项【照片图库】【录像】,点击【录像】-> 唤起相机,只能录像,点击【照片图库】-> 打开相册,只能选择视频
    image.png
  • video/xxx,video/xxx -> 选项【照片图库】【拍照或录像】,点击【录像】-> 唤起相机,能录像和拍照,点击【照片图库】-> 打开相册,能选择视频和图片
    image.png
    由此可知,IOS上的表现与属性值的预期一致。
    在Android微信浏览器上,点击后,会弹出原生的选择弹框,确认用户下一步操作
    image.png
    接下来分别点击【拍摄】和【从相册选择】进行测试。
  • accept="image/*" -> 唤起原生 【拍摄】 和 【从相册中选择】弹窗 -> 点击【拍摄】唤起相机-拍照功能,点击【从相册中选择】-只能选择图片,没有视频,安卓手机
  • accept="image/,video/" -> 唤起原生 【拍摄】 和 【从相册中选择】弹窗 -> 点击【拍摄】唤起相机-拍照功能,点击【从相册中选择】-只能选择图片,没有视频,安卓手机
  • accept="video/,image/" -> 唤起原生 【拍摄】 和 【从相册中选择】弹窗 -> 点击【拍摄】唤起相机-拍照功能,点击【从相册中选择】-只能选择视频,没有图片,安卓手机
  • accept="video/*" -> 唤起原生 【拍摄】 和 【从相册中选择】弹窗 -> 点击【拍摄】唤起相机-摄像功能,点击【从相册中选择】-只能选择视频,没有图片,安卓手机
  • accept="video/mp4,video/ogg,video/webm,video/mov" -> 唤起原生 【拍摄】 和 【从相册中选择】弹窗 -> 点击【拍摄】唤起相机-摄像功能,点击【从相册中选择】-只能选择视频和图片,安卓手机
  • accept="image/jpg,image/jpeg,image/gif,image/png" -> 唤起原生 【拍摄】 和 【从相册中选择】弹窗 -> 点击【拍摄】唤起相机-拍照功能,点击【从相册中选择】-只能选择视频和图片,安卓手机
  • accept="image/jpg,image/jpeg,image/gif,image/png,video/mp4,video/ogg,video/webm,video/mov" -> 唤起原生 【拍摄】 和 【从相册中选择】弹窗 -> 点击【拍摄】唤起相机-拍照功能,点击【从相册中选择】-可以选择视频和图片,安卓手机
  • accept="image/*,video/mp4,video/ogg,video/webm,video/mov" -> 唤起原生 【拍摄】 和 【从相册中选择】弹窗 -> 点击【拍摄】唤起相机-拍照功能,点击【从相册中选择】-可以选择视频和图片,安卓手机
  • accept="video/mp4,video/ogg,video/webm,video/mov,image/*" -> 唤起原生 【拍摄】 和 【从相册中选择】弹窗 -> 点击【拍摄】唤起相机-拍照功能,点击【从相册中选择】-可以选择视频和图片,安卓手机

有点乱,而且貌似不是严格遵循accept属性值规律。为了方便查看和比对区别,梳理成表格的形式

acceptAndroid IOS
原生【拍摄】原生【从照片选择】原生【拍照/录像】原生【照片图库】
"image/*"拍照图片,没有视频拍照图片
"image/,video/"拍照图片,没有视频拍照,录像图片,视频
"video/,image/"拍照视频,没有图片拍照,录像图片,视频
"video/*"录像视频,没有图片录像视频
"video/mp4,video/ogg,video/webm,video/mov"录像视频,图片录像视频
"image/jpg,image/jpeg,image/gif,image/png"拍照视频,图片拍照图片
"image/jpg,image/jpeg,image/gif,image/png,video/mp4,video/ogg,video/webm,video/mov"拍照视频,图片拍照,录像图片,视频
"image/*,video/mp4,video/ogg,video/webm,video/mov"拍照视频,图片拍照,录像图片,视频
"video/mp4,video/ogg,video/webm,video/mov,image/*"拍照视频,图片拍照,录像图片,视频

从中我们可以尝试总结规律

  • accept="video/xxx",即仅有视频格式情况下,Android点击原生【拍摄】唤起相机是录像功能;
  • accept="image/xxx[,video/xxx]",即仅有图片格式或者图片加视频格式情况下,Android点击原生【拍摄】唤起相机都是照相功能;
  • Android点击原生【从照片选择】唤起相册,若要想只筛选视频,最好使用accept="video/*",只筛选最好使用accept="image/*",而图片和视频同时共存,视频和图片格式最好写全或者accept="image/*,video/xxx"

    capture在Android和IOS的表现

    <input type="file" />在以上已有accept属性下,加上capture属性,点击后可直接唤起相机,相机分为拍照和录像两种模式,同样的,我们分别测试Android和IOS的微信浏览器上的结果如下

acceptAndroid【拍摄】IOS【拍摄】
"image/*"拍照拍照
"image/,video/"拍照录像,拍照
"video/,image/"拍照录像,拍照
"video/*"录像录像
"video/mp4,video/ogg,video/webm,video/mov"录像录像,拍照
"image/jpg,image/jpeg,image/gif,image/png"拍照录像,拍照
"image/jpg,image/jpeg,image/gif,image/png,video/mp4,video/ogg,video/webm,video/mov"拍照录像,拍照
"image/*,video/mp4,video/ogg,video/webm,video/mov"拍照录像,拍照
"video/mp4,video/ogg,video/webm,video/mov,image/*"拍照录像,拍照

可以发现,这里直接唤起拍摄和之前通过原生选项框中【拍摄】(Android)或者【录像】(IOS)的表现一致!

实现选择照片(图片&视频)及拍照&录像

综合上述实验可以发现,没有一种acceptcapture的值的组合可以实现在Android中,既要在相册中可以选择图片和视频,又可以直接拍照和录像的情况。
这样可以多一个人为选择弹窗或者将拍摄视频拆分开,类似这样
image.png
点击照片图标,Android手机弹出原始选项框,可以【从相册选择】图片和视频,也可以【拍摄】图片,点击拍摄图标,单纯支持录像。


最终的思路是
在Android微信环境下,点击照片图标触发的inputaccept值为video/mp4,video/ogg,video/webm,video/mov,image/*使其后续【拍摄】唤起相机拍照,唤起相册可以选择图片和视频;点击拍摄图标触发的inputaccept值为video/mp4,video/ogg,video/webm,video/mov,使其唤起相机录像功能;
伪代码实现

<uploader :accept="accept" label="照片" icon="picture" />
<uploader :accept="captureAccept" capture="camera" label="照片" icon="camera" />

const videoAccept = 'video/mp4,video/ogg,video/webm,video/mov'
// 【照片】accept
const accept = `${videoAccept},image/*`
// 【拍摄】accept
const UA = window.navigator.userAgent
const isAndroid = /Android/i.test(UA)
const isWechat = /MicroMessenger/i.test(UA)                                      
const { isAndroid, isWechat } = Terminal
const captureAccept = isAndroid && isWechat ? videoAccept : ${videoAccept},image/*`

完~

Code for work, write for progress!

5.9k 声望
2.5k 粉丝
0 条评论
推荐阅读
「过程详解」async await综合题
如果你之前跟我一样一直对async await熟悉又陌生的话(熟悉是可能每天都在用,陌生是针对一些组合题又丈二和尚摸不着头脑),不妨可以边看边练,总结规律,相信会逐渐清晰并有所得。本文对每个案例都详细描述了代...

wuwhs5阅读 1.3k

封面图
ESlint + Stylelint + VSCode自动格式化代码(2023)
安装插件 ESLint,然后 File -&gt; Preference-&gt; Settings(如果装了中文插件包应该是 文件 -&gt; 选项 -&gt; 设置),搜索 eslint,点击 Edit in setting.json

谭光志34阅读 20.7k评论 9

安全地在前后端之间传输数据 - 「3」真的安全吗?
在「2」注册和登录示例中,我们通过非对称加密算法实现了浏览器和 Web 服务器之间的安全传输。看起来一切都很美好,但是危险就在哪里,有些人发现了,有些人嗅到了,更多人却浑然不知。就像是给门上了把好锁,还...

边城31阅读 7.3k评论 5

封面图
涨姿势了,有意思的气泡 Loading 效果
今日,群友提问,如何实现这么一个 Loading 效果:这个确实有点意思,但是这是 CSS 能够完成的?没错,这个效果中的核心气泡效果,其实借助 CSS 中的滤镜,能够比较轻松的实现,就是所需的元素可能多点。参考我们...

chokcoco21阅读 2.2k评论 3

你可能不需要JS!CSS实现一个计时器
CSS现在可不仅仅只是改一个颜色这么简单,还可以做很多交互,比如做一个功能齐全的计时器?样式上并不复杂,主要是几个交互的地方数字时钟的变化开始、暂停操作重置操作如何仅使用 CSS 来实现这样的功能呢?一起...

XboxYan23阅读 1.6k评论 1

封面图
在前端使用 JS 进行分类汇总
最近遇到一些同学在问 JS 中进行数据统计的问题。虽然数据统计一般会在数据库中进行,但是后端遇到需要使用程序来进行统计的情况也非常多。.NET 就为了对内存数据和数据库数据进行统一地数据处理,发明了 LINQ (L...

边城17阅读 2k

封面图
【已结束】SegmentFault 思否写作挑战赛!
SegmentFault 思否写作挑战赛 是思否社区新上线的系列社区活动在 2 月 8 日 正式面向社区所有用户开启;挑战赛中包含多个可供作者选择的热门技术方向,根据挑战难度分为多个等级,快来参与挑战,向更好的自己前进!

SegmentFault思否20阅读 5.6k评论 10

封面图

Code for work, write for progress!

5.9k 声望
2.5k 粉丝
宣传栏