前言
问题描述:
在工作中使用uni-app遇到了一个兼容问题,是使用uni.chooseImg时候,有些手机不能调用相机只有图像。大概测试了二十多个手机,有不同的表现~~
问题复现:
1、使用官方的uni.chooseImage;
2、在部分安卓手机机型如:"SM-G9700","MX 2S","MATE30 PRO","MI 10 PRO","PRA-AL00X",(小米,魅族、华为),出现无法调取摄像头问题;ios手机测了几台没发现问题; 官方提供代码:uniapp.dcloud.io/api/media/i…
uni.chooseImage({
count: 1,
sourceType: ['album', 'camera'],
sizeType: ['compressed', 'original'],
success: function (res) {
console.log(JSON.stringify(res.tempFilePaths));
}
});
复制代码延伸问题总结:
- 1、uni-app中的uni.chooseImage: h5端chooseimg接口的sourcetype不起作用;
- 2、使用原生的代码:
<input type="file" id="camera" multiple="multiple"capture="camera" accept="image/*" >
ios系统的手机和安卓的部分手机,直接调取相机,没有相册选择功能;
- 3、图片过大时,在IOS上显示压缩
- 4、选择图库或者自拍的照片,显示在页面,不管是IOS还是安卓手机都出现过图片被旋转的问题, 此问题会在后续的文章中,来解决过程,解决代码;
解决问题过程:
1、查看官网社区:
发现很多人遇到了这个问题,但是翻阅了官方的社区回答,发现都是没有解决根本问题,很有其他的延伸问题比如:
延伸问题总结第一条问题:h5端chooseimg接口的sourcetype不起作用; 有的官方给出问题,是让自己动态生成input使用type="file" ,accept规定可通过文件上传控件提交的文件类型,来实现;
2、使用input type="file"形式来实现
遇到问题:延伸问题总结,第二条:在移动端页面使用上传文件或者图片时,IOS和安卓的展现方式有很多不一样。 查资料有的解决方案为如下:
- 第一种解决方案:
<input type="file" accept="image/*" capture="camera">
<input type="file" accept="video/*" capture="camcorder">
<input type="file" accept="audio/*" capture="microphone">
accept表示打开的系统文件目录
capture表示的是系统所捕获的默认设备,
camera:照相机;camcorder:摄像机;microphone:录音;
其中还有一个属性multiple,支持多选,当支持多选时,multiple优先级高于capture,所以只用写成:
就可.
结论: 但是还是在出现了不同的表现形式,ios手机直接调用相机,安卓部分手机直接调用,部分可以选择相机和相册!!!!
- 第二种解决方案:
// 判断当前是否属于ios移动端,兼容input同时调用手机相册和相机
function compatibleInput(){
//获取浏览器的userAgent,并转化为小写
var ua = navigator.userAgent.toLowerCase();
//判断是否是苹果手机,是则是true
var isIos = (ua.indexOf('iphone') != -1) || (ua.indexOf('ipad') != -1);
if (isIos) {
$("input:file").removeAttr("capture");
};
}
结论: 部分安卓手机直接掉用了相机,ios没问题;
- 第三种解决方案
综合前面的情况,因为是只有几款手机会出现此种问题,所以使用判断手机型号,来增加内容capture="camera"; 部分代码实现:
<input id="input" type="file" accept="image/*" multiple>
let input = document.getElementById('input');
const phoneModel = ["TAS-AN00","JKM-AL00b","SM-G9700","MX4","MX 2S","MATE30 PRO","MI 10 PRO","PRA-AL00X"];
const info = uni.getSystemInfoSync();
console.log(info.model,info.platform,info,'关于手机')
let mm = info.model.replace(/(^\s*)|(\s*$)/g, "").toLocaleUpperCase();//去除空格,转换为大写
if (info.platform == 'android' && phoneModel.includes(mm)) {
input.capture = 'camera';
}
input.onchange = (event) => {
console.log('动态添加的input 选取照片', event.target.files);
let files = event.target.files;
if (!files.length) return;
files = Array.prototype.slice.call(files);
this.$emit('chooseImage', files);
}
console.log("使用了什么内核:",window.navigator.userAgent);
结论: 开始测试的时候,确实没有问题了,但是发现这几款手机微信打开浏览器、默认浏览器、QQ浏览器、QQ打开浏览器表现形式还是存在兼容性,且不可能一直这么收集机型,这么解决也是不合理,还是应该从浏览器的内核模式来查看~~
- 最终解决方案 可查看下边的正式部分~
正式:
最终我的解决方案:
在使用了console.log("使用了什么内核:",window.navigator.userAgent);打印,查看了大约二十几款手机,截图比较内核,在分别通过了不同浏览器来总结(呼口气,好累~~): 微信打开浏览器、手机自带浏览器、其他浏览器; 在这就不放截图了,上代码吧~ 本代码写成一个组件CreateChooseImg,可以用与uni-app项目、也可以用于VUE的项目 1、CreateChooseImg组件
<template>
<view ref="my_mdj_input">
</view>
</template>
<script>
/**
* @description 使用原生dom input type=“file” 来调用相机或者选择图片 解决使用uni-app中api部分手机 ,
* @作者:lee
* @property {function} isWeixin,isMQQbrowser,isAndroid 用于获取手机浏览器的内核
* @return files文件信息,可在父组件中chooseImage绑定此方法在具体操作
*/
import { isWeixin,isMQQbrowser,isAndroid } from '@/common/compatible'
export default {
name: 'CreateChooseImg',
methods: {
// 动态创建 input 上传img元素 主要为了兼容
/**
* uni.chooseImg在调用相册和拍照在不同的手机中显示不同 无法调用相机 等问题
* 在各个机型都可以点击 file 调用相册 和 摄像头拍照
1. 在老版本的安卓中,必须加上capture,否则只能调用相册
2. 在IOS中 加了capture,就只能调用摄像头不能调用相册
*/
createUploadImgEle() {
console.log('动态创建 input 上传img元素');
let input = document.createElement('input');
input.type = 'file';
input.accept = 'image/*';
input.multiple = 'multiple';
// input.className = 'input-img_elm';
input.style.position = "absolute";
input.style.left = '0';
input.style.top = '0';
input.style.width = '100%';
input.style.height = '100%';
input.style.overflow = "hidden";
input.style.opacity = 0;
input.onchange = (event) => {
console.log('动态添加的input 选取照片', event.target.files);
let files = event.target.files;
if (!files.length) return;
files = Array.prototype.slice.call(files);
//此方法也可以放到 store中
this.$emit('chooseImageUseH5', files);
}
console.log("使用了什么内核:",window.navigator.userAgent);
try{
if (isAndroid() && isWeixin() && !isMQQbrowser()) {
console.log("强制添加摄像头调用功能");
input.capture = 'camera';
}
}catch(e){
console.log("创建原生input元素报错 :",e);
}
this.$refs.my_mdj_input.$el.appendChild(input);
},
},
mounted() {
this.createUploadImgEle();
}
}
</script>
<style lang="scss" scoped>
</style>
2、增加手机浏览器的版本判断
/**
* 分析智能手机浏览器 版本信息
* @时间:2020.7.1
*/
export const browser = {
versions: function() {
var u = navigator.userAgent,
app = navigator.appVersion;
return { //移动终端浏览器版本信息
trident: u.indexOf('Trident') > -1, //IE内核
presto: u.indexOf('Presto') > -1, //opera内核
webKit: u.indexOf('AppleWebKit') > -1, //苹果、谷歌内核
gecko: u.indexOf('Gecko') > -1 && u.indexOf('KHTML') == -1, //火狐内核
mobile: !!u.match(/AppleWebKit.*Mobile.*/) || !!u.match(/AppleWebKit/), //是否为移动终端
ios: !!u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/), //ios终端
android: u.indexOf('Android') > -1 || u.indexOf('Linux') > -1, //android终端或者uc浏览器
iPhone: u.indexOf('iPhone') > -1 || u.indexOf('Mac') > -1, //是否为iPhone或者QQHD浏览器
iPad: u.indexOf('iPad') > -1, //是否iPad
webApp: u.indexOf('Safari') == -1, //是否web应该程序,没有头部与底部
isWeixin: u.toLowerCase().match(/MicroMessenger/i) == 'micromessenger' ,// 是否是微信打开的浏览器
isMQQbrowser: u.toLowerCase().match(/MQQbrowser/i) == 'mqqbrowser' // 是否是微信打开的浏览器
};
}(),
language: (navigator.browserLanguage || navigator.language).toLowerCase()
}
// 是否是 ios系统
export function isIos() {
if (browser.versions.ios || browser.versions.iPhone || browser.versions.iPad) {
return true;
} else {
return false;
}
}
// 是否是安卓系统
export function isAndroid() {
return browser.versions.android
}
// 是否是移动端
export function isMobile() {
return browser.versions.mobile;
}
export function isWeixin() {
return browser.versions.isWeixin;
}
export function isMQQbrowser() {
return browser.versions.isMQQbrowser;
```
原文链接:https://juejin.cn/post/1fc64a