阅读 1545

h5(移动端)拍照调用相机和选择图库同时存在ios、安卓的兼容问题

前言

问题描述:

在工作中使用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、增加手机浏览器的版本判断

/**
 *  分析智能手机浏览器 版本信息
 * @作者: lixiaoyan
 * @时间:2020.5.15
 */

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;
}
复制代码

后续问题:

因为能找到的手机机型,毕竟有限,以上的最终解决方案,是否还有后续问题,是否都能搞定,还不能确定。如果之后在遇到有问题手机,代码不适应在重新更新代码。。。当然如果有小伙伴们看到这篇文章,有不同的建议或者发现测试后代码确实不能兼容的问题,欢迎来沟通指导~~