无法将文件上传到 Firebase 云存储。错误:“不存在具有所需引用的对象”

问题描述 投票:0回答:1

使用 Firebase 云存储 sdk 的所有请求都会导致“不存在具有所需引用的对象”。使用 expo 和 React Native 构建的相同代码在朋友的机器上运行得非常好。其他 Firebase 服务似乎也可以工作,例如 Firestore 和 Firebase 云消息传递。 这是用于调用 firebase uploadfile 请求的钩子:

import { useState } from "react";
import { UseMutateFunction, useMutation } from "@tanstack/react-query";
import { ImagePickerAsset } from "expo-image-picker";
import storage from "@/storage/init";

type uploadFileResult = {
  uploadFile: UseMutateFunction<
    string | undefined,
    Error,
    uploadFileArgs,
    unknown
  >;
  uploadProgress: number;
  isUploading: boolean;
  error: Error | null;
  downloadURL: string | null;
};
type uploadFileArgs = { file: ImagePickerAsset };

//Handles file upload to Firebase storage.
export function useUploadFile(): uploadFileResult {
  const [uploadProgress, setUploadProgress] = useState(0);
  const [downloadURL, setDownloadURL] = useState<string | null>(null);

  const uploadFile = async (props: uploadFileArgs) => {
    const localFilePath = props.file.uri;
    console.info(localFilePath);
    if (!localFilePath) return;

    const reference = storage.ref(`${props.file.fileName}`);
    const task = reference.putFile(localFilePath);

    task.on("state_changed", (taskSnapshot) => {
      setUploadProgress(
        (taskSnapshot.bytesTransferred / taskSnapshot.totalBytes) * 100,
      );
    });

    await task;

    const url = await reference.getDownloadURL();
    setDownloadURL(url);
    return url;
  };

  const {
    mutate,
    isPending: isUploading,
    error,
  } = useMutation({
    mutationFn: uploadFile,
  });

  return {
    uploadFile: mutate,
    uploadProgress,
    isUploading,
    error,
    downloadURL,
  };
}

这是上述钩子的实现:

import { SettingsToolbar } from "@/components/screens/settings/Toolbar";
import { Avatar } from "@/components/ui/Avatar";
import { Button } from "@/components/ui/Button";
import { Input, InputBox, InputLabel } from "@/components/ui/Input";
import { Tags } from "@/components/ui/Tags";
import { ToastType } from "@/components/ui/Toast";
import { UserRepo } from "@/db/user";
import { useTheme } from "@/hooks/useTheme";
import { trimAll } from "@/lib/utils";
import { Gender } from "@/models/models";
import { useShowToast } from "@/providers/toastProvider";
import { useUserContext } from "@/providers/userProvider";
import { Timestamp } from "@react-native-firebase/firestore";
import * as ImagePicker from "expo-image-picker";
import { router } from "expo-router";
import { Pencil } from "lucide-react-native";
import { useCallback, useState } from "react";
import {
  KeyboardAvoidingView,
  Pressable,
  ScrollView,
  View,
} from "react-native";
import { GenderSelect, InterestedInSelect } from "./signup";
import { useUploadFile } from "@/hooks/useFileUpload";

export default function Settings() {
  const theme = useTheme();
  const user = useUserContext();
  const showToast = useShowToast();
  const { uploadFile, downloadURL } = useUploadFile();

  const [avatar, setAvatar] = useState(user?.avatar || "");
  const [username, setUsername] = useState(user?.username || "");
  const [gender, setGender] = useState<Gender>(user?.gender || "male");
  const [lookingFor, setLookingFor] = useState(user?.lookingFor[0] || "female");
  const [tags, setTags] = useState<string[]>(
    user?.tags.filter((v) => v !== user.gender) || [],
  );

  const pickImage = async () => {
    // No permissions request is necessary for launching the image library
    let result = await ImagePicker.launchImageLibraryAsync({
      mediaTypes: ImagePicker.MediaTypeOptions.All,
      allowsEditing: true,
      aspect: [1, 1],
      quality: 1,
    });

    if (!result.canceled) {
      setAvatar(result.assets[0].uri);
      uploadFile({ file: result.assets[0] });
      return;
    }
    showToast("Image upload was cancelled", ToastType.WARNING);
  };

  const updateUser = useCallback(() => {
    try {
      if (username.length < 3) {
        throw Error("Username is too short!");
      }

      if (trimAll(username) !== username) {
        throw Error("Username has incorrect format!");
      }
      if (username.length > 20) {
        throw Error("Username is too long!");
      }

      if (user) {
        const userRepo = new UserRepo(user.id);
        //user.avatar = avatar;
        user.username = username;
        user.gender = gender;
        user.tags = [gender, ...tags];
        user.lookingFor = [lookingFor, ...tags];
        user.lastOnline = Timestamp.now();
        if (downloadURL) {
          user.avatar = downloadURL;
        }
        userRepo
          .updateUser(user)
          .then(() => {
            router.back();
            showToast("Settings updated", ToastType.INFO);
          })
          .catch((r) => {
            console.error(r);
            showToast("Error updating settings", ToastType.ERROR);
          });
      }
    } catch (r) {
      {
        console.warn(r);
        showToast(`${r}`, ToastType.WARNING);
      }
    }
  }, [downloadURL, gender, lookingFor, showToast, tags, user, username]);

  return (
    <KeyboardAvoidingView
      style={{ flex: 1, backgroundColor: theme.background }}
    >
      <SettingsToolbar />
      <ScrollView style={{ flex: 1 }}>
        <View
          style={{
            paddingHorizontal: 42,
            marginTop: 40,
            alignItems: "center",
          }}
        >
          <Pressable onPress={pickImage}>
            <Avatar size={128} src={avatar} />
            <Pencil
              style={{ position: "absolute", bottom: 0, end: 0 }}
              color={theme.onSecondary}
            />
          </Pressable>
        </View>
        <View style={{ alignItems: "center", gap: 8, marginBottom: 40 }}>
          <Input>
            <InputLabel style={{ color: theme.text }}>Username</InputLabel>
            <InputBox
              maxLength={20}
              value={username}
              onChangeText={setUsername}
            />
          </Input>
          <GenderSelect gender={gender} onChange={setGender} />
          <InterestedInSelect gender={lookingFor} onChange={setLookingFor} />
          <Tags tags={tags} setTags={setTags} />
          <Button onPress={updateUser}>Save</Button>
        </View>
      </ScrollView>
    </KeyboardAvoidingView>
  );
}

同样,这个问题似乎只存在于我的模拟器/手机机器上。经过一些调试后,我还发现我什至无法列出默认存储桶中的项目。我得到同样的错误。这让我相信,也许“不”存在的引用是存储桶本身的默认引用?关于可能出现的问题有什么想法吗? 感谢您提前提供的帮助。

javascript android firebase react-native firebase-storage
1个回答
0
投票

好的,由于某种原因,Firebase 无法找到默认存储桶。因此,每次我尝试将文件放入存储时(我已将其启动为

storage()
),都会导致“不存在对象引用...”,这意味着无法找到存储桶...所以我修复它的方法是初始化存储,就好像它是自定义存储桶一样:

import { firebase } from "@react-native-firebase/storage";
const storage = firebase.app().storage(process.env.BUCKET_URL);
export default storage;

我还是不知道为什么它找不到默认存储桶...

© www.soinside.com 2019 - 2024. All rights reserved.