Загрузка фотографии через Expo в хранилище Firebase (Firebase JS SDK) не работает (преобразование BLOB-объектов)Android

Форум для тех, кто программирует под Android
Ответить Пред. темаСлед. тема
Anonymous
 Загрузка фотографии через Expo в хранилище Firebase (Firebase JS SDK) не работает (преобразование BLOB-объектов)

Сообщение Anonymous »

Я не знаю, что еще попробовать, и мне нужна помощь с загрузкой фотографии, сделанной с помощью expo-camera, на физическое устройство Android с установленным Expo Go для загрузки в хранилище Firebase (на данный момент эмулируется) с помощью Firebase JS SDK.
Я видел много темы по этому поводу, но большинство из них либо устарели, либо используют React Native Firebase вместо JS SDK. Поскольку для работы мне также нужен Интернет, я бы хотел придерживаться JS.
Это прекрасно работает со многими подходами, которые вы увидите ниже в Интернете.
Без лишних слов, вот мой код. Пожалуйста! Дайте мне знать, как правильно преобразовать большой двоичный объект и загрузить его (мне не важно, с помощью uploadBytes, uploadBytesResumable или uploadString...
Camera.tsx

Код: Выделить всё

const takePhoto = async () => {
const photo = await cameraRef.current?.takePictureAsync({
quality: 0.5,
base64: true,
})
if (!photo) {
console.error('No photo taken')
return
}
console.log(photo)
const uploadResult = await uploadPhoto(photo)
console.log(uploadResult)
}
api/uploadPhoto.ts

Код: Выделить всё

import { SaveFormat, manipulateAsync } from 'expo-image-manipulator'
import * as FileSystem from 'expo-file-system'
import uuid from 'react-native-uuid'
import {
ref,
uploadBytesResumable,
getDownloadURL,
uploadBytes,
StorageReference,
FirebaseStorage,
uploadString,
} from 'firebase/storage'
import { FIREBASE_DB, FIREBASE_STORAGE } from '@/utils/firebaseConfig'
import { addDoc, collection, serverTimestamp } from 'firebase/firestore'
const MAX_FILE_SIZE_MB = 1

export default async function uploadPhoto(photo) {
console.log('Received photo', photo)
// Create a storage reference
const storage = FIREBASE_STORAGE
const storageRef = ref(storage, `photos/${uuid.v4()}`)
console.log('storageRef', storageRef)
// Get uri from Photo
const uri = await getUriFromPhoto(photo)
console.log('Photo uri', uri)
try {
// Fetch file
const file = await fetch(uri.replace('file:///', 'file:/'))
console.log('file', file)
// Compress file
const compressedFile = await compressFile(uri)
console.log('compressedFile', compressedFile)
//Check if file is smaller than 1MB
const smallerThanMaxSize = await checkSizeIsLessThan(
compressedFile.uri,
MAX_FILE_SIZE_MB
)
if (!smallerThanMaxSize) {
throw new Error('Image is too large')
} else {
console.log('File is smaller than 1MB')
}
//Create blob from file
const fetchedCompressedFile = await fetch(
compressedFile.uri.replace('file:///', 'file:/')
)
console.log('fetchedCompressedFile', fetchedCompressedFile)
// const blob1 = await uriToBlob(fetchedCompressedFile.uri)
// console.log('blob1', blob1)
// const blob2 = await createBlobFromUriXhr(compressedFile)
// console.log('blob2', blob2)
// const blob3 = await createBlobFromUriWorkaround(compressedFile)
// console.log('blob3', blob3)
// Upload file and get download URL
// const downloadUrl = await uploadBlob(storageRef, blob1, {
//   contentType: 'image/jpeg',
// })
// console.log('downloadUrl', downloadUrl)
return
// Add URL to Firestore
// const id = await addDownloadUrlToFirestore(photo.filename, downloadUrl)
} catch (uploadError) {
console.error('Error uploading bytes:', uploadError)
}
}

async function uploadImageAsync(uri) {
// Why are we using XMLHttpRequest? See:
// https://github.com/expo/expo/issues/2402#issuecomment-443726662
const storage = FIREBASE_STORAGE
const blob = await new Promise((resolve, reject) =>  {
const xhr = new XMLHttpRequest()
xhr.onload = function () {
resolve(xhr.response as Blob)
}
xhr.onerror = function (e) {
console.log(e)
reject(new TypeError('Network request failed'))
}
xhr.responseType = 'blob'
xhr.open('GET', uri, true)
xhr.send(null)
})

const storageRef = ref(storage, `photos/${uuid.v4()}`)
const snapshot = await uploadBytes(storageRef, blob)

return await getDownloadURL(snapshot.ref)
}
async function getUriFromPhoto(photo) {
const uri = photo.uri
return uri
}

async function fetchFile(uri: string) {
const response = await fetch(uri)

if (!response.ok) {
throw new Error(
`Failed to fetch file from uri: ${uri}: response.statusText`
)
}
return response
}

async function compressFile(uri: string) {
try {
const result = await manipulateAsync(
uri,
[
{
resize: {
width: 800,
},
},
],
{
format: SaveFormat.JPEG,
base64: true,
compress: 0.1,
}
)
console.log('Reduced file result:', result)
return result
} catch (error) {
console.error('Error compressing file:', error)
throw error
}
}

async function checkSizeIsLessThan(
uri: string,
maxSizeMb: number
): Promise {
const fileInfo = await FileSystem.getInfoAsync(uri)
if (!fileInfo.exists) {
throw new Error(`File does not exist at uri: ${uri}`)
}
return fileInfo.size! < maxSizeMb * 1024 * 1024
}

async function createBlobFromUri(uri: string): Promise {
try {
const response = await fetch(uri)
const blob = await response.blob()
console.log('createBlobFromUri blob', blob)
return blob
} catch (error) {
console.error('Failed to create blob from URI', error)
throw error
}
}

/**
* Function to convert a URI to a Blob object
* @param {string} uri - The URI of the file
* @returns {Promise} - Returns a promise that resolves with the Blob object
*/
export function uriToBlob(uri: string): Promise {
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest()

// If successful -> return with blob
xhr.onload = function () {
resolve(xhr.response)
}

// reject on error
xhr.onerror = function () {
reject(new Error('uriToBlob failed'))
}

// Set the response type to 'blob' - this means the server's response
// will be accessed as a binary object
xhr.responseType = 'blob'

// Initialize the request. The third argument set to 'true' denotes
// that the request is asynchronous
xhr.open('GET', uri, true)

// Send the request.  The 'null' argument means that no body content is given for the request
xhr.send(null)
})
}

