Android 10使用HTML5 <input type="file">从相机录像模式拍照后文件大小为0的问题
Android 10相机录像模式拍图后文件大小为0、损坏的问题排查与修复
在Android 10设备上,使用相机的录像模式拍摄照片后,生成的图片文件大小为0且图片损坏。调用FileReader的readAsDataURL方法后,打印e.target.result仅得到"data:",无有效Base64字符串。相关截图如下:


现有代码
HTML代码
<button class="btn-file-upload">Upload File</button> <input type="file" name="file" id="file">
JavaScript代码
$('.btn-file-upload').on('click', function() { $('#file').click(); }) $(document).on('change', '#file', function(event) { var allowedTypes = ['image/jpg', 'image/jpeg', 'image/png']; var input = event.target; console.log(input.files[0]) if (input.files && input.files[0]) { var reader = new FileReader(); reader.onload = function(e) { var blob_url = window.URL.createObjectURL(input.files[0]); var text = ` <div class="text-left"> type => `+input.files[0].type+` <br> size => `+input.files[0].size+` <br> name => `+input.files[0].name+` <br> <img src="`+blob_url+`" width="100"> </div> `; Swal.fire({ html: text, icon: 'warning', }); if(allowedTypes.indexOf(input.files[0].type) != -1) { console.log("Valid") console.log(e.target.result) // 此处结果仅为"data:"(无Base64字符串) } else { console.log("Invalid") } event.target.value = ''; } reader.readAsDataURL(input.files[0]); } })
问题原因
这是Android 10系统的兼容性问题:当通过<input type="file">调用相机的录像模式拍摄照片时,系统会先创建一个空的临时文件占位,后续才会写入实际图片数据,但浏览器的change事件会在占位文件创建后立即触发,此时实际数据还未写入完成,导致读取到的文件大小为0,FileReader无法解析出有效的Base64内容。
修复方案
方案1:强制调用相机拍照模式
给<input type="file">添加capture="camera"和accept="image/*"属性,直接唤起相机的拍照模式,避免触发录像模式的异常逻辑:
<input type="file" name="file" id="file" capture="camera" accept="image/*">
方案2:延迟读取文件
在change事件触发后,延迟一段时间再读取文件,给系统足够的时间完成图片数据写入(时长可根据设备性能调整):
$(document).on('change', '#file', function(event) { var allowedTypes = ['image/jpg', 'image/jpeg', 'image/png']; var input = event.target; console.log(input.files[0]) if (input.files && input.files[0]) { // 延迟500ms执行读取操作 setTimeout(() => { var reader = new FileReader(); reader.onload = function(e) { var blob_url = window.URL.createObjectURL(input.files[0]); var text = ` <div class="text-left"> type => `+input.files[0].type+` <br> size => `+input.files[0].size+` <br> name => `+input.files[0].name+` <br> <img src="`+blob_url+`" width="100"> </div> `; Swal.fire({ html: text, icon: 'warning', }); if(allowedTypes.indexOf(input.files[0].type) != -1) { console.log("Valid") console.log(e.target.result) } else { console.log("Invalid") } event.target.value = ''; } reader.readAsDataURL(input.files[0]); }, 500); } })
方案3:校验文件大小后重试
在读取文件前检查文件大小,如果为0则延迟重试,直到读取到有效文件(可设置重试次数上限避免死循环):
function readFile(file, allowedTypes, retryCount = 0) { // 最多重试3次 if (retryCount >= 3) { console.log("文件读取失败,重试次数已达上限"); return; } if (file.size === 0) { // 文件为空,延迟300ms后重试 setTimeout(() => readFile(file, allowedTypes, retryCount + 1), 300); return; } var reader = new FileReader(); reader.onload = function(e) { var blob_url = window.URL.createObjectURL(file); var text = ` <div class="text-left"> type => `+file.type+` <br> size => `+file.size+` <br> name => `+file.name+` <br> <img src="`+blob_url+`" width="100"> </div> `; Swal.fire({ html: text, icon: 'warning', }); if(allowedTypes.indexOf(file.type) != -1) { console.log("Valid") console.log(e.target.result) } else { console.log("Invalid") } } reader.readAsDataURL(file); } $(document).on('change', '#file', function(event) { var allowedTypes = ['image/jpg', 'image/jpeg', 'image/png']; var input = event.target; if (input.files && input.files[0]) { readFile(input.files[0], allowedTypes); event.target.value = ''; } })
内容的提问来源于stack exchange,提问作者Codeblooded Saiyan
相关产品推荐
相关产品推荐

