Hermes引擎下Uint16Array异常致Firebase二进制上传失败
解决Hermes引擎下Firebase上传二进制数据异常问题
问题概述
在iOS React Native应用(基于Hermes引擎)中,处理ESP32传输的字节数组并上传至Firebase时,移动端生成的文件为字符形式(如69,120,67,90),而非预期的原始二进制数据;但相同代码在Node环境下运行正常。核心原因是Hermes对TypedArray的处理存在差异,将其识别为字典对象(打印结果为{ '0': 30789, '1': 23107 }),导致Firebase无法正确解析二进制格式。
解决方案
方案1:将TypedArray转为普通数组后重构
通过Array.from()将TypedArray转为原生数组,再重新构建Uint8Array,确保Firebase能识别为二进制数据:
async function uploadBlob(bytes){ const newByteRef = doc(collection(db, "PPG")); const url = 'PPG/'+newByteRef.id; const storageRef = ref(storage, url); // 先转普通数组,再重构Uint8Array const rawArray = Array.from(bytes); const U8bytes = new Uint8Array(rawArray); try{ await uploadBytes(storageRef, U8bytes); const downloadUrl = await getDownloadURL(storageRef); const data = { date: Date.now(), url: downloadUrl.split("/").slice(-1)[0] }; await setDoc(newByteRef, data); } catch (error){ console.log(error); } }
方案2:使用Blob包装二进制数据
Hermes对Blob的支持更稳定,直接用Blob包装TypedArray后上传:
async function uploadBlob(bytes){ const newByteRef = doc(collection(db, "PPG")); const url = 'PPG/'+newByteRef.id; const storageRef = ref(storage, url); // 用Blob包装二进制数据,指定MIME类型为二进制流 const blob = new Blob([bytes], { type: 'application/octet-stream' }); try{ await uploadBytes(storageRef, blob); const downloadUrl = await getDownloadURL(storageRef); const data = { date: Date.now(), url: downloadUrl.split("/").slice(-1)[0] }; await setDoc(newByteRef, data); } catch (error){ console.log(error); } }
方案3:修复Base64上传异常(针对复现案例)
绕开Hermes对uploadString的Base64解析问题,手动解码Base64为Uint8Array后上传:
const base64String = "eEU="; const storageRef = ref(storage, url); // 手动解码Base64为Uint8Array const decodeBase64 = (base64) => { const binaryString = atob(base64); const bytes = new Uint8Array(binaryString.length); for (let i = 0; i < binaryString.length; i++) { bytes[i] = binaryString.charCodeAt(i); } return bytes; }; const binaryData = decodeBase64(base64String); await uploadBytes(storageRef, binaryData);
辅助优化:拼接TypedArray时转普通数组处理
针对concatTypedArrays函数,转普通数组拼接可避免Hermes的TypedArray异常:
concatTypedArrays(base64String) { const byteArr = new Uint16Array(base64String.length/2); for (let i = 0; i < base64String.length; i+=2) { const highByte = base64String.charCodeAt(i) << 8; const lowByte = base64String.charCodeAt(i + 1); byteArr[i / 2] = highByte | lowByte; } // 转普通数组拼接后再转回Uint16Array const combinedArray = [...Array.from(this.arr), ...Array.from(byteArr)]; this.arr = new Uint16Array(combinedArray); console.log(this.arr); }
内容的提问来源于stack exchange,提问作者SebastiaanTheCoder
相关产品推荐
相关产品推荐