async function createBlobFromUriXhr(uri: string): Promise {
console.log('createBlobViaXhrAsync uri', uri)

const blob = await new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest()
xhr.onload = function () {
resolve(xhr.response as Blob)
}
xhr.onerror = function (e) {
console.log(e)
reject(new TypeError('Network request failed'))
}
xhr.responseType = 'blob'
xhr.open('GET', uri, true)
xhr.send(null)
})
console.log('createBlobViaXhrAsync blob', blob)
return blob
}

async function createBlobFromUriWorkaround(uri: string): Promise {
const originalUri = uri
const fileName = uri.substring(uri.lastIndexOf('/') + 1)
// Workaround see https://github.com/facebook/react-native/issues/27099
const newUri = `${FileSystem.documentDirectory}resumableUploadManager-${fileName}.toupload`
await FileSystem.copyAsync({ from: originalUri, to: newUri })
const response = await fetch(newUri)
const blobData = await response.blob()
const blob = new Blob([blobData], { type: 'image/jpeg' })
console.log('createBlobFromUriWorkaround blob', blob)
return blob
}

async function uploadBlob(
storageRef: StorageReference,
blob: Blob,
metadata?: any
): Promise {
const uploadBytesResponse = await uploadBytes(storageRef, blob, metadata)
console.log('uploadBytesResponse', uploadBytesResponse)
try {
const uploadTask = uploadBytesResumable(storageRef, blob, metadata)
return new Promise((resolve, reject) => {
uploadTask.on(
'state_changed',
(snapshot) => {
const progress =
(snapshot.bytesTransferred / snapshot.totalBytes) * 100
console.log('Upload is ' + progress + '% done')
switch (snapshot.state) {
case 'paused':
console.log('Upload is paused')
break
case 'running':
console.log('Upload is running')
break
}
},
(error) => {
console.error('Error uploading bytes:', error)
reject(error)
},
() => {
console.log('Upload is complete')
getDownloadURL(uploadTask.snapshot.ref)
.then((downloadURL) => {
console.log('File available at', downloadURL)
resolve(uploadTask.snapshot.ref.fullPath)
})
.catch((error) => {
console.error('Error getting download URL:', error)
reject(error)
})
}
)
})
} catch (error) {
console.error('Error uploading bytes:', error)
throw error
}
}

async function addDownloadUrlToFirestore(
fileName: string,
downloadURL: string
) {
try {
const docRef = await addDoc(collection(FIREBASE_DB, 'photos'), {
fileName,
downloadURL,
createdAt: serverTimestamp(),
})
console.log('Document written with ID: ', docRef.id)
return docRef.id
} catch (error) {
console.error('Error adding document: ', error)
throw error
}
}
А теперь список ресурсов, которые я использовал, или сообщений, которые я пробовал (как вы увидите в моем коде)
  • https://firebase.google.com/docs/storag ... load-files (ofc)
  • https://www.youtube.com/watch?v=KkZckepfm2Q (тоже старый/использует RNF)
  • https://github.com/choru-k/React-Native ... act-native (слишком старый/используется RNF)
  • Преобразовать путь к изображению в собственный код реагирования на большой двоичный объект (в основном ориентирован на RNF)
  • React Native при извлечении Blob выдает ошибку: не удалось создать «Ответ» : предоставленный статус (0) находится за пределами диапазона [200, 599] (это помогло при загрузке симулятора Android, но также не работает на физическом устройстве).
  • Преобразовать путь к изображению в blob React Native
  • Загрузка фотографий с камеры Expo в хранилище Firebase не определена – React Native (решение уже включено здесь – возможно, оно устарело?)
Я также пробовал это на физическом устройстве iOS, результат тот же (нет).

Подробнее здесь: https://stackoverflow.com/questions/791 ... ing-blob-c
Реклама
Ответить Пред. темаСлед. тема

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение

Вернуться в «Android»